<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <author>
    <name>Claude 中文知识站</name>
  </author>
  <generator uri="https://hexo.io/">Hexo</generator>
  <id>https://claude.cocoloop.cn/</id>
  <link href="https://claude.cocoloop.cn/" rel="alternate"/>
  <link href="https://claude.cocoloop.cn/atom.xml" rel="self"/>
  <rights>All rights reserved 2026, Claude 中文知识站</rights>
  <subtitle>从入门到精通 · Claude 官方能力全景指南</subtitle>
  <title>Claude 中文知识站</title>
  <updated>2026-04-19T10:57:00.000Z</updated>
  <entry>
    <author>
      <name>Claude 中文知识站</name>
    </author>
    <category term="入门" scheme="https://claude.cocoloop.cn/categories/%E5%85%A5%E9%97%A8/"/>
    <category term="Claude" scheme="https://claude.cocoloop.cn/tags/Claude/"/>
    <category term="Claude Code" scheme="https://claude.cocoloop.cn/tags/Claude-Code/"/>
    <category term="MCP" scheme="https://claude.cocoloop.cn/tags/MCP/"/>
    <category term="选型" scheme="https://claude.cocoloop.cn/tags/%E9%80%89%E5%9E%8B/"/>
    <content>
      <![CDATA[<p>上周帮一个做跨境电商的朋友排查，他说”Claude 买贵了”。我一问，他同时开了 Claude Pro 订阅（桌面端）、Claude Code 订阅，还在 API 上充了 200 刀，以为这三个是分开收费的产品，要买三份才能全用。</p><p>我跟他解释完他愣了半天，差点把不用的那份退掉。</p><p>这种混乱我这两年见了太多次，干脆整理一篇。</p><h2 id="四个入口的真实定位"><a href="#四个入口的真实定位" class="headerlink" title="四个入口的真实定位"></a>四个入口的真实定位</h2><p>先把定位讲清楚，后面选型才不纠结。</p><p><strong>Claude 桌面端</strong>（claude.ai 网页版 + macOS&#x2F;Windows 原生 App）：面向终端用户的聊天产品。像 ChatGPT 那样聊天用的。有 Projects、Artifacts、记忆、MCP 支持。按月订阅 Claude Pro（20 美元）或 Max（100+ 美元）解锁额度和功能。</p><p><strong>Claude Code</strong>：面向开发者的命令行 + IDE 集成工具，专门写代码用。跑在你本地电脑上，直接操作你的文件系统和 git。走 Claude Pro&#x2F;Max 的订阅额度——<strong>关键</strong>：不需要单独再买一份订阅，同一个 Pro 账号在桌面端和 Claude Code 里共用额度。</p><p><strong>API</strong>（console.anthropic.com 拿 key 之后直接调）：面向产品开发的裸模型接口。按 token 计费，跟上面两个的订阅完全是两套账。你做一个产品给别人用，必走 API。</p><p><strong>第三方客户端</strong>（比如 Chatbox、Cherry Studio、NextChat 这类）：自带 UI，但底层调用的是 API key。相当于你有一瓶矿泉水（API），这些客户端给你提供了更漂亮的杯子。</p><p>关键要理解：<strong>订阅和 API 是两套账</strong>。Pro 订阅不能让你的 API 变便宜，API 充值也不能让你用桌面端。</p><h2 id="决策表：你到底要哪个"><a href="#决策表：你到底要哪个" class="headerlink" title="决策表：你到底要哪个"></a>决策表：你到底要哪个</h2><p>把你的需求对号入座：</p><table><thead><tr><th>你的需求</th><th>推荐入口</th></tr></thead><tbody><tr><td>我就是想聊天、写东西、查资料</td><td>桌面端 Pro</td></tr><tr><td>我要写代码、改代码库、做 refactor</td><td>Claude Code</td></tr><tr><td>我要做个产品&#x2F;服务给别人用</td><td>API</td></tr><tr><td>我想要 MCP 自由度（接各种外部工具）</td><td>桌面端 + MCP 配置</td></tr><tr><td>我想多模型对比、本地跑 Prompt 实验</td><td>第三方客户端 + API</td></tr><tr><td>我要批量处理数据、定时任务</td><td>API（尤其是 batch API）</td></tr><tr><td>我是个人开发者，写点小脚本自用</td><td>API + 第三方客户端</td></tr></tbody></table><p>最常被搞混的两项我展开一下。</p><h2 id="常见误区一：以为-Claude-Code-要单独付钱"><a href="#常见误区一：以为-Claude-Code-要单独付钱" class="headerlink" title="常见误区一：以为 Claude Code 要单独付钱"></a>常见误区一：以为 Claude Code 要单独付钱</h2><p>我见过至少 5 个朋友这么理解过。实际上 Claude Code 是内置在 Pro&#x2F;Max 订阅里的。你开了 Pro（20 美元&#x2F;月），在终端 <code>claude</code> 命令装一下，登录同一个账号，就能直接用，没有额外费用。</p><p>如果你是重度代码用户，Max 订阅（100+ 美元&#x2F;月）的额度更大，适合一天几小时都在 Claude Code 里泡着的人。</p><p>如果你不是订阅用户，也可以用 API key 跑 Claude Code，按 token 计费。这种方式在长时间密集使用时比订阅贵，但零散用比较灵活。</p><p>具体能力差异和跟 Cursor&#x2F;Cline 的对比，<a href="/posts/claude-code-vs-cursor-cline/">我写过一篇 Claude Code 横向对比</a>。</p><h2 id="常见误区二：以为-MCP-只能在-Claude-Code-里用"><a href="#常见误区二：以为-MCP-只能在-Claude-Code-里用" class="headerlink" title="常见误区二：以为 MCP 只能在 Claude Code 里用"></a>常见误区二：以为 MCP 只能在 Claude Code 里用</h2><p>MCP（Model Context Protocol）这个协议，很多人第一次听说是从 Claude Code 那边，就以为只有 Claude Code 才支持。</p><p>实际情况是：<strong>桌面端现在也完全支持 MCP</strong>。你在桌面端配置 MCP server（比如接你本地的 Obsidian、Notion、GitHub、数据库），Claude 桌面端就能调用这些工具。</p><p>我自己的设置是桌面端接了 6 个 MCP server，一个日常查文件、一个查日历、一个查本地数据库、两个跟我自己产品后台打通、一个外部搜索。相当于把桌面端的 Claude 升级成了一个真正的”了解我的工作环境”的助手。</p><p>想搞清楚 MCP 跟 function calling 的区别、什么时候选哪个，可以看<a href="/posts/mcp-vs-function-calling/">这篇 MCP vs Function Calling 对比</a>。想看 MCP server 实战案例，<a href="/posts/mcp-server-internal-tools/">内部工具用 MCP server 的思路</a>里有几个可以直接抄的模板。</p><h2 id="我自己一天怎么切换这几个入口"><a href="#我自己一天怎么切换这几个入口" class="headerlink" title="我自己一天怎么切换这几个入口"></a>我自己一天怎么切换这几个入口</h2><p>给你看一个具体的一天：</p><p><strong>早上 8:30-10:00</strong>：开桌面端 Claude。今天要写一篇文章，先让 Claude 帮我梳理大纲、找论据、列潜在反驳。我开着 Projects，把相关的参考资料都挂在 project 上下文里。这个阶段用桌面端是因为它的 Artifacts 能直接预览写作效果，MCP 能让我连接本地笔记库。</p><p><strong>上午 10:00-12:00</strong>：切到 Claude Code。有个项目要改一个鉴权模块的 bug，我用 Claude Code 跑在 repo 里，直接让它读代码、写测试、跑验证。这种活桌面端做不了——它没法直接动我的文件系统和 git。</p><p><strong>下午 14:00-17:00</strong>：开 API 脚本。今天要把 500 篇客户反馈做情绪分类，写一个 Python 脚本调 API 批量跑。这种规模用桌面端会累死，用 Claude Code 也浪费——API + batch mode 跑一下，等 2 小时就出结果，而且是半价。</p><p><strong>晚上</strong>：偶尔用第三方客户端（比如 Chatbox），因为我同时在测 Claude、GPT、Gemini 三家回答同一个问题，客户端能并排显示对比，方便。</p><p>所以四个入口不是互斥选一个，是<strong>互补</strong>。每个入口解决一类问题。</p><h2 id="几个具体场景的推荐组合"><a href="#几个具体场景的推荐组合" class="headerlink" title="几个具体场景的推荐组合"></a>几个具体场景的推荐组合</h2><p><strong>个人学习&#x2F;写作</strong>：桌面端 Pro，一个订阅够用。</p><p><strong>独立开发者做小产品</strong>：桌面端 Pro（聊天&#x2F;测试用）+ API key（产品调用）。订阅是你的”工作台”，API 是你产品的”发动机”。</p><p><strong>公司团队写代码</strong>：每人一个 Pro 订阅 + Claude Code。如果要做产品内嵌 AI 就再加 API。</p><p><strong>数据处理&#x2F;批量任务</strong>：只需 API，不必订阅。充值好额度，用 batch 接口，定时跑。</p><p><strong>给家人&#x2F;朋友送礼</strong>：他们大概率用桌面端就够了，Pro 订阅当生日礼物最实在。</p><h2 id="最后一点省钱提醒"><a href="#最后一点省钱提醒" class="headerlink" title="最后一点省钱提醒"></a>最后一点省钱提醒</h2><p>Pro 订阅一个月 20 美元，上限大概相当于 API 充值 40-60 美元的用量。如果你每个月 API 消耗接近或超过这个水平、且主要是交互式使用，订阅会更划算。如果你只是零散用、或者用量很不稳定，API 按需付费更好。</p><p>搞清楚怎么选之后，具体到每次请求该用哪档模型，建议看<a href="/posts/claude-family-haiku-sonnet-opus/">Haiku&#x2F;Sonnet&#x2F;Opus 选型那篇</a>，成本还能再挤下来一半。</p><div class="cta-card" style="margin:32px 0;padding:20px 24px;background:#f0f7ff;border-left:4px solid #0c97fe;border-radius:6px;"><p style="margin:0 0 8px;font-weight:600;color:#1f2937;">想系统学 Claude？</p><p style="margin:0;color:#4b5563;font-size:14px;line-height:1.8;">选完入口，下一步看<a href="/posts/claude-code-vs-cursor-cline/">Claude Code 对比 Cursor 和 Cline</a>搞清楚代码工具生态。桌面端要接 MCP 的朋友，<a href="/posts/mcp-vs-function-calling/">MCP 和 Function Calling 的差异</a>是必读。走 API 路线的，<a href="/posts/claude-api-quickstart/">15 分钟 API 快速上手</a>能把你送到第一个请求。</p></div>]]>
    </content>
    <id>https://claude.cocoloop.cn/posts/claude-desktop-vs-code-vs-api/</id>
    <link href="https://claude.cocoloop.cn/posts/claude-desktop-vs-code-vs-api/"/>
    <published>2026-04-18T14:19:00.000Z</published>
    <summary>用 Claude 三年了，身边朋友问我最多的问题从&quot;Claude 怎么用&quot;变成了&quot;我到底该在哪个入口用&quot;。桌面端、Claude Code、API、第三方客户端，四个入口定位差异我讲过不下五十遍，这篇写下来一次说清，附我自己的一天怎么在这四个入口之间切换。</summary>
    <title>Claude 桌面端、Claude Code、API、第三方客户端，到底怎么选</title>
    <updated>2026-04-19T10:57:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Claude 中文知识站</name>
    </author>
    <category term="Prompt 工程" scheme="https://claude.cocoloop.cn/categories/Prompt-%E5%B7%A5%E7%A8%8B/"/>
    <category term="Claude" scheme="https://claude.cocoloop.cn/tags/Claude/"/>
    <category term="Prompt" scheme="https://claude.cocoloop.cn/tags/Prompt/"/>
    <category term="JSON" scheme="https://claude.cocoloop.cn/tags/JSON/"/>
    <category term="Tool Use" scheme="https://claude.cocoloop.cn/tags/Tool-Use/"/>
    <category term="结构化输出" scheme="https://claude.cocoloop.cn/tags/%E7%BB%93%E6%9E%84%E5%8C%96%E8%BE%93%E5%87%BA/"/>
    <content>
      <![CDATA[<p>两年前我刚开始在生产环境跑 Claude，第一个痛点就是 JSON 不稳定。</p><p>你在 playground 里跑 10 次都好好的，上线之后一天跑一万次，总有几十次它给你塞一句”Here is the JSON you requested:”开头，或者最后多个 markdown 代码块标记，或者引号没闭合，或者塞了个注释（JSON 是不允许注释的）。</p><p>那段时间我下游 parser 的 try&#x2F;except 里能喂饱一个告警群。</p><p>后来慢慢摸出来一套组合拳，现在我项目里 JSON 出错率能压到 0.5% 以下，而且剩下那 0.5% 也能被兜底解析救回来。这篇把所有套路说清楚。</p><h2 id="先来组真实数字"><a href="#先来组真实数字" class="headerlink" title="先来组真实数字"></a>先来组真实数字</h2><p>我拿一个抽取 10 个字段的任务跑 10000 条，不同方案的合规率：</p><ul><li>**只说 “Return JSON”**：87.3%</li><li><strong>+ XML 标签 + 明确 schema</strong>：94.1%</li><li><strong>+ Prefill <code>&#123;</code> 作为起始</strong>：97.6%</li><li><strong>+ stop_sequences 卡住结尾</strong>：98.2%</li><li><strong>上 Tool Use（structured output）</strong>：99.8%</li></ul><p>从 87% 到 99.8%，差的不是一点半点。但是 tool use 也不是每个场景都能用，所以后面的套路都要备着。</p><h2 id="套路一：Tool-Use-是王道"><a href="#套路一：Tool-Use-是王道" class="headerlink" title="套路一：Tool Use 是王道"></a>套路一：Tool Use 是王道</h2><p>这是 Anthropic 官方也在推的方案。本质上你定义一个 tool（带 JSON schema），让 Claude”调用”这个 tool 来输出——Claude 在调用 tool 时的参数就是严格遵循 schema 的 JSON。</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><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">tools = [&#123;</span><br><span class="line">    <span class="string">&quot;name&quot;</span>: <span class="string">&quot;extract_info&quot;</span>,</span><br><span class="line">    <span class="string">&quot;description&quot;</span>: <span class="string">&quot;抽取合同关键信息&quot;</span>,</span><br><span class="line">    <span class="string">&quot;input_schema&quot;</span>: &#123;</span><br><span class="line">        <span class="string">&quot;type&quot;</span>: <span class="string">&quot;object&quot;</span>,</span><br><span class="line">        <span class="string">&quot;properties&quot;</span>: &#123;</span><br><span class="line">            <span class="string">&quot;party_a&quot;</span>: &#123;<span class="string">&quot;type&quot;</span>: <span class="string">&quot;string&quot;</span>&#125;,</span><br><span class="line">            <span class="string">&quot;party_b&quot;</span>: &#123;<span class="string">&quot;type&quot;</span>: <span class="string">&quot;string&quot;</span>&#125;,</span><br><span class="line">            <span class="string">&quot;amount&quot;</span>: &#123;<span class="string">&quot;type&quot;</span>: <span class="string">&quot;number&quot;</span>&#125;,</span><br><span class="line">            <span class="string">&quot;signed_date&quot;</span>: &#123;<span class="string">&quot;type&quot;</span>: <span class="string">&quot;string&quot;</span>, <span class="string">&quot;format&quot;</span>: <span class="string">&quot;date&quot;</span>&#125;,</span><br><span class="line">        &#125;,</span><br><span class="line">        <span class="string">&quot;required&quot;</span>: [<span class="string">&quot;party_a&quot;</span>, <span class="string">&quot;party_b&quot;</span>]</span><br><span class="line">    &#125;</span><br><span class="line">&#125;]</span><br><span class="line"></span><br><span class="line">response = client.messages.create(</span><br><span class="line">    model=<span class="string">&quot;claude-sonnet-4&quot;</span>,</span><br><span class="line">    tools=tools,</span><br><span class="line">    tool_choice=&#123;<span class="string">&quot;type&quot;</span>: <span class="string">&quot;tool&quot;</span>, <span class="string">&quot;name&quot;</span>: <span class="string">&quot;extract_info&quot;</span>&#125;,</span><br><span class="line">    messages=[&#123;<span class="string">&quot;role&quot;</span>: <span class="string">&quot;user&quot;</span>, <span class="string">&quot;content&quot;</span>: <span class="string">&quot;...&quot;</span>&#125;]</span><br><span class="line">)</span><br></pre></td></tr></table></figure></div><p><code>tool_choice</code> 强制指定调用哪个 tool——这样模型不会犹豫要不要调，直接调。返回的 <code>tool_use</code> block 里的 <code>input</code> 就是合规 JSON。</p><p>这条路的好处：</p><ul><li>结构严格，类型会被校验</li><li>不会混入自然语言</li><li>Anthropic 后端做了额外保障</li></ul><p>坏处：</p><ul><li>有些场景你不想引入 tool 的概念（比如一个单次批处理脚本）</li><li>嵌套非常深的 schema 偶尔还是会翻车</li><li>想让模型先”解释一下”再输出 JSON 的场景不适合</li></ul><p>关于 tool use 和 MCP 的关系、什么时候用哪个，<a href="/posts/mcp-vs-function-calling/">这篇</a>我专门讨论过。</p><h2 id="套路二：严格-schema-描述-XML-封装"><a href="#套路二：严格-schema-描述-XML-封装" class="headerlink" title="套路二：严格 schema 描述 + XML 封装"></a>套路二：严格 schema 描述 + XML 封装</h2><p>不用 tool use 的时候，先把你要的结构写清楚。光说”return JSON”不够，得告诉它是什么样的 JSON。</p><div class="code-container" data-rel="Xml"><figure class="iseeu highlight xml"><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></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">output_format</span>&gt;</span></span><br><span class="line">返回严格的 JSON，结构如下：</span><br><span class="line">&#123;</span><br><span class="line">  &quot;party_a&quot;: &quot;string, 甲方公司全称&quot;,</span><br><span class="line">  &quot;party_b&quot;: &quot;string, 乙方公司全称&quot;,</span><br><span class="line">  &quot;amount&quot;: &quot;number, 合同金额，单位元，不含逗号&quot;,</span><br><span class="line">  &quot;signed_date&quot;: &quot;string, 签约日期, 格式 YYYY-MM-DD&quot;,</span><br><span class="line">  &quot;risks&quot;: [</span><br><span class="line">    &#123;&quot;level&quot;: &quot;high|medium|low&quot;, &quot;description&quot;: &quot;string&quot;&#125;</span><br><span class="line">  ]</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">不要用 markdown 代码块包裹。不要加任何解释性文字。</span><br><span class="line">直接以 &#123; 开头，以 &#125; 结尾。</span><br><span class="line"><span class="tag">&lt;/<span class="name">output_format</span>&gt;</span></span><br></pre></td></tr></table></figure></div><p>几个要点：</p><ul><li>每个字段后面跟一句中文说明，比起纯 JSON schema 对 Claude 更友好</li><li>枚举值用 <code>high|medium|low</code> 这种竖线语法，模型理解很好</li><li>明确说”不要 markdown 代码块”、”不要解释文字”——这两条漏掉的话翻车率立刻上去</li><li>用 <code>&lt;output_format&gt;</code> 这种 XML 标签包起来比 markdown 标题稳。Claude 对 XML 的偏好我在<a href="/posts/claude-xml-over-markdown/">这篇</a>里系统讲过</li></ul><h2 id="套路三：Prefill-预填起始"><a href="#套路三：Prefill-预填起始" class="headerlink" title="套路三：Prefill 预填起始"></a>套路三：Prefill 预填起始</h2><p>这是个非常好使的小 trick。在 API 调用里，你可以在 <code>messages</code> 的最后塞一个 assistant 消息，内容是 <code>&#123;</code>——Claude 会从这个 <code>&#123;</code> 继续往下写，自然就不会再加什么”Here is the JSON:”这种废话了。</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><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">messages = [</span><br><span class="line">    &#123;<span class="string">&quot;role&quot;</span>: <span class="string">&quot;user&quot;</span>, <span class="string">&quot;content&quot;</span>: <span class="string">&quot;...&quot;</span>&#125;,</span><br><span class="line">    &#123;<span class="string">&quot;role&quot;</span>: <span class="string">&quot;assistant&quot;</span>, <span class="string">&quot;content&quot;</span>: <span class="string">&quot;&#123;&quot;</span>&#125;</span><br><span class="line">]</span><br></pre></td></tr></table></figure></div><p>返回结果会缺少最前面的 <code>&#123;</code>，你自己拼回去就行。这个技巧光加这一条，成功率从 94% 干到 97% 以上。</p><p>注意：</p><ul><li>prefill 只在 API 可用，Claude.ai 界面不行</li><li>prefill 内容要和你期望的输出”无缝衔接”，有换行有空格都可能引起模型迷惑</li><li>如果你用 XML 输出格式，prefill 也可以用，比如填 <code>&lt;result&gt;</code></li></ul><h2 id="套路四：Stop-Sequences-卡住结尾"><a href="#套路四：Stop-Sequences-卡住结尾" class="headerlink" title="套路四：Stop Sequences 卡住结尾"></a>套路四：Stop Sequences 卡住结尾</h2><p>前面解决了开头，还有结尾问题。有时候模型会在 JSON 结束后多输出几行解释文字，虽然 parser 能切掉，但不优雅。</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><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">response = client.messages.create(</span><br><span class="line">    ...,</span><br><span class="line">    stop_sequences=[<span class="string">&quot;\n\n&quot;</span>, <span class="string">&quot;```&quot;</span>, <span class="string">&quot;&#125;\n\n&quot;</span>]</span><br><span class="line">)</span><br></pre></td></tr></table></figure></div><p>这个要根据你的 JSON 结构定。如果你的 JSON 只有一个顶层对象，<code>&#125;</code> 后面跟两个换行基本能卡住收尾。如果是嵌套多层的复杂对象，你得想清楚停在哪儿。</p><p>Stop sequences 不会出现在返回结果里，是个干净的截断。</p><h2 id="套路五：兜底解析"><a href="#套路五：兜底解析" class="headerlink" title="套路五：兜底解析"></a>套路五：兜底解析</h2><p>就算你前面四招都用上，总还有那么 0.5% 会翻车。真实线上不能让这 0.5% 打穿 pipeline。我现在的兜底层是这么写的：</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><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="keyword">def</span> <span class="title function_">robust_json_parse</span>(<span class="params">text: <span class="built_in">str</span></span>):</span><br><span class="line">    <span class="comment"># 1. 直接解析</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        <span class="keyword">return</span> json.loads(text)</span><br><span class="line">    <span class="keyword">except</span> json.JSONDecodeError:</span><br><span class="line">        <span class="keyword">pass</span></span><br><span class="line"></span><br><span class="line">    <span class="comment"># 2. 剥离 markdown 代码块</span></span><br><span class="line">    <span class="keyword">if</span> <span class="string">&quot;```&quot;</span> <span class="keyword">in</span> text:</span><br><span class="line">        text = re.sub(<span class="string">r&quot;```(?:json)?\s*&quot;</span>, <span class="string">&quot;&quot;</span>, text)</span><br><span class="line">        text = text.replace(<span class="string">&quot;```&quot;</span>, <span class="string">&quot;&quot;</span>)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 3. 找到第一个 &#123; 和最后一个 &#125;</span></span><br><span class="line">    start = text.find(<span class="string">&quot;&#123;&quot;</span>)</span><br><span class="line">    end = text.rfind(<span class="string">&quot;&#125;&quot;</span>)</span><br><span class="line">    <span class="keyword">if</span> start &gt;= <span class="number">0</span> <span class="keyword">and</span> end &gt; start:</span><br><span class="line">        text = text[start:end+<span class="number">1</span>]</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 4. 再试</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        <span class="keyword">return</span> json.loads(text)</span><br><span class="line">    <span class="keyword">except</span> json.JSONDecodeError:</span><br><span class="line">        <span class="keyword">pass</span></span><br><span class="line"></span><br><span class="line">    <span class="comment"># 5. 修常见错误：尾逗号、单引号</span></span><br><span class="line">    text = re.sub(<span class="string">r&quot;,\s*&#125;&quot;</span>, <span class="string">&quot;&#125;&quot;</span>, text)</span><br><span class="line">    text = re.sub(<span class="string">r&quot;,\s*\]&quot;</span>, <span class="string">&quot;]&quot;</span>, text)</span><br><span class="line">    text = text.replace(<span class="string">&quot;&#x27;&quot;</span>, <span class="string">&#x27;&quot;&#x27;</span>)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 6. 还是不行，重试调用模型</span></span><br><span class="line">    <span class="keyword">return</span> <span class="literal">None</span>  <span class="comment"># 触发上层重试</span></span><br></pre></td></tr></table></figure></div><p>这套逻辑能救回大约 90% 的”小翻车”。剩下实在救不回来的，触发重试机制，重跑一次基本就好了。</p><h2 id="几个容易踩的细节"><a href="#几个容易踩的细节" class="headerlink" title="几个容易踩的细节"></a>几个容易踩的细节</h2><p><strong>转义字符的坑。</strong>中文内容里夹英文引号、代码片段里的反斜杠，这些在 JSON 里必须转义。Claude 大多数时候会处理对，但偶尔会漏。我现在的做法是：<strong>需要输出代码或者含引号内容时，尽量用 base64 或单独字段存储</strong>，避免它在 string 里硬转义。</p><p><strong>日期和数字。</strong>你在 schema 里说”amount: number”，它有 3% 概率给你一个 <code>&quot;12000&quot;</code> 字符串。解决办法：要么 parser 里做类型归一，要么在 schema 描述里加一句”金额必须是纯数字，不能加引号”。</p><p><strong>可选字段。</strong>Claude 对”可选”理解有时候偏差。你让它”字段 X 如果没有就不要这个 key”，它有时候会给你填 <code>null</code> 或空字符串。我现在干脆规定：”所有可选字段，如果无值，填 null”——统一了就好处理。</p><p><strong>多层嵌套深不要过四层。</strong>我跑过一个五层深的 schema，错误率直接飙到 15%。复杂结构建议拍扁成多轮调用，每次处理一层。</p><h2 id="我现在的生产标准模板"><a href="#我现在的生产标准模板" class="headerlink" title="我现在的生产标准模板"></a>我现在的生产标准模板</h2><p>组合起来长这样：</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><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">SYSTEM = <span class="string">&quot;&quot;&quot;你是一个结构化数据抽取助手。严格按照指定 JSON schema 输出，</span></span><br><span class="line"><span class="string">不要添加任何解释文字，不要用 markdown 代码块包裹。&quot;&quot;&quot;</span></span><br><span class="line"></span><br><span class="line">USER = <span class="string">f&quot;&quot;&quot;</span></span><br><span class="line"><span class="string">&lt;input&gt;</span></span><br><span class="line"><span class="string"><span class="subst">&#123;content&#125;</span></span></span><br><span class="line"><span class="string">&lt;/input&gt;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">&lt;output_format&gt;</span></span><br><span class="line"><span class="string"><span class="subst">&#123;json_schema_description&#125;</span></span></span><br><span class="line"><span class="string">&lt;/output_format&gt;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">直接输出 JSON，以 &#123;&#123; 开头。</span></span><br><span class="line"><span class="string">&quot;&quot;&quot;</span></span><br><span class="line"></span><br><span class="line">response = client.messages.create(</span><br><span class="line">    model=<span class="string">&quot;claude-sonnet-4&quot;</span>,</span><br><span class="line">    system=SYSTEM,</span><br><span class="line">    messages=[</span><br><span class="line">        &#123;<span class="string">&quot;role&quot;</span>: <span class="string">&quot;user&quot;</span>, <span class="string">&quot;content&quot;</span>: USER&#125;,</span><br><span class="line">        &#123;<span class="string">&quot;role&quot;</span>: <span class="string">&quot;assistant&quot;</span>, <span class="string">&quot;content&quot;</span>: <span class="string">&quot;&#123;&quot;</span>&#125;</span><br><span class="line">    ],</span><br><span class="line">    stop_sequences=[<span class="string">&quot;\n\n\n&quot;</span>],</span><br><span class="line">    max_tokens=<span class="number">2048</span>,</span><br><span class="line">)</span><br><span class="line"></span><br><span class="line">raw = <span class="string">&quot;&#123;&quot;</span> + response.content[<span class="number">0</span>].text</span><br><span class="line">result = robust_json_parse(raw)</span><br><span class="line"><span class="keyword">if</span> result <span class="keyword">is</span> <span class="literal">None</span>:</span><br><span class="line">    <span class="comment"># 重试一次</span></span><br><span class="line">    ...</span><br></pre></td></tr></table></figure></div><p>能用 tool use 的场景我直接上 tool use。不能用的场景这个模板顶得住 99.5%。</p><h2 id="最后说一句"><a href="#最后说一句" class="headerlink" title="最后说一句"></a>最后说一句</h2><p>JSON 稳定性这事，单个技巧提升都是边际的，组合起来才是降维打击。我见过太多人在一个技巧上死磕——“我加了 prefill 还是不稳啊”。那当然，你没加 schema 描述、没加 stop、没加兜底，单靠 prefill 救不了命。</p><p>把这 5 招全部铺上，再留一层重试和兜底，基本能把 JSON 这块的工程风险降到可以不再每天看告警的程度。</p><p>对了，如果你项目还没开 prompt caching，赶紧开。JSON schema 这种长期固定的内容进了缓存，省下的钱够你一个月的咖啡钱。<a href="/posts/prompt-caching-deep-guide/">这篇</a>里有详细的配置方法。刚开始接触 Claude API 的同学可以先去看看<a href="/posts/claude-api-quickstart/">API 快速入门</a>打个底。</p><div class="cta-card" style="margin:32px 0;padding:20px 24px;background:#f0f7ff;border-left:4px solid #0c97fe;border-radius:6px;"><p style="margin:0 0 8px;font-weight:600;color:#1f2937;">延伸阅读</p><p style="margin:0;color:#4b5563;font-size:14px;line-height:1.8;">Tool use 和 MCP 怎么选，看 <a href="/posts/mcp-vs-function-calling/">MCP vs Function Calling</a>。让 schema 进缓存省钱，去 <a href="/posts/prompt-caching-deep-guide/">Prompt Caching 深度指南</a>。API 入门和基本用法，看 <a href="/posts/claude-api-quickstart/">Claude API 快速入门</a>。配合 XML 标签让整套 prompt 更稳，别错过 <a href="/posts/claude-xml-over-markdown/">XML vs Markdown 对比</a>。</p></div>]]>
    </content>
    <id>https://claude.cocoloop.cn/posts/prompt-output-format-json-schema/</id>
    <link href="https://claude.cocoloop.cn/posts/prompt-output-format-json-schema/"/>
    <published>2026-04-18T14:00:00.000Z</published>
    <summary>直接让 Claude &quot;return JSON&quot; 我在生产环境里实测过一万条，成功率 87.3%。听起来不低吧？可对一个需要下游解析的 pipeline 来说，那 12.7% 的失败就是 1270 条死数据。这篇把我两年来在各种项目里打磨出来的 5 个套路全倒出来——从 tool use 到 prefill 到兜底解析，拼起来现在稳定在 99.5%+。</summary>
    <title>让 Claude 稳定吐 JSON 的 5 个套路</title>
    <updated>2026-04-19T01:30:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Claude 中文知识站</name>
    </author>
    <category term="入门" scheme="https://claude.cocoloop.cn/categories/%E5%85%A5%E9%97%A8/"/>
    <category term="Claude" scheme="https://claude.cocoloop.cn/tags/Claude/"/>
    <category term="API" scheme="https://claude.cocoloop.cn/tags/API/"/>
    <category term="新手" scheme="https://claude.cocoloop.cn/tags/%E6%96%B0%E6%89%8B/"/>
    <category term="Python" scheme="https://claude.cocoloop.cn/tags/Python/"/>
    <content>
      <![CDATA[<p>上周又有朋友来问我”Claude API 怎么用”，我发现每次都要重讲一遍，干脆整理成文。</p><p>这篇是完全按照”一个新手第一次碰 Claude API”的真实顺序来的，我自己按表计了时——从注册到第一个请求跑出来，熟手 5 分钟，生手大概 15 分钟。</p><h2 id="Step-1：到-console-anthropic-com-注册"><a href="#Step-1：到-console-anthropic-com-注册" class="headerlink" title="Step 1：到 console.anthropic.com 注册"></a>Step 1：到 console.anthropic.com 注册</h2><p>这个地址要认准。不是 claude.ai（那是聊天产品），是 console.anthropic.com（开发者后台）。</p><p>国内用户一个现实问题：注册需要一个能接收短信验证码的手机号，国内号码是收不到的，需要一个海外号或者能收海外短信的虚拟号。这不是 Claude 的问题，是 Anthropic 现在的注册门槛。解决方案我就不在这里展开了，网上方案很多。</p><p>注册完之后登录，左侧菜单找 <strong>Billing</strong>，先把付款方式加上。没有付款方式的账号有免费额度但很少，几次测试就花完了。</p><h2 id="Step-2：创建一个-API-Key"><a href="#Step-2：创建一个-API-Key" class="headerlink" title="Step 2：创建一个 API Key"></a>Step 2：创建一个 API Key</h2><p>Dashboard 左侧 <strong>API Keys</strong> → <strong>Create Key</strong>，给它起个名字比如 <code>local-dev</code>，点生成。</p><p><strong>关键</strong>：这个 key 只会显示一次。复制下来立刻存好，页面关了就看不到了，只能重新生成。</p><p>存到哪？<strong>别存到代码里</strong>。我见过不止三个朋友把 key 直接 commit 到 GitHub 公开仓库的——有人 20 分钟内就收到 Anthropic 的告警邮件说 key 已经泄漏自动禁用了，运气好没扣钱；有人没这么走运，被人刷了 300 多刀。</p><h2 id="Step-3：把-key-存到环境变量"><a href="#Step-3：把-key-存到环境变量" class="headerlink" title="Step 3：把 key 存到环境变量"></a>Step 3：把 key 存到环境变量</h2><p>Mac&#x2F;Linux，在 <code>~/.zshrc</code> 或 <code>~/.bashrc</code> 加一行：</p><div class="code-container" data-rel="Bash"><figure class="iseeu 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">export</span> ANTHROPIC_API_KEY=<span class="string">&quot;sk-ant-xxx...&quot;</span></span><br></pre></td></tr></table></figure></div><p>然后 <code>source ~/.zshrc</code>。</p><p>Windows PowerShell：</p><div class="code-container" data-rel="Powershell"><figure class="iseeu highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[<span class="type">System.Environment</span>]::SetEnvironmentVariable(<span class="string">&quot;ANTHROPIC_API_KEY&quot;</span>,<span class="string">&quot;sk-ant-xxx...&quot;</span>,<span class="string">&quot;User&quot;</span>)</span><br></pre></td></tr></table></figure></div><p>重开一下 terminal。</p><p>验证：<code>echo $ANTHROPIC_API_KEY</code>（Windows 是 <code>echo $env:ANTHROPIC_API_KEY</code>），能打出 sk-ant- 开头的字符串就 OK。</p><h2 id="Step-4：第一个-curl-请求"><a href="#Step-4：第一个-curl-请求" class="headerlink" title="Step 4：第一个 curl 请求"></a>Step 4：第一个 curl 请求</h2><p>测通这个说明网络+key 都没问题：</p><div class="code-container" data-rel="Bash"><figure class="iseeu 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></pre></td><td class="code"><pre><span class="line">curl https://api.anthropic.com/v1/messages \</span><br><span class="line">  --header <span class="string">&quot;x-api-key: <span class="variable">$ANTHROPIC_API_KEY</span>&quot;</span> \</span><br><span class="line">  --header <span class="string">&quot;anthropic-version: 2023-06-01&quot;</span> \</span><br><span class="line">  --header <span class="string">&quot;content-type: application/json&quot;</span> \</span><br><span class="line">  --data <span class="string">&#x27;&#123;</span></span><br><span class="line"><span class="string">    &quot;model&quot;: &quot;claude-sonnet-4-6&quot;,</span></span><br><span class="line"><span class="string">    &quot;max_tokens&quot;: 100,</span></span><br><span class="line"><span class="string">    &quot;messages&quot;: [&#123;&quot;role&quot;: &quot;user&quot;, &quot;content&quot;: &quot;用一句话介绍你自己&quot;&#125;]</span></span><br><span class="line"><span class="string">  &#125;&#x27;</span></span><br></pre></td></tr></table></figure></div><p>正常情况下你会看到一个 JSON 返回，里面 <code>content[0].text</code> 就是 Claude 的回答。</p><p>跑不通？往下看 Step 7 的排错清单。</p><h2 id="Step-5：Python-版"><a href="#Step-5：Python-版" class="headerlink" title="Step 5：Python 版"></a>Step 5：Python 版</h2><p>我假设你装了 Python 3.10+。</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pip install anthropic</span><br></pre></td></tr></table></figure></div><p>写一个 <code>hello.py</code>：</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> anthropic <span class="keyword">import</span> Anthropic</span><br><span class="line"></span><br><span class="line">client = Anthropic()  <span class="comment"># 会自动读 ANTHROPIC_API_KEY</span></span><br><span class="line"></span><br><span class="line">response = client.messages.create(</span><br><span class="line">    model=<span class="string">&quot;claude-sonnet-4-6&quot;</span>,</span><br><span class="line">    max_tokens=<span class="number">200</span>,</span><br><span class="line">    messages=[</span><br><span class="line">        &#123;<span class="string">&quot;role&quot;</span>: <span class="string">&quot;user&quot;</span>, <span class="string">&quot;content&quot;</span>: <span class="string">&quot;用三句话介绍一下 Anthropic&quot;</span>&#125;</span><br><span class="line">    ]</span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(response.content[<span class="number">0</span>].text)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;\n---\n输入 tokens: <span class="subst">&#123;response.usage.input_tokens&#125;</span>&quot;</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;输出 tokens: <span class="subst">&#123;response.usage.output_tokens&#125;</span>&quot;</span>)</span><br></pre></td></tr></table></figure></div><p><code>python hello.py</code>，看到回答就成了。注意最后两行——这是我强烈建议你第一天就加上去的，<strong>永远打印 token 用量</strong>，后面我会讲为什么。</p><h2 id="Step-6：Node-js-版"><a href="#Step-6：Node-js-版" class="headerlink" title="Step 6：Node.js 版"></a>Step 6：Node.js 版</h2><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install @anthropic-ai/sdk</span><br></pre></td></tr></table></figure></div><p><code>hello.mjs</code>：</p><div class="code-container" data-rel="Javascript"><figure class="iseeu highlight javascript"><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="keyword">import</span> <span class="title class_">Anthropic</span> <span class="keyword">from</span> <span class="string">&quot;@anthropic-ai/sdk&quot;</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> client = <span class="keyword">new</span> <span class="title class_">Anthropic</span>();</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> response = <span class="keyword">await</span> client.<span class="property">messages</span>.<span class="title function_">create</span>(&#123;</span><br><span class="line">  <span class="attr">model</span>: <span class="string">&quot;claude-sonnet-4-6&quot;</span>,</span><br><span class="line">  <span class="attr">max_tokens</span>: <span class="number">200</span>,</span><br><span class="line">  <span class="attr">messages</span>: [&#123; <span class="attr">role</span>: <span class="string">&quot;user&quot;</span>, <span class="attr">content</span>: <span class="string">&quot;用三句话介绍一下 Anthropic&quot;</span> &#125;],</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(response.<span class="property">content</span>[<span class="number">0</span>].<span class="property">text</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`input: <span class="subst">$&#123;response.usage.input_tokens&#125;</span> / output: <span class="subst">$&#123;response.usage.output_tokens&#125;</span>`</span>);</span><br></pre></td></tr></table></figure></div><p><code>node hello.mjs</code>。</p><h2 id="Step-7：报错了怎么办"><a href="#Step-7：报错了怎么办" class="headerlink" title="Step 7：报错了怎么办"></a>Step 7：报错了怎么办</h2><p>按出现频率排：</p><p><strong>401 Unauthorized</strong>：key 错了。检查环境变量是不是真的生效了，有没有多余的空格或引号。最常见是 Windows 下 SetEnvironmentVariable 之后没重开 terminal。</p><p><strong>429 Too Many Requests</strong>：限流。免费账号和刚加付款方式的账号初始限额很低。查 Anthropic console 里的 <strong>Limits</strong> 页面，看你当前等级。等几分钟重试，或者充值提升等级。</p><p><strong>400 Invalid Request</strong>：参数有问题。最常见是 model 名字写错（比如写成 <code>claude-4.6-sonnet</code> 这种倒过来的），或者 <code>max_tokens</code> 忘了填，或者 <code>messages</code> 里 role 不是 <code>user</code>&#x2F;<code>assistant</code>。错误返回 JSON 里通常会告诉你具体哪个字段有问题，认真看一眼。</p><p><strong>500 &#x2F; 529</strong>：Anthropic 自己的问题或者过载。重试，或者上 status.anthropic.com 看看。</p><p><strong>ConnectionError</strong>：网络问题。国内访问需要稳定的出口，不然会很痛苦。</p><h2 id="那个我刚开始不知道的计费小坑"><a href="#那个我刚开始不知道的计费小坑" class="headerlink" title="那个我刚开始不知道的计费小坑"></a>那个我刚开始不知道的计费小坑</h2><p>讲几个官方文档写了但你不读就发现不了的事：</p><p><strong>输出比输入贵 5 倍</strong>。Sonnet 4.6 输入 3 美元&#x2F;百万 tokens，输出 15 美元&#x2F;百万 tokens。意思是你生成 1000 字的成本比你输入 1000 字高得多。所以如果你在做”让 Claude 大段生成”的任务，成本主要在输出端。我有个朋友第一周账单爆了，就是因为他让 Claude 一次性生成 30K tokens 的长文，一天 200 次。</p><p><strong>缓存 tokens 单独计费，但便宜很多</strong>。同一段 prompt（比如系统提示词）重复用的时候，Anthropic 允许你缓存它，缓存命中的 token 只收 10% 的价钱。我在<a href="/posts/prompt-caching-deep-guide/">这篇 prompt caching 深度指南</a>里写得很细，如果你的系统 prompt 长、且重复调用——比如 RAG、客服 bot、Agent workflow——一定要配置它，能省 60% 以上。</p><p>**max_tokens 不是”期望输出”是”最多输出”**。但你设 8000 和设 200 的成本差异只体现在实际生成了多少——没生成的不收费。所以设大点没事。但如果你不设限，模型可能真的给你写 8000，一次把你一天的预算吃光。</p><p><strong>batch API 打 50% 折扣</strong>。如果你不需要实时响应、可以异步等几小时，用 batch API 价格直接砍半。批量跑总结、分类、翻译这种活非常适合。</p><h2 id="跑通之后的下一步"><a href="#跑通之后的下一步" class="headerlink" title="跑通之后的下一步"></a>跑通之后的下一步</h2><p>第一个请求跑通之后我建议你做三件事：</p><p>一是把 <code>print(response.usage)</code> 这行代码作为永久习惯留着。成本意识是用 API 的第一课。</p><p>二是去试试 streaming 模式（<code>client.messages.stream(...)</code>），用户体验完全不一样。</p><p>三是搞清楚 Claude 的三档模型价格差异，按任务选型——<a href="/posts/claude-family-haiku-sonnet-opus/">三档选型这篇</a>我详细写过。</p><div class="cta-card" style="margin:32px 0;padding:20px 24px;background:#f0f7ff;border-left:4px solid #0c97fe;border-radius:6px;"><p style="margin:0 0 8px;font-weight:600;color:#1f2937;">想系统学 Claude？</p><p style="margin:0;color:#4b5563;font-size:14px;line-height:1.8;">跑通 API 之后，强烈建议立刻学<a href="/posts/prompt-caching-deep-guide/">prompt caching 深度配置</a>，这是省钱的第一优先级。想搭真正的产品，<a href="/posts/agent-sdk-architecture/">Agent SDK 架构设计</a>这篇从 0 讲到可上线。想知道什么时候该用 API 什么时候用桌面端，<a href="/posts/claude-desktop-vs-code-vs-api/">四个入口对比</a>能给你清晰答案。</p></div>]]>
    </content>
    <id>https://claude.cocoloop.cn/posts/claude-api-quickstart/</id>
    <link href="https://claude.cocoloop.cn/posts/claude-api-quickstart/"/>
    <published>2026-04-18T12:03:00.000Z</published>
    <summary>我去年带过一个完全零编程基础的运营朋友跑通第一个 Claude API，全程 14 分钟。这篇按时间线一步步写下来，注册、拿 key、环境变量、curl/Python/Node 三版 hello-world、常见 401/429/400 怎么自查、一个我当时自己没注意的计费小坑。</summary>
    <title>从注册到第一个 API 请求，15 分钟跑通 Claude</title>
    <updated>2026-04-19T08:42:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Claude 中文知识站</name>
    </author>
    <category term="Prompt 工程" scheme="https://claude.cocoloop.cn/categories/Prompt-%E5%B7%A5%E7%A8%8B/"/>
    <category term="Claude" scheme="https://claude.cocoloop.cn/tags/Claude/"/>
    <category term="Prompt" scheme="https://claude.cocoloop.cn/tags/Prompt/"/>
    <category term="Chain of Thought" scheme="https://claude.cocoloop.cn/tags/Chain-of-Thought/"/>
    <category term="Extended Thinking" scheme="https://claude.cocoloop.cn/tags/Extended-Thinking/"/>
    <content>
      <![CDATA[<p>大概一年半前我做过一个医疗 FAQ 智能客服，核心任务是”从 800 条标准问答里召回最相关的 3 条”。0-shot + 结构化 prompt 跑下来准确率 92%，客户验收通过。</p><p>上线一个月后我想着优化一下，加了 <code>&lt;thinking&gt;</code> 让模型”先分析问题意图再选择答案”。心想这肯定更稳吧，结果一跑——84%。</p><p>整整掉了 8 个点。我反复看了很多 case 才搞明白：这类任务本质上是”语义相似度召回”，模型在 embedding 层面其实已经做对了判断，你硬让它”逐步推理”，它反而会被自己推出来的中间结论带偏。</p><p>这事给我上了一课。CoT（Chain of Thought）不是越多越好，更不是万能。这篇说一下我现在怎么判断。</p><h2 id="什么时候-CoT-是神器"><a href="#什么时候-CoT-是神器" class="headerlink" title="什么时候 CoT 是神器"></a>什么时候 CoT 是神器</h2><p>先说有用的场景。我经验里 CoT 确实能显著提升效果的几类任务：</p><p><strong>一、数学和数值推理。</strong>不管多简单，只要涉及”一步算错全盘错”的计算，让它一步步来就对了。实测一个三步应用题，直接问正确率 73%，加 <code>&lt;thinking&gt;</code> 后 94%。这个提升是稳的。</p><p><strong>二、多跳问答。</strong>“根据 A 文档里的 X 和 B 文档里的 Y 推出 Z”这种。模型需要先把中间结论落到纸面，不然容易幻觉。</p><p><strong>三、合规 &#x2F; 规则判断。</strong>比如”判断这份合同是否违反下面 7 条规则”。你不让它一条一条过，它会漏。让它显式地说”规则 1: 符合；规则 2: 不符合，因为…”准确率直接上去。</p><p><strong>四、复杂决策树。</strong>客服分流、工单分类有 20 多种类别且存在嵌套层级的时候，CoT 能让模型稳得多。</p><p>这些任务的共同点：<strong>有可拆分的中间步骤、有客观验证路径、犯错代价高。</strong>给它展开的空间，它会自己纠偏。</p><h2 id="什么时候-CoT-反而添乱"><a href="#什么时候-CoT-反而添乱" class="headerlink" title="什么时候 CoT 反而添乱"></a>什么时候 CoT 反而添乱</h2><p>这些是我踩过坑的：</p><p><strong>一、纯召回 &#x2F; 纯匹配任务。</strong>像我开头说的那个 FAQ 项目。模型其实一眼就知道答案，你让它”分析再选”是在给它添乱。</p><p><strong>二、简单分类。</strong>三到五个类别、边界清楚的那种。加 CoT 会让模型过度理由化——“这条评论包含了正面情绪但也有一丝失望所以应该是…”结果越想越歪。直接判断快又稳。</p><p><strong>三、创作 &#x2F; 生成任务。</strong>让它写一个故事前先 <code>&lt;thinking&gt;</code> 梳理一下人物？没必要。创作是发散的，强行收窄到”先想后写”反而让输出变得程式化。</p><p><strong>四、高吞吐短响应场景。</strong>API 客服实时应答，延迟要求 500ms 以内，你加一段思考就是 500+ tokens 的开销，用户体验直接崩。这时候宁可损失 2-3 个点的准确率也要快。</p><p>判断逻辑大致是：<strong>任务能不能”一眼看出对错”？能的话，CoT 大概率添乱。需要”想一下才能判断对错”的，CoT 才有意义。</strong></p><h2 id="标签的正确用法"><a href="#标签的正确用法" class="headerlink" title="&lt;thinking&gt; 标签的正确用法"></a><code>&lt;thinking&gt;</code> 标签的正确用法</h2><p>决定要用 CoT 之后，怎么用也有讲究。我看过太多人把这个标签用歪了。</p><p><strong>错误用法一：标签里塞”万能咒语”。</strong></p><div class="code-container" data-rel="Plaintext"><figure class="iseeu 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><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&lt;thinking&gt;</span><br><span class="line">请仔细思考这个问题，考虑所有可能的情况，</span><br><span class="line">确保你的回答准确无误。</span><br><span class="line">&lt;/thinking&gt;</span><br></pre></td></tr></table></figure></div><p>这种写法 Claude 看了基本等于没看。空洞的”请认真思考”对输出没任何指导作用。</p><p><strong>错误用法二：要求固定的思考步骤但步骤不匹配任务。</strong></p><div class="code-container" data-rel="Plaintext"><figure class="iseeu 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><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">&lt;thinking&gt;</span><br><span class="line">1. 分析用户意图</span><br><span class="line">2. 检索相关信息</span><br><span class="line">3. 组织回答</span><br><span class="line">&lt;/thinking&gt;</span><br></pre></td></tr></table></figure></div><p>这种模板如果和真实任务路径对不上，反而在限制模型。比如任务是个简单数值题，它会被迫走”分析用户意图”这一步，浪费 token 还可能走偏。</p><p><strong>我现在的写法：任务依赖型，而不是通用型。</strong></p><p>合规判断场景：</p><div class="code-container" data-rel="Xml"><figure class="iseeu highlight xml"><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="tag">&lt;<span class="name">thinking</span>&gt;</span></span><br><span class="line">先把合同里所有可能涉及规则的条款列出来，</span><br><span class="line">对每一条规则判断：符合 / 不符合 / 不适用。</span><br><span class="line">所有规则过完再给最终结论。</span><br><span class="line"><span class="tag">&lt;/<span class="name">thinking</span>&gt;</span></span><br></pre></td></tr></table></figure></div><p>数学题场景：</p><div class="code-container" data-rel="Xml"><figure class="iseeu highlight xml"><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="tag">&lt;<span class="name">thinking</span>&gt;</span></span><br><span class="line">逐步列出计算过程，每一步明确说明依据的条件和得到的中间值。</span><br><span class="line">算完后回头验算一遍。</span><br><span class="line"><span class="tag">&lt;/<span class="name">thinking</span>&gt;</span></span><br></pre></td></tr></table></figure></div><p>具体、可执行、紧贴任务。不是给模型”打气”，是给它”操作手册”。</p><h2 id="那个”让它思考反而更错”的-case"><a href="#那个”让它思考反而更错”的-case" class="headerlink" title="那个”让它思考反而更错”的 case"></a>那个”让它思考反而更错”的 case</h2><p>再讲个我印象深的反例。某金融客户要做”判断一条新闻是利好还是利空”。</p><p>0-shot 准确率 81%，我觉得还能更高，加了一段：</p><div class="code-container" data-rel="Xml"><figure class="iseeu highlight xml"><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="tag">&lt;<span class="name">thinking</span>&gt;</span></span><br><span class="line">先分析这条新闻涉及的主体是谁、事件性质是什么、</span><br><span class="line">短期影响和长期影响分别如何、最后综合判断利好利空。</span><br><span class="line"><span class="tag">&lt;/<span class="name">thinking</span>&gt;</span></span><br></pre></td></tr></table></figure></div><p>测下来 76%。反复看了 case 之后我发现问题：<strong>金融新闻的”利好利空”很多时候是情感驱动的市场反应，不是严密因果推理的结果。</strong></p><p>你让模型去分析”长期影响”，它经常会推出一个”虽然短期看是利空但长期利好”的结论，结果跟市场真实反应完全相反。真实市场就是看短期情绪，不看你的长期理性推理。</p><p>后来我把 thinking 拿掉，改成一条简短的 hint：”从市场短期情绪反应的角度判断”，准确率回到 81% 并稳定在那。</p><p><strong>这个教训是：CoT 的前提是任务本身有”可推理”的结构。没有这个前提，你强行推理就是在制造噪声。</strong></p><h2 id="Extended-Thinking-模式怎么看"><a href="#Extended-Thinking-模式怎么看" class="headerlink" title="Extended Thinking 模式怎么看"></a>Extended Thinking 模式怎么看</h2><p>Claude 后来出的 extended thinking 模式（就是那个可以看到完整思考链、token 消耗翻倍的那个）我也用过不少。</p><p><strong>值得开的场景：</strong></p><ul><li>复杂代码生成（写一个有设计模式考虑的完整模块）</li><li>多文档综合分析</li><li>需要调试的 bug 排查</li><li>棋类 &#x2F; 规则类博弈决策</li></ul><p><strong>不值得开的场景：</strong></p><ul><li>所有短平快任务</li><li>写营销文案、客服回复</li><li>文档抽取（大部分情况）</li><li>简单的代码 review</li></ul><p>成本上，extended thinking 的 token 消耗能达到常规的 2-5 倍。我自己项目里的原则是：<strong>能用 Sonnet 常规模式解决的事，不开 thinking；必须开的时候，先用 Opus 试，效果 OK 再考虑降级。</strong><a href="/posts/claude-family-haiku-sonnet-opus/">Claude 家族那篇</a>里有更细的模型选型讨论。</p><p>还有个细节：extended thinking 模式下，prompt caching 的表现和常规模式有些差异，具体的我在<a href="/posts/prompt-caching-deep-guide/">缓存深度指南</a>里提过。</p><h2 id="我的决策树"><a href="#我的决策树" class="headerlink" title="我的决策树"></a>我的决策树</h2><p>简化一下我现在的判断流程：</p><ol><li>先 0-shot 跑 baseline，记录准确率和延迟</li><li>分析错误 case：错的地方是”不会”还是”没想到”？<ul><li>“不会”（知识 &#x2F; 能力不够）→ 换更强的模型，或者加 few-shot，CoT 救不了</li><li>“没想到”（漏掉一步推理）→ 上 CoT 可能有效</li></ul></li><li>如果任务天然是”一眼看对错”的类型 → 跳过 CoT</li><li>如果任务需要多步推理且每步可验证 → 上 CoT，写任务依赖型 thinking</li><li>CoT 之后再评估一次准确率和延迟，权衡是否值得</li></ol><p>顺便说一句，CoT 和 few-shot 不是互斥的。有时候我会写 3 条带 thinking 过程的示例，让模型学会”怎么思考”。这种组合在复杂推理上特别猛。few-shot 的数量和顺序我在<a href="/posts/prompt-few-shot-design/">另一篇</a>里细讲了。</p><h2 id="最后"><a href="#最后" class="headerlink" title="最后"></a>最后</h2><p>CoT 这个东西，两年前大家吹它是灵丹妙药，现在业内已经慢慢意识到它是一把双刃。用对了提升显著，用错了不但浪费 token 还损失精度。</p><p>核心就一句话：<strong>不是所有问题都需要”想一下”才能答。</strong>你问一个人”1+1 等于几”，他想 30 秒再回答你，你反而怀疑他是不是有啥毛病。模型也一样。</p><div class="cta-card" style="margin:32px 0;padding:20px 24px;background:#f0f7ff;border-left:4px solid #0c97fe;border-radius:6px;"><p style="margin:0 0 8px;font-weight:600;color:#1f2937;">延伸阅读</p><p style="margin:0;color:#4b5563;font-size:14px;line-height:1.8;">CoT 和 few-shot 怎么组合，看 <a href="/posts/prompt-few-shot-design/">Few-shot 的 3/5/7 法则</a>。开启 extended thinking 前的模型选型，去 <a href="/posts/claude-family-haiku-sonnet-opus/">Claude 家族 Haiku/Sonnet/Opus 那篇</a>。thinking 模式下的 token 优化，看 <a href="/posts/prompt-caching-deep-guide/">Prompt Caching 深度指南</a>。</p></div>]]>
    </content>
    <id>https://claude.cocoloop.cn/posts/prompt-chain-of-thought-vs-direct/</id>
    <link href="https://claude.cocoloop.cn/posts/prompt-chain-of-thought-vs-direct/"/>
    <published>2026-04-18T11:15:00.000Z</published>
    <summary>
      <![CDATA[有次给一个做 FAQ 召回的项目加了 `<thinking>` 标签，准确率从 92% 掉到 84%。我当时就懵了——不是说让模型思考会更准吗？后来才摸明白，CoT 不是万能补药，用错地方反而拉胯。这篇说一下我现在怎么判断该不该让 Claude 思考、extended thinking 什么时候值得开。]]>
    </summary>
    <title>让 Claude &quot;思考&quot;还是直接&quot;给答案&quot;？我摸出来的分水岭</title>
    <updated>2026-04-19T02:45:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Claude 中文知识站</name>
    </author>
    <category term="入门" scheme="https://claude.cocoloop.cn/categories/%E5%85%A5%E9%97%A8/"/>
    <category term="Claude" scheme="https://claude.cocoloop.cn/tags/Claude/"/>
    <category term="新手" scheme="https://claude.cocoloop.cn/tags/%E6%96%B0%E6%89%8B/"/>
    <category term="使用场景" scheme="https://claude.cocoloop.cn/tags/%E4%BD%BF%E7%94%A8%E5%9C%BA%E6%99%AF/"/>
    <category term="Prompt" scheme="https://claude.cocoloop.cn/tags/Prompt/"/>
    <content>
      <![CDATA[<p>有个朋友上周开了 Claude 账号，问我第一天该怎么用。我发了几句，他说太多了记不住。我想想也是，与其甩一堆能力清单，不如按”正常人真的会遇到的顺序”排一条上手路径。</p><p>下面这 10 个场景是我带过十几个非技术朋友之后总结的，按他们实际使用的先后顺序排，不是按官方文档的功能分类。</p><h2 id="1-总结一篇读不下去的长文章"><a href="#1-总结一篇读不下去的长文章" class="headerlink" title="1. 总结一篇读不下去的长文章"></a>1. 总结一篇读不下去的长文章</h2><p>这是 90% 的人第一次用 Claude 干的活。丢一个链接或者粘贴一大段文字进去，让它告诉你在说什么。</p><p><strong>可直接用的 prompt</strong>：<code>帮我用 5 条以内总结重点，最后加一句作者立场</code></p><p>加那句”最后加一句作者立场”很关键，不然你拿到的就是流水账。Claude 对作者立场的判断比单纯总结好用得多。</p><h2 id="2-重写一封不好意思发的邮件"><a href="#2-重写一封不好意思发的邮件" class="headerlink" title="2. 重写一封不好意思发的邮件"></a>2. 重写一封不好意思发的邮件</h2><p>被客户怼了想回一封不失礼的，或者要跟老板请假又不想显得太随便的，都丢给它。</p><p><strong>prompt</strong>：<code>我想表达 XX 意思，但不要显得太弱/太硬，帮我写一版</code></p><p>头两周我没搞懂的坑：**不要直接让它”帮我写一封邮件”**。你得先把你想表达的核心诉求说清楚，Claude 再往上加语气层。你越具体它越好用。</p><h2 id="3-帮你-review-一段你写的代码"><a href="#3-帮你-review-一段你写的代码" class="headerlink" title="3. 帮你 review 一段你写的代码"></a>3. 帮你 review 一段你写的代码</h2><p>你不用是程序员也能用这个。写个 Excel 公式、一段 Shell 脚本、一段 SQL 查询都行。</p><p><strong>prompt</strong>：<code>这段代码是要做 XX 的，帮我看看有没有 bug 或者能简化的地方</code></p><p>关键是”是要做 XX 的”——光贴代码不说意图，Claude 只能猜，准确率会掉一半。</p><h2 id="4-给你已有的代码写测试"><a href="#4-给你已有的代码写测试" class="headerlink" title="4. 给你已有的代码写测试"></a>4. 给你已有的代码写测试</h2><p>这个是 Claude 做得比我好很多倍的事。我会把一个函数贴过去，让它帮我列 edge case。</p><p><strong>prompt</strong>：<code>帮我为这个函数列出 10 个 edge case，按出现概率排序</code></p><p>去年我有个做支付的客户，让 Claude 帮他审一个结算函数，它列出来的 12 个 case 里有 3 个他们上线 8 个月都没考虑到——包括一个跨时区结算日期的 off-by-one bug。</p><h2 id="5-让它帮你啃一份长-PDF"><a href="#5-让它帮你啃一份长-PDF" class="headerlink" title="5. 让它帮你啃一份长 PDF"></a>5. 让它帮你啃一份长 PDF</h2><p>这是 Claude 最强的主场之一。一份 80 页的投资协议、一本教材、一份财报，都能丢进去让它定向问答。</p><p><strong>prompt</strong>：<code>这份 PDF 里关于 XX 的部分在第几页，请把原文贴给我并翻译</code></p><p><strong>让它贴原文</strong>是个很重要的小技巧。我头两周不知道这个，Claude 给我总结，我信了，结果一查原文根本不是那样。要它贴原文之后，幻觉率降了一大截。</p><h2 id="6-CSV-数据快速分析"><a href="#6-CSV-数据快速分析" class="headerlink" title="6. CSV 数据快速分析"></a>6. CSV 数据快速分析</h2><p>把一个 CSV 丢进去（桌面端支持，API 需要配合 code execution），让它告诉你”这份数据里最异常的是什么”。</p><p><strong>prompt</strong>：<code>这份数据有 XX 行，帮我找出前 5 个异常值并解释为什么异常</code></p><p>这里有个我一直在重复的提示：**不要问”你发现了什么”，要问”按 XX 标准找 5 个”**。开放式提问 Claude 给你的答案通常很平。</p><h2 id="7-读图表、读截图、读手写笔记"><a href="#7-读图表、读截图、读手写笔记" class="headerlink" title="7. 读图表、读截图、读手写笔记"></a>7. 读图表、读截图、读手写笔记</h2><p>上传一张截图，让它帮你读。这个能力在我刚开始用的时候根本想不到会这么好用。我上个月用它读完一本我爷爷留下的中医笔记——手写繁体，识别率 90% 以上。</p><p><strong>prompt</strong>：<code>帮我识别这张图里的所有文字，如果有表格保留结构</code></p><h2 id="8-翻译不是翻译而是本地化"><a href="#8-翻译不是翻译而是本地化" class="headerlink" title="8. 翻译不是翻译而是本地化"></a>8. 翻译不是翻译而是本地化</h2><p>别用 Claude 做机械翻译，那样它还不如 Google。正确的用法是让它做”本地化”——带语气、带语境、带文化适配的转写。</p><p><strong>prompt</strong>：<code>把下面这段英文翻译成面向中国二线城市中年用户的中文，语气要像本地人写的</code></p><p>你会发现出来的东西跟直接翻译完全不是一个东西。我去年做一个出海反向落地项目，这种”反本地化”写法帮团队省了至少 40% 的本地内容生产成本。</p><h2 id="9-串起来做-Agent-工作流"><a href="#9-串起来做-Agent-工作流" class="headerlink" title="9. 串起来做 Agent 工作流"></a>9. 串起来做 Agent 工作流</h2><p>到这一步你已经不是在”用 Claude”了，是在”让 Claude 帮你干活”。简单的 Agent 就是让它读邮件→判断优先级→起草回复→等你确认。</p><p>这块有门槛，涉及到 MCP、tool use 这些概念。入门可以先看<a href="/posts/mcp-vs-function-calling/">我写的 MCP 跟 Function Calling 的对比</a>，把底层机制摸清楚。真要落地的话，<a href="/posts/mcp-server-internal-tools/">内部工具用 MCP server 的思路</a>这篇给了我一个很具体的模板。</p><h2 id="10-搭自己的私人知识库"><a href="#10-搭自己的私人知识库" class="headerlink" title="10. 搭自己的私人知识库"></a>10. 搭自己的私人知识库</h2><p>最终形态。你把自己的所有笔记、邮件、文档、书签都接到 Claude 里，让它成为”比你自己还了解你的那个助手”。</p><p>这条路要走深一点，涉及到 <a href="/posts/claude-md-project-config/">claude.md 项目配置</a> 还有自定义 Skill。我自己也还在调，远没到完美——但是每隔两周我会发现新的玩法。</p><h2 id="头两周我没搞懂的几件事"><a href="#头两周我没搞懂的几件事" class="headerlink" title="头两周我没搞懂的几件事"></a>头两周我没搞懂的几件事</h2><p><strong>“上下文”不是越长越好</strong>。我早期什么都往 prompt 里塞，结果 Claude 开始走神。把不相关的删掉，回答质量立刻上来。这是我从 prompt 时代走到 <a href="/posts/prompt-to-context-engineering/">context engineering 时代</a>之后最大的认知更新。</p><p><strong>“让 Claude 反问你”这个技巧</strong>。我头两周不知道这招，直到有一天 Claude 自己问我：”你确定要按 A 方案还是 B 方案？我默认 A 了。”那之后我写复杂 prompt 都会加一句”如果有关键信息缺失，请先问我再动手”。</p><p><strong>桌面端和 API 不是同一个东西</strong>。桌面端有 Projects、有记忆、有 artifacts，API 是裸模型。新手建议先在桌面端玩明白了再碰 API。</p><h2 id="最后一个小建议"><a href="#最后一个小建议" class="headerlink" title="最后一个小建议"></a>最后一个小建议</h2><p>别把 Claude 当 Google 用。Google 帮你找答案，Claude 帮你想问题。两种工具的使用节奏完全不一样——Claude 最擅长的是”你有一个模糊的想法，让它帮你把边缘磨清楚”。</p><div class="cta-card" style="margin:32px 0;padding:20px 24px;background:#f0f7ff;border-left:4px solid #0c97fe;border-radius:6px;"><p style="margin:0 0 8px;font-weight:600;color:#1f2937;">想系统学 Claude？</p><p style="margin:0;color:#4b5563;font-size:14px;line-height:1.8;">如果上面这 10 个场景你至少试过 3 个，接下来可以深入学<a href="/posts/prompt-to-context-engineering/">从 prompt 到 context engineering 的转变</a>。想分清楚什么时候用桌面端什么时候用 API，<a href="/posts/claude-desktop-vs-code-vs-api/">四个入口怎么选</a>这篇会帮你省很多力气。代码场景深入可以看<a href="/posts/claude-code-vs-cursor-cline/">Claude Code 对比 Cursor/Cline</a>。</p></div>]]>
    </content>
    <id>https://claude.cocoloop.cn/posts/claude-first-time-10-scenarios/</id>
    <link href="https://claude.cocoloop.cn/posts/claude-first-time-10-scenarios/"/>
    <published>2026-04-18T09:48:00.000Z</published>
    <summary>身边朋友开了 Claude 账号之后最常问的问题是&quot;我该拿它干嘛&quot;。这篇我按自己带过十几个新手的经验，把 10 个场景按上手难度从易到难排了一遍，每个都配一个能直接 copy 的短 prompt，中间还穿插了几个我头两周怎么都没搞明白的坑。</summary>
    <title>第一次用 Claude？这 10 个场景我按踩坑顺序排好了</title>
    <updated>2026-04-19T06:15:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Claude 中文知识站</name>
    </author>
    <category term="Prompt 工程" scheme="https://claude.cocoloop.cn/categories/Prompt-%E5%B7%A5%E7%A8%8B/"/>
    <category term="Claude" scheme="https://claude.cocoloop.cn/tags/Claude/"/>
    <category term="Prompt" scheme="https://claude.cocoloop.cn/tags/Prompt/"/>
    <category term="Few-shot" scheme="https://claude.cocoloop.cn/tags/Few-shot/"/>
    <category term="In-context Learning" scheme="https://claude.cocoloop.cn/tags/In-context-Learning/"/>
    <content>
      <![CDATA[<p>前年夏天做过一个电商评论情感分类的项目。客户要求不用微调，只能靠 prompt 解决。我最开始用零样本，就一句”判断下面这条评论是正面、负面还是中性”，跑了 500 条标注数据，准确率 68%。客户皱了皱眉，说能不能再高点。</p><p>我加了 3 条示例进去，升到 81%。再加到 5 条，到 89%。客户说够了够了，上线。</p><p>后来我自己出于好奇，又加到 10 条示例，心想应该能冲到 92%？结果掉回了 85%。</p><p>当时我特别费解。加示例不是应该让模型学得更好吗？为什么到一定程度后会倒退？</p><p>这个问题我花了大半年才摸清楚。这篇就说说我现在怎么定 few-shot 的数量。</p><h2 id="先讲那个倒退曲线"><a href="#先讲那个倒退曲线" class="headerlink" title="先讲那个倒退曲线"></a>先讲那个倒退曲线</h2><p>这事其实有道理的。Few-shot 的本质是”上下文学习”（in-context learning），模型在推理时动态地从你给的例子里提炼模式。但提炼是有极限的——示例太多，会发生两件事：</p><p><strong>第一，示例之间的细微不一致被放大。</strong>你自己写 10 条示例，总有几条风格或边界判断不完全一样。模型会把这些”不一致”也当成信号，结果反而变得犹豫。</p><p><strong>第二，上下文长度增加，对任务本身的注意力被稀释。</strong>尤其在长文档场景下更明显。</p><p>所以 few-shot 不是”越多越好”。是有个甜蜜点，过了就掉头。</p><h2 id="我现在用的-3-5-7-法则"><a href="#我现在用的-3-5-7-法则" class="headerlink" title="我现在用的 3&#x2F;5&#x2F;7 法则"></a>我现在用的 3&#x2F;5&#x2F;7 法则</h2><p>这个法则不是啥标准答案，是我在实际项目里反复校准出来的经验值。不同任务类型，甜蜜点位置不一样：</p><h3 id="3-条：分类任务-风格迁移"><a href="#3-条：分类任务-风格迁移" class="headerlink" title="3 条：分类任务 + 风格迁移"></a>3 条：分类任务 + 风格迁移</h3><p>情感分类、意图识别、打标签、改写成某种特定文风——这类任务的特点是”模式相对简单，但边界需要锚定”。</p><p>3 条示例基本够了。一条典型正例、一条典型负例、一条边界模糊的。这样模型就明白了你的判定规则在哪。</p><p>再多加也没啥用。你加第四条、第五条多半是在重复前三条的模式，对模型来说是冗余信号。</p><h3 id="5-条：结构化抽取"><a href="#5-条：结构化抽取" class="headerlink" title="5 条：结构化抽取"></a>5 条：结构化抽取</h3><p>从长文本里抽字段、从邮件里提关键信息、从合同里找条款——这类任务需要模型学会”看哪里”和”怎么填”。</p><p>5 条示例里我通常这样配：2 条标准样例、2 条包含噪声或歧义的、1 条字段缺失或需要”填 null”的。覆盖主流情况 + 典型异常，再多就多余了。</p><h3 id="7-条：复杂推理-多步决策"><a href="#7-条：复杂推理-多步决策" class="headerlink" title="7 条：复杂推理 &#x2F; 多步决策"></a>7 条：复杂推理 &#x2F; 多步决策</h3><p>比如多跳问答、合规判断（需要组合多条规则）、代码评审这种需要”先看整体再判断细节”的任务。</p><p>7 条示例里，我会确保每条示例的”推理路径”都不一样——不是换输入，是换思考路径。让模型看到”哦原来这类问题可以这么想、也可以那么想”。</p><p>超过 7 条我基本就不加了。要么升级到带 <code>&lt;thinking&gt;</code> 的链式推理（这个在<a href="/posts/prompt-chain-of-thought-vs-direct/">思考还是直接给答案那篇</a>里细说），要么考虑微调或者上更强的模型。</p><h2 id="示例顺序的讲究"><a href="#示例顺序的讲究" class="headerlink" title="示例顺序的讲究"></a>示例顺序的讲究</h2><p>这是个容易被忽略的点。同样 5 条示例，顺序不同效果能差 3-5 个百分点。</p><p>我摸出来的规律：<strong>最相关、最典型的那条放最后。</strong>Claude 的注意力对”刚刚看到的内容”是有偏向的（这事叫 recency bias），放最后的示例在生成时的权重明显更高。</p><p>所以我现在的排法大致是：</p><ol><li>先放几条”覆盖各种情况”的杂样例</li><li>中间放”边界案例”</li><li>最后放一条和当前待处理输入最相似的</li></ol><p>有时候如果我能动态检索，还会做个”相似度召回”，用检索到的最相似 case 作为最后一条示例。这套手法在 RAG 项目里特别好使。</p><h2 id="示例写太好，反而拉低平均"><a href="#示例写太好，反而拉低平均" class="headerlink" title="示例写太好，反而拉低平均"></a>示例写太好，反而拉低平均</h2><p>这点我踩过大坑。</p><p>有次给一个客服改写项目写示例，我特别认真地把每条都润色得又专业又亲切。结果上线一测，发现模型在处理比较随意的用户投诉时，输出也变得很客套很书面——用户反馈说”像在跟机器人讲话”。</p><p>把示例里两条换成稍微”粗糙”一点的真实样本，口吻立刻松下来了，用户满意度反而上去了。</p><p>所以：<strong>示例的质量是”代表性”，不是”完美”。</strong>你的真实输入有多杂，示例就该有多杂。不要把示例全写成你梦里希望的那种理想形态，模型会照着做，然后在处理现实世界输入时别扭得要命。</p><h2 id="输入输出对齐的格式"><a href="#输入输出对齐的格式" class="headerlink" title="输入输出对齐的格式"></a>输入输出对齐的格式</h2><p>Few-shot 的格式写法我建议用 XML 标签成对包装，比 “Q:… A:…” 这种冒号式更稳定。为啥 Claude 特别吃 XML，<a href="/posts/claude-xml-over-markdown/">这篇</a>专门讲过。</p><p>典型写法：</p><div class="code-container" data-rel="Xml"><figure class="iseeu highlight xml"><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></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">example</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">input</span>&gt;</span>用户评论：这破玩意儿用了三天就坏了<span class="tag">&lt;/<span class="name">input</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">output</span>&gt;</span>负面<span class="tag">&lt;/<span class="name">output</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">example</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">example</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">input</span>&gt;</span>用户评论：还行吧，没啥特别感觉<span class="tag">&lt;/<span class="name">input</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">output</span>&gt;</span>中性<span class="tag">&lt;/<span class="name">output</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">example</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">example</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">input</span>&gt;</span>用户评论：冲着品牌买的，用起来确实比便宜货强<span class="tag">&lt;/<span class="name">input</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">output</span>&gt;</span>正面<span class="tag">&lt;/<span class="name">output</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">example</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">task</span>&gt;</span></span><br><span class="line">请判断下面这条评论的情感：</span><br><span class="line">&#123;用户输入&#125;</span><br><span class="line"><span class="tag">&lt;/<span class="name">task</span>&gt;</span></span><br></pre></td></tr></table></figure></div><p>格式统一、标签闭合、最后一条是最典型的。</p><h2 id="0-shot-vs-Few-shot-怎么选"><a href="#0-shot-vs-Few-shot-怎么选" class="headerlink" title="0-shot vs Few-shot 怎么选"></a>0-shot vs Few-shot 怎么选</h2><p>不是所有任务都需要 few-shot。我的判断标准：</p><p><strong>能 0-shot 就 0-shot。</strong>Claude 的 zero-shot 能力本身就很强，简单任务加示例是浪费 token、拖慢响应。</p><p><strong>什么时候需要 few-shot？</strong></p><ul><li>任务有”主观判断”的成分（比如风格分类）</li><li>期望输出有特定格式且不容易用自然语言描述清楚</li><li>边界情况多，光靠规则说不清楚</li><li>你试了 0-shot 结果准确率差 5 个百分点以上</li></ul><p>先 0-shot 测一轮，拿到 baseline，再决定要不要加示例。有些人上来就怼 10 条例子，既浪费 token 也错过了真实性能评估。</p><h2 id="我开头那个-68-→89-到底怎么拆的"><a href="#我开头那个-68-→89-到底怎么拆的" class="headerlink" title="我开头那个 68%→89% 到底怎么拆的"></a>我开头那个 68%→89% 到底怎么拆的</h2><p>回到那个情感分类项目。我当时加示例的具体步骤，给大家看下：</p><ul><li><strong>第 1 条</strong>：一个明显负面但用词委婉的（让模型学会看”言外之意”）</li><li><strong>第 2 条</strong>：一个表面夸实则讽刺的（中文里特别多这种）</li><li><strong>第 3 条</strong>：一个情感混合的，判定为中性（教它怎么处理混合情感）</li><li><strong>第 4 条</strong>：一个带脏话的负面（锚定”脏话≠一定是差评”的边界）</li><li><strong>第 5 条</strong>：和当前测试集分布最接近的一条标准负面</li></ul><p>每加一条都带来 2-5 个点的提升。到第 5 条时覆盖了主要 edge case，再往上加就开始触发前面说的”不一致被放大”现象。</p><h2 id="一些零碎经验"><a href="#一些零碎经验" class="headerlink" title="一些零碎经验"></a>一些零碎经验</h2><ul><li><strong>示例里的输入尽量匿名化。</strong>别写真实用户名、真实公司名，容易让模型”记住”导致偏差。</li><li><strong>输出格式在示例和最终任务里必须一致。</strong>你示例里是一个词，任务要求一段话，模型会精分。</li><li><strong>示例本身也会走 prompt caching。</strong>如果你的示例长期固定，可以让它进缓存，省下不少钱。缓存机制我在<a href="/posts/prompt-caching-deep-guide/">这篇</a>里拆过。</li><li><strong>不同模型的甜蜜点不同。</strong>Haiku 对示例更敏感、可能 7 条都嫌少；Opus 自身推理强、3 条可能就够。<a href="/posts/claude-family-haiku-sonnet-opus/">Claude 家族那篇</a>里有模型选型的讨论。</li></ul><h2 id="最后"><a href="#最后" class="headerlink" title="最后"></a>最后</h2><p>Few-shot 这事说玄乎也玄乎——同样的示例换个顺序都能差好几个点。说朴素也朴素——你给模型看的就是它学到的，你示例写得糙，模型就糙。</p><p>3&#x2F;5&#x2F;7 不是铁律，是个起点。拿这个数字去试，根据你自己的评估集往上调或往下调 1-2 条。这个过程才是 prompt 工程的本体，不是套公式。</p><div class="cta-card" style="margin:32px 0;padding:20px 24px;background:#f0f7ff;border-left:4px solid #0c97fe;border-radius:6px;"><p style="margin:0 0 8px;font-weight:600;color:#1f2937;">延伸阅读</p><p style="margin:0;color:#4b5563;font-size:14px;line-height:1.8;">想把示例放进缓存省钱，看 <a href="/posts/prompt-caching-deep-guide/">Prompt Caching 深度指南</a>。想区分 few-shot 和 CoT 的边界，去 <a href="/posts/prompt-chain-of-thought-vs-direct/">让 Claude 思考还是直接给答案</a>。不同模型对示例数量的敏感度差异，在 <a href="/posts/claude-family-haiku-sonnet-opus/">Claude 家族选型那篇</a>里有讨论。</p></div>]]>
    </content>
    <id>https://claude.cocoloop.cn/posts/prompt-few-shot-design/</id>
    <link href="https://claude.cocoloop.cn/posts/prompt-few-shot-design/"/>
    <published>2026-04-18T08:30:00.000Z</published>
    <summary>做情感分类那个项目，0-shot 准确率 68%，加到 3 条示例升到 81%，5 条到 89%，再加到 10 条反而掉回 85%。这个曲线让我后来定了一套 3/5/7 法则：分类和风格迁移 3 条、抽取任务 5 条、复杂推理 7 条。这篇把我踩过的坑和摸出来的经验全倒出来。</summary>
    <title>Few-shot 示例到底放几条？我的 3/5/7 法则</title>
    <updated>2026-04-19T03:20:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Claude 中文知识站</name>
    </author>
    <category term="入门" scheme="https://claude.cocoloop.cn/categories/%E5%85%A5%E9%97%A8/"/>
    <category term="Claude" scheme="https://claude.cocoloop.cn/tags/Claude/"/>
    <category term="选型" scheme="https://claude.cocoloop.cn/tags/%E9%80%89%E5%9E%8B/"/>
    <category term="Haiku" scheme="https://claude.cocoloop.cn/tags/Haiku/"/>
    <category term="Sonnet" scheme="https://claude.cocoloop.cn/tags/Sonnet/"/>
    <category term="Opus" scheme="https://claude.cocoloop.cn/tags/Opus/"/>
    <content>
      <![CDATA[<p>我上个月账单 2300 多美元，拆开看，Sonnet 4.6 占了 72%，Haiku 4.5 占 19%，Opus 4.7 只占 9%。这个比例跟一年前完全反过来——那会儿我还在迷信 Opus，什么活都往上堆，结果成本打到地板，很多任务 Sonnet 做得一样好。</p><p>这篇就讲讲怎么别犯我去年犯过的错。</p><h2 id="2026-Q2-的真实价格"><a href="#2026-Q2-的真实价格" class="headerlink" title="2026 Q2 的真实价格"></a>2026 Q2 的真实价格</h2><p>先把数字摆出来，按百万 tokens 计：</p><ul><li><strong>Haiku 4.5</strong>：输入 1 美元 &#x2F; 输出 5 美元</li><li><strong>Sonnet 4.6</strong>：输入 3 美元 &#x2F; 输出 15 美元</li><li><strong>Opus 4.7</strong>：输入 15 美元 &#x2F; 输出 75 美元</li></ul><p>注意这里有几个坑，我去年是一个一个踩过的：</p><p><strong>输出永远比输入贵 5 倍</strong>。这意味着如果你让模型写长文，成本主要花在输出上。我帮一个朋友算过，他让 Opus 输出 10 万 tokens 的研报，光一次就是 7.5 美元，一天跑 20 份就是 150 刀，一个月 4500 刀——然后他发现 Sonnet 跑出来的东西他客户根本看不出差别。</p><p><strong>Opus 是 Sonnet 的 5 倍</strong>。不是”稍贵一点”，是 5 倍。这个倍数值不值你得算一下。</p><p><strong>缓存 token 单独计价</strong>，这个很多人不知道，<a href="/posts/prompt-caching-deep-guide/">我专门写过一篇 prompt caching 深度指南</a>，上下文重复度高的场景能省 80% 以上。</p><h2 id="速度实测，不是官方宣传数字"><a href="#速度实测，不是官方宣传数字" class="headerlink" title="速度实测，不是官方宣传数字"></a>速度实测，不是官方宣传数字</h2><p>我在 us-east-1 附近的 VPS 上用同一段 2000 字中文输入做 streaming 压测，20 次取中位数：</p><ul><li><strong>Haiku 4.5</strong>：约 1100 tok&#x2F;s，首字延迟 300ms 左右</li><li><strong>Sonnet 4.6</strong>：约 720 tok&#x2F;s，首字 600ms</li><li><strong>Opus 4.7</strong>：约 230 tok&#x2F;s，首字 1.2s</li></ul><p>Haiku 的 1100 tok&#x2F;s 是什么概念？一个 500 字的中文回答，它 0.5 秒就输出完了，比你眨眼慢一点。这就是为什么我把所有”用户界面里要让人感觉没延迟”的交互都挂 Haiku。</p><p>Opus 的 230 tok&#x2F;s 慢吗？慢，但它做的事一般值得等。我让它分析一份复杂合同，等 8 秒出一段推理清晰的判断，我愿意等。如果同样的活让 Haiku 做，它可能 1 秒给我一段但结论是错的——那就没意义。</p><h2 id="按任务类型的选型决策树"><a href="#按任务类型的选型决策树" class="headerlink" title="按任务类型的选型决策树"></a>按任务类型的选型决策树</h2><p>我自己画了一棵树，给团队新人讲过好多次，大致这样：</p><p><strong>第一问：这个任务错了会怎样？</strong></p><ul><li>错了客户要投诉&#x2F;打官司&#x2F;赔钱 → 直接 Opus，不要省这个钱</li><li>错了我自己修一下就行 → 往下看</li></ul><p><strong>第二问：这个任务每天跑多少次？</strong></p><ul><li>每天 10 万次以上 → 无脑 Haiku，成本压不下来就 run 不起</li><li>每天几十到几千次 → Sonnet</li><li>每天几次到几十次，但每次很重要 → Opus</li></ul><p><strong>第三问：用户在等结果吗？</strong></p><ul><li>用户在界面上盯着进度条 → Haiku 或 Sonnet，不要 Opus</li><li>是后台批处理，用户不等 → 按复杂度选</li></ul><p>这套问下来 90% 情况能定。剩下 10% 是边界案例，比如”每天跑几千次但每次都很重要”，这种我一般会用 <a href="/posts/haiku-router-cost-cutting/">Haiku 路由再向上 fallback 的方案</a>——先让 Haiku 判断难度，难的才交给 Sonnet 或 Opus。</p><h2 id="我自己项目里三档各占多少"><a href="#我自己项目里三档各占多少" class="headerlink" title="我自己项目里三档各占多少"></a>我自己项目里三档各占多少</h2><p>我手里几个活的的比例，给你做参考：</p><p><strong>客服机器人（日均 8 万次对话）</strong>：Haiku 90%，Sonnet 10%（遇到 Haiku 判断不了的升级路由）。Opus 0%，完全用不上。</p><p><strong>合同审查工具（日均 30 份）</strong>：Sonnet 60%，Opus 40%。重要条款和有争议的部分交给 Opus，一般条款 Sonnet 搞定。</p><p><strong><a href="/posts/claude-sonnet-daily-driver/">我用 Sonnet 当日常生产力主力</a>的内容生成管线（日均 200 篇）</strong>：Sonnet 95%，Opus 5%（只有长篇深度文章会用 Opus）。</p><p><strong>内部 RAG 知识库问答（日均 3000 次）</strong>：Haiku 70% 做初筛和简单问答，Sonnet 30% 做复杂推理。</p><p>加起来的综合比例就是我前面说的 Sonnet 72% &#x2F; Haiku 19% &#x2F; Opus 9%。Sonnet 4.6 确实是 2026 年的主力驮马。</p><h2 id="几个我踩过的坑"><a href="#几个我踩过的坑" class="headerlink" title="几个我踩过的坑"></a>几个我踩过的坑</h2><p><strong>坑一：别用 Opus 做简单翻译</strong>。我早期把 Opus 当万能钥匙用，翻译几百字的产品说明都上 Opus，一个月多花 400 多美元。换成 Haiku 之后质量基本没降。</p><p><strong>坑二：别用 Haiku 做多步推理</strong>。去年我图便宜让 Haiku 做一个”读完合同→提取条款→判断风险→输出报告”的四步任务，结果第二步之后的上下文它就开始忘，最后给出的风险判断全是瞎说。这种活交给 Sonnet 稳得多。</p><p><strong>坑三：Opus 不是任何时候都比 Sonnet 强</strong>。在我做过的一批代码审查任务里，Sonnet 4.6 的表现反而比 Opus 4.7 更一致——Opus 偶尔会想得太多，加一堆用户没问的建议。</p><h2 id="最后的建议"><a href="#最后的建议" class="headerlink" title="最后的建议"></a>最后的建议</h2><p>如果你刚上手，别纠结这个选择。先所有任务都丢给 Sonnet 4.6，跑两周看账单和效果。然后把账单里贵的那几个任务挑出来：</p><ul><li>质量够了但太贵 → 降级到 Haiku 试试</li><li>质量明显不够 → 升级到 Opus 试试</li></ul><p>不要一上来就做复杂的路由方案，先用最简单的规则跑顺了再优化。</p><div class="cta-card" style="margin:32px 0;padding:20px 24px;background:#f0f7ff;border-left:4px solid #0c97fe;border-radius:6px;"><p style="margin:0 0 8px;font-weight:600;color:#1f2937;">想系统学 Claude？</p><p style="margin:0;color:#4b5563;font-size:14px;line-height:1.8;">已经选定了模型，下一步可以看<a href="/posts/claude-api-quickstart/">15 分钟跑通第一个 API 请求</a>。要把成本再打下来一半，<a href="/posts/haiku-router-cost-cutting/">Haiku 路由降本实战</a>这篇是我项目里真的在用的方案。把 Sonnet 的日常用法榨干，可以接着看<a href="/posts/claude-sonnet-daily-driver/">Sonnet 日常生产力主力的 20 种用法</a>。</p></div>]]>
    </content>
    <id>https://claude.cocoloop.cn/posts/claude-family-haiku-sonnet-opus/</id>
    <link href="https://claude.cocoloop.cn/posts/claude-family-haiku-sonnet-opus/"/>
    <published>2026-04-18T06:37:00.000Z</published>
    <summary>我在生产环境里把三档 Claude 都跑过，Haiku、Sonnet、Opus 每个月在账单里都占一块。这篇把 2026 Q2 的真实价格、我自己压测的速度、按任务类型选型的决策树一次讲清楚，不是官方文档那种答非所问的对比表。</summary>
    <title>Haiku 4.5、Sonnet 4.6、Opus 4.7 到底怎么选</title>
    <updated>2026-04-19T03:20:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Claude 中文知识站</name>
    </author>
    <category term="Prompt 工程" scheme="https://claude.cocoloop.cn/categories/Prompt-%E5%B7%A5%E7%A8%8B/"/>
    <category term="Claude" scheme="https://claude.cocoloop.cn/tags/Claude/"/>
    <category term="Prompt" scheme="https://claude.cocoloop.cn/tags/Prompt/"/>
    <category term="XML" scheme="https://claude.cocoloop.cn/tags/XML/"/>
    <category term="结构化输入" scheme="https://claude.cocoloop.cn/tags/%E7%BB%93%E6%9E%84%E5%8C%96%E8%BE%93%E5%85%A5/"/>
    <content>
      <![CDATA[<p>去年十月我接了个活儿：从一批医疗器械注册文件里抽取 14 个字段。文件结构乱、术语杂、有中文有英文。我一开始用 markdown 写的 prompt，测完一批，准确率 74%。</p><p>改天心血来潮，把同一个 prompt 的分区从 <code>## 文档内容</code> 改成 <code>&lt;document&gt;...&lt;/document&gt;</code>、<code>## 抽取要求</code> 改成 <code>&lt;instructions&gt;...&lt;/instructions&gt;</code>，其它一个字没动。再跑一遍，准确率 91%。</p><p>17 个百分点。我当时就懵了，以为是哪里串了变量。反复对了三次，确实就是标签的差别。</p><p>从那以后我就开始系统地玩这套东西，到现在差不多大半年。这篇写一下我摸出来的规律。</p><h2 id="这事的历史根源"><a href="#这事的历史根源" class="headerlink" title="这事的历史根源"></a>这事的历史根源</h2><p>先说个不那么技术的背景。Claude 的训练数据里，XML 出现的频率和使用方式跟 GPT 那边不太一样。Anthropic 官方在多份文档里直接推荐用 XML 标签组织 prompt——这不是一个说说而已的”最佳实践”，而是他们从训练阶段就在铺这条路。</p><p>具体表现是：Claude 对成对出现的 <code>&lt;tag&gt;...&lt;/tag&gt;</code> 有非常强的”边界感知”。它会把标签内的内容视为一个语义独立的单元，而不是和周围文字融成一片。</p><p>反观 markdown 标题，<code>## 某某某</code> 只是一个软分界——视觉上清楚，但模型在注意力机制里并没有对它做特别处理。于是你的”文档内容”和”抽取要求”在它眼里可能是一碗汤里的两块肉，有时候分得清有时候分不清。</p><p>这个差别在任务复杂度低的时候不明显。越是长上下文、多段文本、多任务混排的场景，XML 的优势越明显。我那个 14 字段抽取就是典型长文档 + 多目标。</p><h2 id="我实测过的几组对比"><a href="#我实测过的几组对比" class="headerlink" title="我实测过的几组对比"></a>我实测过的几组对比</h2><p>除了开头那个医疗文档，我后来又做了几组对照实验，数据大致是这样：</p><ul><li><strong>短对话（单轮、上下文 &lt;500 字）</strong>：markdown 和 XML 几乎没差，都在 95%+，在误差范围内。</li><li><strong>中等文档抽取（2k-5k 字 + 3-5 个字段）</strong>：XML 普遍高 5-10 个点。</li><li><strong>长文档 + 多段指令（10k+ 字 + 多任务混排）</strong>：XML 优势 15-20 个点，甚至有任务从不可用变成可用。</li><li><strong>RAG 场景（多段检索结果 + 用户问题）</strong>：XML 把”检索内容”和”用户问题”隔开的效果明显，减少了幻觉引用。</li></ul><p>所以不是什么情况都非得用 XML。短任务你爱用啥用啥。我现在的习惯是：<strong>只要 prompt 里有两段以上语义不同的内容块，就上 XML。</strong>一段的就 plain text 算了，别瞎包。</p><p>关于这个话题 <a href="/posts/claude-xml-over-markdown/">XML 和 Markdown 的深度对比那篇</a>有更细的版本对照，我不展开重复。</p><h2 id="标签怎么起名是个学问"><a href="#标签怎么起名是个学问" class="headerlink" title="标签怎么起名是个学问"></a>标签怎么起名是个学问</h2><p>刚开始玩的时候我也犯过错。为了好看，标签名起得很文艺，<code>&lt;gorgeous_article&gt;</code>、<code>&lt;user_question_that_requires_thoughtful_answer&gt;</code>——这种不但没加分还减分。</p><p>摸到的规律是：<strong>标签名要语义化、短、尽量用通用词。</strong></p><p>通用词是指 <code>&lt;document&gt;</code>、<code>&lt;context&gt;</code>、<code>&lt;instructions&gt;</code>、<code>&lt;example&gt;</code>、<code>&lt;input&gt;</code>、<code>&lt;output&gt;</code>、<code>&lt;question&gt;</code>、<code>&lt;answer&gt;</code>、<code>&lt;thinking&gt;</code> 这类。Claude 的训练数据里见得多，它一看到就知道”哦这是文档内容”。</p><p>自创词也不是不能用，但得让标签名本身传达清楚角色。<code>&lt;medical_report&gt;</code> 可以，<code>&lt;the_big_text_blob&gt;</code> 就很差。</p><p>还有一点，<strong>标签名本身就是一种提示。</strong>我做法律项目时试过把 <code>&lt;text&gt;</code> 改成 <code>&lt;contract&gt;</code>，没改其它任何东西，合同里的风险识别率微微上升了一点。模型会根据标签名调整对内部内容的”期待”。</p><h2 id="嵌套别上头"><a href="#嵌套别上头" class="headerlink" title="嵌套别上头"></a>嵌套别上头</h2><p>见过有人把 XML 嵌套玩出六层的。<code>&lt;task&gt;&lt;context&gt;&lt;documents&gt;&lt;document&gt;&lt;metadata&gt;&lt;author&gt;...</code> 这种。</p><p>这么写 Claude 不会报错，但会累。我实测过嵌套超过三层之后，模型对内层标签的”尊重程度”开始下降。三层以内是甜蜜区。</p><p>我现在的原则：<strong>扁平优先，能不嵌套就不嵌套。</strong>需要层级的时候也不超过三层。</p><p>比较健康的一种结构：</p><div class="code-container" data-rel="Xml"><figure class="iseeu highlight xml"><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="tag">&lt;<span class="name">context</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">document</span> <span class="attr">id</span>=<span class="string">&quot;1&quot;</span>&gt;</span>...<span class="tag">&lt;/<span class="name">document</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">document</span> <span class="attr">id</span>=<span class="string">&quot;2&quot;</span>&gt;</span>...<span class="tag">&lt;/<span class="name">document</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">context</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">instructions</span>&gt;</span></span><br><span class="line">...</span><br><span class="line"><span class="tag">&lt;/<span class="name">instructions</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">output_format</span>&gt;</span></span><br><span class="line">...</span><br><span class="line"><span class="tag">&lt;/<span class="name">output_format</span>&gt;</span></span><br></pre></td></tr></table></figure></div><p>三层封顶，每层职责清楚。需要更细的分组，用属性（像上面那个 <code>id=&quot;1&quot;</code>）比继续嵌套好。</p><h2 id="闭合标签不要偷懒"><a href="#闭合标签不要偷懒" class="headerlink" title="闭合标签不要偷懒"></a>闭合标签不要偷懒</h2><p>我见过一些人写到后面懒了，只写 <code>&lt;document&gt;</code> 开标签不写闭合。这个我测过，不严重但确实会有损耗——大概降 2-3 个百分点，尤其是在多段内容的场景。</p><p>Claude 对成对标签的处理是优化过的。你不闭合，它会自己猜边界，猜得多数时候对，有时候不对。不对的那几次就是你损失的精度。</p><p>同理，<code>&lt;tag/&gt;</code> 这种自闭合标签在纯 prompt 场景里我建议少用，没啥必要，还可能引起歧义。</p><h2 id="什么时候-XML-反而拖累"><a href="#什么时候-XML-反而拖累" class="headerlink" title="什么时候 XML 反而拖累"></a>什么时候 XML 反而拖累</h2><p>XML 不是万能药。有些场景它反而碍事：</p><p><strong>一、纯创作任务。</strong>你让它写一首诗、编一个故事，前面包一堆 <code>&lt;poem_topic&gt;</code>、<code>&lt;style_preference&gt;</code>、<code>&lt;length&gt;</code> 标签，会让模型进入”分析模式”，输出反而板正。这种场景 plain text 自然语言就够了。</p><p><strong>二、极短 prompt。</strong>system 里就一句”你是个客服助手”，包个 <code>&lt;role&gt;你是个客服助手&lt;/role&gt;</code> 没意义，反而显得刻意。</p><p><strong>三、需要模型自由展开的头脑风暴。</strong>标签会隐性收紧模型的发散范围。要创意的时候给它松绑。</p><h2 id="Tool-use-的响应里也有-XML-痕迹"><a href="#Tool-use-的响应里也有-XML-痕迹" class="headerlink" title="Tool use 的响应里也有 XML 痕迹"></a>Tool use 的响应里也有 XML 痕迹</h2><p>顺便提一下。你用 Claude 的 tool use（function calling）时会发现，模型在推理阶段倾向用类 XML 的结构组织它的”思路”，最后才调用工具。这不是巧合——它的 thinking 模式就是在 <code>&lt;thinking&gt;...&lt;/thinking&gt;</code> 标签里展开的。</p><p>这也反过来印证了 Claude 训练时 XML 的权重。你要让它”想一下再答”，用 <code>&lt;thinking&gt;</code> 标签比用”让我们一步步来”这种自然语言触发词要稳得多。相关细节我在<a href="/posts/prompt-chain-of-thought-vs-direct/">思考还是直接给答案那篇</a>里有说。</p><p>说到 tool use，它和 MCP 的区别和选型在<a href="/posts/mcp-vs-function-calling/">这篇</a>里有讲，感兴趣可以顺手看看。</p><h2 id="我现在的默认模板"><a href="#我现在的默认模板" class="headerlink" title="我现在的默认模板"></a>我现在的默认模板</h2><p>给一个我个人在中等复杂度任务上的骨架：</p><div class="code-container" data-rel="Xml"><figure class="iseeu highlight xml"><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></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">context</span>&gt;</span></span><br><span class="line">[背景资料、检索结果、文档内容]</span><br><span class="line"><span class="tag">&lt;/<span class="name">context</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">task</span>&gt;</span></span><br><span class="line">[这次要干的事，一两句话说清]</span><br><span class="line"><span class="tag">&lt;/<span class="name">task</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">constraints</span>&gt;</span></span><br><span class="line">- [约束 1]</span><br><span class="line">- [约束 2]</span><br><span class="line"><span class="tag">&lt;/<span class="name">constraints</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">output_format</span>&gt;</span></span><br><span class="line">[期望的输出结构]</span><br><span class="line"><span class="tag">&lt;/<span class="name">output_format</span>&gt;</span></span><br></pre></td></tr></table></figure></div><p>四个块、全闭合、不嵌套。90% 的项目这个骨架够用了。</p><p>最后说一句心里话。XML 这东西在 prompt 工程里被神化过也被踩过，我摸了大半年，结论还是那句：<strong>它不是魔法，是一个让你的意图传达得更准的工具。</strong>你意图本身就乱，再包多少标签都救不回来。但你想法清楚的时候，XML 能帮你把想法”原封不动”地送到模型面前，而不是在路上被稀释掉。</p><div class="cta-card" style="margin:32px 0;padding:20px 24px;background:#f0f7ff;border-left:4px solid #0c97fe;border-radius:6px;"><p style="margin:0 0 8px;font-weight:600;color:#1f2937;">延伸阅读</p><p style="margin:0;color:#4b5563;font-size:14px;line-height:1.8;">想看更全的对照实验数据，看 <a href="/posts/claude-xml-over-markdown/">XML vs Markdown 的深度对比</a>。想理解 system 里怎么和 XML 配合，去 <a href="/posts/prompt-system-role-placement.md">System Prompt 放什么那篇</a>。想把这套结构化输入和 tool use 结合起来，别错过 <a href="/posts/mcp-vs-function-calling/">MCP vs Function Calling</a>。</p></div>]]>
    </content>
    <id>https://claude.cocoloop.cn/posts/prompt-xml-tags-claude-special/</id>
    <link href="https://claude.cocoloop.cn/posts/prompt-xml-tags-claude-special/"/>
    <published>2026-04-18T05:45:00.000Z</published>
    <summary>同一个文档抽取任务，用 markdown 分段我的准确率 74%，换成 XML 标签跑一遍就到了 91%。差距有点吓人，我花了大半年在实际项目里反复验证这个现象，也大概摸清了为什么。这篇说一下 Claude 为什么吃 XML 这口、怎么用才不翻车、哪些是花架子哪些是真功夫。</summary>
    <title>为什么 Claude 特别吃 XML 标签？这是我摸了半年的答案</title>
    <updated>2026-04-19T08:10:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Claude 中文知识站</name>
    </author>
    <category term="Prompt 工程" scheme="https://claude.cocoloop.cn/categories/Prompt-%E5%B7%A5%E7%A8%8B/"/>
    <category term="Claude" scheme="https://claude.cocoloop.cn/tags/Claude/"/>
    <category term="Prompt" scheme="https://claude.cocoloop.cn/tags/Prompt/"/>
    <category term="System Prompt" scheme="https://claude.cocoloop.cn/tags/System-Prompt/"/>
    <category term="结构设计" scheme="https://claude.cocoloop.cn/tags/%E7%BB%93%E6%9E%84%E8%AE%BE%E8%AE%A1/"/>
    <content>
      <![CDATA[<p>上周给一个做法律 AI 的客户 review 线上代码，看到他 system prompt 里塞了足足 850 个字。开头是”你是一个专业、严谨、客观、富有同理心且极其注重细节的法律助手”，后面跟了两段职业操守、三段风格要求，还夹了一条”请确保你的回答准确无误”。</p><p>user 那边呢？就一句：”请帮我分析这份合同的风险点。”然后把合同全文贴上去。</p><p>我看完大概沉默了十秒。这不是一个 prompt，这是一份岗位说明书。</p><h2 id="我先讲一下-system-和-user-的职责边界"><a href="#我先讲一下-system-和-user-的职责边界" class="headerlink" title="我先讲一下 system 和 user 的职责边界"></a>我先讲一下 system 和 user 的职责边界</h2><p>这事其实 Anthropic 在官方文档里讲得挺清楚，但被大部分中文教程带偏了。中文圈子里流行的说法是”system 放人设，user 放问题”，听起来没毛病，但太笼统。</p><p>我现在理解的边界是这样：</p><p><strong>system 管的是”约束”——不管这次来什么请求，这些规则都成立。</strong>比如你是什么角色、不能做什么、输出什么格式、用哪种语气、失败时怎么兜底。这些东西一旦写进 system，Claude 会把它当成整个会话的”重力场”。</p><p><strong>user 管的是”指令”——这一次我具体要你干什么。</strong>输入数据、本次任务目标、这次特殊的限制。</p><p>所以”请确保你的回答准确无误”这种话放 system 是浪费 token。它对所有任务都成立，说了等于没说。Claude 又不会因为你没说就故意瞎编。</p><p>那个客户一开始不服气，说你看 OpenAI 官方示例里也会写”你要准确”。我说那是他们 GPT 的风格，Claude 对这种”空话”敏感度很高，你写多了它反而会把实际约束稀释掉。</p><h2 id="我拆的三层模型"><a href="#我拆的三层模型" class="headerlink" title="我拆的三层模型"></a>我拆的三层模型</h2><p>在他项目上我重写了一版，就砍到 320 字，结构长这样：</p><p>第一层是<strong>身份（Identity）</strong>。两三句说清你是谁、服务谁、核心任务。不要形容词堆叠。”你是一名为中国中小企业服务的合同审阅助手，用户通常是没有法务团队的创业者”——这一句比”专业严谨富有同理心”信息量大十倍。因为它锚定了读者画像。</p><p>第二层是<strong>规则（Rules）</strong>。必须做什么、绝对不能做什么、边界在哪。我一般用无序列表直接列出来，每条不超过 15 字。比如：</p><ul><li>不提供具体诉讼策略</li><li>不引用未经查证的法条编号</li><li>发现高风险条款必须用 <code>&lt;alert&gt;</code> 标签标出</li><li>无法判断时直接说”建议咨询律师”，不要硬答</li></ul><p>这层最怕的是写得像宪法——“应当秉持公正原则”这种话 Claude 看了会礼貌性点头然后该怎么错还怎么错。要具体、要可执行、要像红线。</p><p>第三层是<strong>示例（Examples）</strong>。1-2 个微型 in&#x2F;out 对，展示典型场景的风格和格式。如果你的任务有固定输出结构，这一层几乎是救命的。不过示例别写太长，system 里的示例主要是”锚定风格”，不是”穷举用例”。穷举用例的活儿交给 user 里的 few-shot 做更合适，这个我在<a href="/posts/prompt-few-shot-design/">另一篇讲 few-shot 设计的文章</a>里会细说。</p><h2 id="客户那版为什么会失败"><a href="#客户那版为什么会失败" class="headerlink" title="客户那版为什么会失败"></a>客户那版为什么会失败</h2><p>回头看他原来那 850 字，问题不是”写得不好”，是”层次混乱”。身份、规则、示例、自我吹捧全糊在一块儿。</p><p>Claude 这种大模型处理长 system 的时候，有个我观察到的规律：<strong>越靠前的内容权重越高，越具体的内容越容易被执行，越形容词化的内容越容易被忽略。</strong></p><p>他原 prompt 开头那三行全是形容词，Claude 大致相当于收到一个”请你表现得很牛逼”的模糊信号。到第 400 字左右才出现”不要编造法条”这种硬约束——但这时候注意力已经被稀释了。</p><p>我重写后把身份压到两句、规则上提到前置位、形容词几乎全删。实测在同一批 200 个合同分析 case 上，合格率从 71% 涨到 88%。”合格”的标准是他们自己的 QA 团队打分，不是我定的。</p><h2 id="Claude-到底多”听”system"><a href="#Claude-到底多”听”system" class="headerlink" title="Claude 到底多”听”system"></a>Claude 到底多”听”system</h2><p>这事我顺手测过。同一条硬约束，放 system 里和放 user 里，执行率差多少？</p><p>我拿一个简单规则：”输出必须是 JSON，不要任何解释文字”，跑了 100 次相同的抽取任务。</p><ul><li>只写在 user 里：73 次合规</li><li>只写在 system 里：91 次合规</li><li>两边都写：96 次合规</li></ul><p>差距挺明显的。Claude 对 system 的”服从度”确实更高，这也是为什么我倾向把格式约束、输出结构这类”每次都一样”的东西往 system 放。想稳住 JSON 输出还有一套组合拳，我在<a href="/posts/prompt-output-format-json-schema/">让 Claude 稳定吐 JSON 的 5 个套路</a>里专门写了。</p><p>顺便提一句，如果你在用 <code>CLAUDE.md</code> 做项目级配置，那个文件本质上就是个持久化的 system 增强，相关的写法我在<a href="/posts/claude-md-project-config/">Claude Code 项目配置那篇</a>里有更细的讨论。</p><h2 id="一些容易踩的坑"><a href="#一些容易踩的坑" class="headerlink" title="一些容易踩的坑"></a>一些容易踩的坑</h2><p><strong>坑一：把可能变化的东西写进 system。</strong>比如”今天是 2026 年 4 月 20 日”——明天就过期了。这种应该放 user 或者动态注入。</p><p><strong>坑二：system 里塞大段背景资料。</strong>知识性内容该放 user 或者用 RAG。system 主要承载规则，不是知识库。放多了既浪费缓存命中率，又让模型分心。prompt caching 的机制我在<a href="/posts/prompt-caching-deep-guide/">另一篇深入讲过</a>。</p><p><strong>坑三：用 markdown 标题装饰 system。</strong><code># 身份</code> <code>## 规则</code> 这种写法不是不行，但 Claude 对 XML 标签更敏感，用 <code>&lt;identity&gt;</code> <code>&lt;rules&gt;</code> <code>&lt;examples&gt;</code> 这种语义标签效果更稳。为什么 Claude 特别吃 XML，<a href="/posts/claude-xml-over-markdown/">这篇</a>专门讨论过。</p><p><strong>坑四：规则互相矛盾没察觉。</strong>比如一边说”回答要简洁”一边说”要引用具体法条并解释”。Claude 遇到矛盾约束时倾向挑软的执行，结果就是两头不讨好。写完规则自己过一遍，看有没有打架的。</p><h2 id="我现在的-system-模板"><a href="#我现在的-system-模板" class="headerlink" title="我现在的 system 模板"></a>我现在的 system 模板</h2><p>给一个脱敏后的骨架，你可以照着改：</p><div class="code-container" data-rel="Xml"><figure class="iseeu highlight xml"><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="tag">&lt;<span class="name">identity</span>&gt;</span></span><br><span class="line">你是 [服务对象] 的 [核心角色]，主要帮他们 [核心任务]。</span><br><span class="line"><span class="tag">&lt;/<span class="name">identity</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">rules</span>&gt;</span></span><br><span class="line">- [硬红线 1，越具体越好]</span><br><span class="line">- [硬红线 2]</span><br><span class="line">- [输出格式约束]</span><br><span class="line">- [失败/不确定时的兜底行为]</span><br><span class="line"><span class="tag">&lt;/<span class="name">rules</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">style</span>&gt;</span><span class="language-css"></span></span><br><span class="line"><span class="language-css">- 语气：<span class="selector-attr">[具体到<span class="string">&quot;像资深同事一样&quot;</span>这种]</span></span></span><br><span class="line"><span class="language-css">- 长度：<span class="selector-attr">[默认段落数或字数区间]</span></span></span><br><span class="line"><span class="language-css">- 禁用：<span class="selector-attr">[明确不要的措辞]</span></span></span><br><span class="line"><span class="language-css"></span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">example</span>&gt;</span></span><br><span class="line">输入：...</span><br><span class="line">输出：...</span><br><span class="line"><span class="tag">&lt;/<span class="name">example</span>&gt;</span></span><br></pre></td></tr></table></figure></div><p>基本上 200-400 字解决战斗。想加东西先问自己：”这条规则是不是每次都成立？”不是就挪去 user。</p><p>写 prompt 这事最怕的就是”越写越长、越长越虚”。砍到只剩骨头，反而是最快出效果的办法。</p><div class="cta-card" style="margin:32px 0;padding:20px 24px;background:#f0f7ff;border-left:4px solid #0c97fe;border-radius:6px;"><p style="margin:0 0 8px;font-weight:600;color:#1f2937;">延伸阅读</p><p style="margin:0;color:#4b5563;font-size:14px;line-height:1.8;">想把 Claude 的 XML 能力用到极致，看 <a href="/posts/claude-xml-over-markdown/">为什么 Claude 特别吃 XML 标签</a>。想搞清楚 system 和持久化配置的边界，去 <a href="/posts/claude-md-project-config/">CLAUDE.md 项目配置那篇</a>。要让输出稳定，别错过 <a href="/posts/prompt-output-format-json-schema/">让 Claude 稳定吐 JSON 的 5 个套路</a>。</p></div>]]>
    </content>
    <id>https://claude.cocoloop.cn/posts/prompt-system-role-placement/</id>
    <link href="https://claude.cocoloop.cn/posts/prompt-system-role-placement/"/>
    <published>2026-04-18T02:20:00.000Z</published>
    <summary>上周给一个做法律 AI 的客户 review，看到他 system 里塞了 850 字的&quot;你是一个专业且严谨的助手&quot;，user 里反而只有光秃秃一句问题。我把 system 重写成 320 字分三层，同一批 200 个测试 case 的合格率从 71% 拉到 88%。这篇就说说 system 和 user 到底各自管什么。</summary>
    <title>System Prompt 到底放什么？我把 Anthropic 那套约束拆了三层</title>
    <updated>2026-04-19T06:40:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Claude 中文知识站</name>
    </author>
    <category term="入门" scheme="https://claude.cocoloop.cn/categories/%E5%85%A5%E9%97%A8/"/>
    <category term="Anthropic" scheme="https://claude.cocoloop.cn/tags/Anthropic/"/>
    <category term="Claude" scheme="https://claude.cocoloop.cn/tags/Claude/"/>
    <category term="Constitutional AI" scheme="https://claude.cocoloop.cn/tags/Constitutional-AI/"/>
    <category term="AI 安全" scheme="https://claude.cocoloop.cn/tags/AI-%E5%AE%89%E5%85%A8/"/>
    <content>
      <![CDATA[<p>我第一次知道 Anthropic 这家公司，是 2021 年夏天。那会儿朋友圈有人转过一张图，说 OpenAI 安全团队的核心十几个人集体离职了，领头的是个叫 Dario Amodei 的意大利裔研究员，他妹妹 Daniela 跟他一起走。当时我没在意，觉得不过是硅谷又一次常规的团队分裂。</p><p>后来 ChatGPT 火了，我被推着去试了 GPT-3.5，然后有朋友从内测通道甩给我一个叫 Claude 的东西，让我试试。我记得那天晚上我把同一段写得很烂的需求文档分别喂给两个模型，让它们帮我重写。GPT 给我的东西结构很漂亮但逻辑是飘的，Claude 给我的第一版不好看，但它会主动指出”你第 3 条和第 5 条是矛盾的，我暂时按第 3 条来写了，你确认一下”。</p><p>就那一句话，我记到今天。</p><h2 id="那群人为什么非要从-OpenAI-出来"><a href="#那群人为什么非要从-OpenAI-出来" class="headerlink" title="那群人为什么非要从 OpenAI 出来"></a>那群人为什么非要从 OpenAI 出来</h2><p>Anthropic 的核心创始团队，基本上是 OpenAI 当年负责 GPT-2、GPT-3 研究和安全的那批人。Dario 之前是 OpenAI 的研究 VP，Daniela 管运营，Tom Brown 是 GPT-3 论文一作，Jared Kaplan 是 scaling law 那篇论文的作者之一。</p><p>他们出来的表面原因是”对公司方向有分歧”，但你跟在那个圈子里的人聊过就知道，真实原因没那么玄乎：他们觉得 OpenAI 在安全问题上往后退了，产品化压力越来越大，而他们想做的事——搞清楚”一个能力越来越强的模型，怎么才能持续可控”——在原来那个组织里推不动了。</p><p>所以 Anthropic 一开始不是一家产品公司，是一家研究公司。2021 年成立，头两年几乎没对外发布任何可用的东西，只发论文。这跟 OpenAI 一上来就憋大招搞 GPT-3 API 完全是两种打法。</p><p>顺便说一句，我去年跟一个在 Anthropic SF 办公室的朋友吃饭，他说他们内部开会还是把”Safety”放在产品节奏前面的，这跟外界的印象差不多能对上。</p><h2 id="Constitutional-AI-到底是什么，用白话讲"><a href="#Constitutional-AI-到底是什么，用白话讲" class="headerlink" title="Constitutional AI 到底是什么，用白话讲"></a>Constitutional AI 到底是什么，用白话讲</h2><p>要理解 Claude 跟 GPT 的区别，绕不开 Constitutional AI（简称 CAI）。很多文章讲这玩意讲得云里雾里，我用一个我给非技术客户讲过的比喻：</p><p>RLHF，也就是 OpenAI 训 ChatGPT 那套主流做法，相当于雇了一群人类标注员去打分——模型生成 A 和 B 两个回答，人看完说 A 更好，模型就记住”要像 A 那样”。这种方式的问题在于，人工很贵，而且人会累、会不一致、会有偏见。</p><p>CAI 的做法是：先写一份”宪法”，大概几十条原则（比如”不要帮用户做违法的事””不要输出对特定群体不公平的表述””当你不确定的时候要说不确定”），然后让模型自己拿这份宪法去给自己的回答打分、改写、再打分。人类只在最开始参与，后面大部分工作模型自己循环。</p><p>好处是一致性高、可审计（宪法是明文的）、更便宜。缺点是如果宪法写歪了，模型会一本正经地把错误放大。Anthropic 这几年在改的主要就是这份宪法本身。</p><p>想展开看 Claude 和 GPT、Gemini 各自的路线差异，<a href="/posts/claude-vs-gpt-gemini-2026q2/">我之前写过一篇 2026 Q2 的横向对比</a>，可以接着读。</p><h2 id="Claude-家族这几年怎么长起来的"><a href="#Claude-家族这几年怎么长起来的" class="headerlink" title="Claude 家族这几年怎么长起来的"></a>Claude 家族这几年怎么长起来的</h2><p>我简单捋一下，按我自己用过的版本为准：</p><ul><li><strong>Claude 1（2023 初）</strong>：只在 Slack 里能用，反应慢，但长文本理解明显比当时的 GPT-3.5 好。</li><li><strong>Claude 2（2023 年中）</strong>：开放了 API，上下文窗口做到 100K，我当时拿来啃合同、翻法律文书，第一次感觉”这东西能干活”。</li><li><strong>Claude 3 系列（2024）</strong>：第一次分了 Haiku &#x2F; Sonnet &#x2F; Opus 三档，Opus 3 在推理和写作上当时是拉开同档 GPT 一截的。</li><li><strong>Claude 3.5 &#x2F; 3.7（2024-2025）</strong>：Sonnet 3.5 开始真的好用，Claude Code 也是这一代起步的。</li><li><strong>Claude 4 系列（2025-2026）</strong>：现在线上是 Haiku 4.5、Sonnet 4.6、Opus 4.7。Sonnet 4.6 已经是我日常 80% 任务的主力。</li></ul><p>三档模型怎么选，我在<a href="/posts/claude-family-haiku-sonnet-opus">这篇 Haiku&#x2F;Sonnet&#x2F;Opus 选型笔记</a>里写得很细，这里不重复。</p><h2 id="和-GPT、Gemini-的定位差异"><a href="#和-GPT、Gemini-的定位差异" class="headerlink" title="和 GPT、Gemini 的定位差异"></a>和 GPT、Gemini 的定位差异</h2><p>我尽量不贬低其他家，说几个我自己体感上的区别：</p><p><strong>写长文、处理长文档</strong>：Claude 到现在为止还是我的首选。它在 50K 以上上下文里不容易丢信息，GPT-4 类在这种场景下常常会”中间段失忆”。</p><p><strong>代码</strong>：以前 GPT 更强，2025 年之后 Claude Code + Sonnet 反超了，尤其是改大型代码库、做 refactor 这种活。我现在写代码 90% 用 <a href="/posts/claude-code-vs-cursor-cline">Claude Code 这一套</a>。</p><p><strong>对话自然度</strong>：GPT 的”人味”更足一点，Claude 会稍微一本正经一些。写营销文案我反而会用 GPT 打草稿，再用 Claude 改逻辑。</p><p><strong>安全边界</strong>：Claude 拒答率偏高，有时候你让它帮你写个对某个公司有点批评的分析，它会很谨慎。好处是不容易出事，坏处是有时候挺烦的。</p><p><strong>价格</strong>：Haiku 做到 1 美元&#x2F;百万 tokens 输入，这个价位段 Anthropic 比较卷。</p><p>Gemini 我用得少，主要在 Google Workspace 场景里当插件用，独立用它写东西我没习惯。</p><h2 id="我印象最深的一次对话"><a href="#我印象最深的一次对话" class="headerlink" title="我印象最深的一次对话"></a>我印象最深的一次对话</h2><p>2024 年夏天，我帮一个客户做合同风险审查，把一份 80 页的英文投资协议丢给 Claude 2，让它找出”对乙方明显不利的条款”。</p><p>它没直接列清单，先跟我说了一句：”这份合同里的不利条款有些是显性的（比如第 14.3 条违约金），有些是靠几条互相引用的条款组合出来的陷阱（比如 7.2+11.5+附件 C-3），你想要哪种？”</p><p>我当时愣了一下。那个”组合陷阱”它最后挑出来 3 条，其中 1 条我们的律师团队初审都没发现。</p><p>从那之后我对 Claude 的印象就定下来了——它不是最聪明的，但它是那个”会告诉你它在想什么、不确定的地方会说出来”的模型。我觉得这跟 Constitutional AI 这条技术路线是有关系的，不完全是运气。</p><div class="cta-card" style="margin:32px 0;padding:20px 24px;background:#f0f7ff;border-left:4px solid #0c97fe;border-radius:6px;"><p style="margin:0 0 8px;font-weight:600;color:#1f2937;">想系统学 Claude？</p><p style="margin:0;color:#4b5563;font-size:14px;line-height:1.8;">接下来建议先看<a href="/posts/claude-family-haiku-sonnet-opus/">三档模型怎么选</a>，搞清楚你手里这个任务该调用哪一个。想直接上手 API 的话，<a href="/posts/claude-api-quickstart/">15 分钟跑通第一次请求</a>这篇是我写给完全没碰过的朋友的。横向对比 GPT/Gemini 可以看<a href="/posts/claude-vs-gpt-gemini-2026q2/">2026 Q2 三家对比</a>。</p></div>]]>
    </content>
    <id>https://claude.cocoloop.cn/posts/claude-what-is-anthropic-vs-openai/</id>
    <link href="https://claude.cocoloop.cn/posts/claude-what-is-anthropic-vs-openai/"/>
    <published>2026-04-18T01:12:00.000Z</published>
    <summary>我从 2023 年初开始用 Claude，一路看着它从 Slack bot 里的一个小玩具长成现在 Opus 4.7 这个样子。很多人问我 Claude 到底是什么、跟 GPT 差别在哪、为什么那群人要从 OpenAI 出来单干——今天这篇就按我自己理解的顺序，从头讲到尾。</summary>
    <title>Claude 是什么？从 Anthropic 那群 OpenAI 出走的人说起</title>
    <updated>2026-04-19T02:04:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Claude 中文知识站</name>
    </author>
    <category term="入门介绍" scheme="https://claude.cocoloop.cn/categories/%E5%85%A5%E9%97%A8%E4%BB%8B%E7%BB%8D/"/>
    <category term="选型" scheme="https://claude.cocoloop.cn/tags/%E9%80%89%E5%9E%8B/"/>
    <category term="模型对比" scheme="https://claude.cocoloop.cn/tags/%E6%A8%A1%E5%9E%8B%E5%AF%B9%E6%AF%94/"/>
    <category term="Claude Opus" scheme="https://claude.cocoloop.cn/tags/Claude-Opus/"/>
    <category term="GPT-5" scheme="https://claude.cocoloop.cn/tags/GPT-5/"/>
    <category term="Gemini" scheme="https://claude.cocoloop.cn/tags/Gemini/"/>
    <content>
      <![CDATA[<p>Q2 这三个月我机器上同时挂着三家 API——Anthropic、OpenAI、Google。每次有新项目启动，我都会用这三家分别跑一轮同样的任务，看哪家合适就用哪家做主力，其余两家备着。</p><p>这篇文章不是那种”看完就能做决策”的权威指南——我也做不到，任何说自己能做到的人都是在忽悠你。不同场景、不同预算、不同风险偏好，最优解完全不一样。这里只讲<strong>我自己在 Q2 的真实使用感受</strong>，分六个场景讲，每个场景给一个倾向性选择，最后给一套混搭方案。</p><p>先把三家这季度的旗舰摆出来：</p><ul><li><strong>Claude Opus 4.7</strong>：Anthropic 最新，强在 Agent 和代码</li><li><strong>GPT-5.4</strong>：OpenAI 在多模态和生态上追回来了</li><li><strong>Gemini 3.1 Pro</strong>：Google 的长上下文 + 原生多模态还是最强</li></ul><p>下面按场景拆。</p><h2 id="场景一：写代码"><a href="#场景一：写代码" class="headerlink" title="场景一：写代码"></a>场景一：写代码</h2><p>这个我打得最多——过去三个月三家都让我写过中等复杂度的 Python&#x2F;TypeScript 项目。</p><p><strong>我的倾向：Claude Opus 4.7</strong>（但 Sonnet 4.6 性价比更高）</p><p>理由很简单：<strong>Claude 在”理解现有代码、做克制修改”这件事上依然领先</strong>。GPT-5.4 这一版在代码能力上有明显进步，尤其是复杂算法题，但它骨子里那个”爱自作主张重构”的毛病还在。我测试过一个场景——让三家在一个 3000 行的 repo 里加一个新接口，Claude 改了 4 个文件、GPT 改了 11 个、Gemini 改了 7 个。事后 review，GPT 改动里有 3 处是”顺手优化”和我本意相悖的。</p><p>Gemini 3.1 在代码上追得很快，单文件新代码生成和 Claude 差距不大，但涉及多文件的时候还是吃亏——它的”跨文件一致性”感觉差一层。</p><p>但！<strong>日常写代码别用 Opus</strong>。Sonnet 4.6 已经能覆盖 90% 的代码任务，Opus 贵好几倍但提升有限，除非你在做很复杂的架构设计或者调 bug 调不出来了，否则没必要。这块我在 <a href="/categories/Claude-Code/">Claude-Code 分类</a> 里有更详细的测评。</p><h2 id="场景二：长文档处理"><a href="#场景二：长文档处理" class="headerlink" title="场景二：长文档处理"></a>场景二：长文档处理</h2><p><strong>我的倾向：Gemini 3.1 Pro</strong>（但 Claude 紧咬着）</p><p>Gemini 的 2M token 上下文还是一骑绝尘的。但重点不是”能塞多少”——是它<strong>在长上下文里的召回率</strong>。我做过一个测试：200K 的文档里塞一个无关的”测试句子”，问三家”这段话在哪”。</p><ul><li>Gemini 3.1 Pro：几乎 100% 能找到</li><li>Claude Opus 4.7：200K 范围内 95%+ 召回率，但超过 180K 开始下降</li><li>GPT-5.4：130K 之内不错，超过就明显掉</li></ul><p>但 Gemini 有个问题是<strong>响应速度和稳定性</strong>。2M token 的请求单次要等 30+ 秒，偶尔还会 503。如果你是在线的、对延迟敏感的应用，可能还是 Claude 的 200K 更稳。</p><p>我现在的分工：批量处理大文档（比如审法律合同 PDF）用 Gemini，在线问答 &#x2F; 交互式任务用 Claude。</p><h2 id="场景三：多模态"><a href="#场景三：多模态" class="headerlink" title="场景三：多模态"></a>场景三：多模态</h2><p><strong>我的倾向：GPT-5.4</strong></p><p>这是 OpenAI Q2 追回来的主要领域。GPT-5.4 在图像理解、视频帧解析、音频转录这些任务上综合体验最好。尤其是<strong>图 + 文 + 代码的混合输入</strong>——给它一张 UI 截图加一段代码问”这个按钮对应哪里”，它的定位精度明显优于另外两家。</p><p>Gemini 3.1 的多模态本来有先发优势，但这个季度 GPT 更新之后，优势被抹平了一部分。Gemini 在视频理解上还是最强（能直接吃 1 小时视频做分析），但图像这块 GPT-5.4 开始反超。</p><p>Claude 的图像能力……说实话依然是三家里<strong>最弱的</strong>。Anthropic 这季度有更新，但重点是在 Agent 和代码，多模态优先级不高。给 Claude 一张复杂截图做 OCR + 理解，它做得到，但不如另外两家干脆。</p><h2 id="场景四：推理"><a href="#场景四：推理" class="headerlink" title="场景四：推理"></a>场景四：推理</h2><p><strong>我的倾向：看题型</strong></p><p>这事儿不能一概而论。三家在推理这块各有特长：</p><ul><li><strong>GPT-5.4 o 系列</strong>：数学竞赛题、形式逻辑题、需要”深度思考链”的场景最强。它那个”思考多久给结果”的参数调高之后，复杂题解答质量明显提升</li><li>**Claude Opus 4.7 (thinking mode)**：偏向”工程化推理”——解释代码、分析架构、做技术决策这类任务体验最好。它的思考过程可读性最好，便于 debug</li><li><strong>Gemini 3.1 Pro</strong>：科学推理强，尤其是物理、化学、生物领域。猜测是训练数据里学术内容比例高</li></ul><p>如果你是学生做题、科研人员算东西，GPT 或者 Gemini；如果你是开发者、产品经理做技术决策，Claude 的思考模式更顺手。</p><h2 id="场景五：中文写作"><a href="#场景五：中文写作" class="headerlink" title="场景五：中文写作"></a>场景五：中文写作</h2><p><strong>我的倾向：Claude &gt; GPT &gt; Gemini</strong></p><p>这个话题玄学，不同人感知差别很大，我只说我自己的感觉。</p><p>Claude 系列（Sonnet 4.6 和 Opus 4.7）的中文**最”不翻译腔”**。它写出来的东西有中文原生的节奏感——句子长短错落、转折词用得地道、不会动不动来一句明显是从英文结构翻过来的句子。</p><p>GPT-5.4 的中文比 GPT-4 时代好多了，但仔细看还是有”英文影子”。尤其是写长文章，段落结构偏英式——每段开头一个主题句，后面例证展开。这种结构严谨但不太像中国人写的。</p><p>Gemini 的中文最弱。不是说它错，是**过于”百度百科腔”**——工整、信息量足、但没有温度。让它写个人公众号风格的文章，出来的东西很 AI。</p><p>创意写作（小说、诗词、段子）我自己反而会用 GPT——Claude 太”认真”，不放飞。这是个反直觉的点。</p><h2 id="场景六：Agent-任务"><a href="#场景六：Agent-任务" class="headerlink" title="场景六：Agent 任务"></a>场景六：Agent 任务</h2><p><strong>我的倾向：Claude Opus 4.7</strong></p><p>Agent 这块 Anthropic 是真的下了功夫。Opus 4.7 在<strong>工具调用的稳定性、多步任务的一致性、遇到错误的恢复能力</strong>上都是最好的。</p><p>我做 Agent 项目这一年踩下来，最怕的不是”模型能力不够”，而是”模型在第 20 步突然忘记最初的目标”。Claude 在这个问题上明显比 GPT 和 Gemini 稳——可能是训练时对长程任务做了针对性优化。</p><p>GPT-5.4 做简单 Agent 没问题，但步数一多容易”偏航”。Gemini 的 Agent 能力在快速进步，但目前还不够稳定，我不敢把生产任务交给它。</p><p>如果你在做 Agent 产品，Opus 4.7 值得它的溢价。具体怎么搭 Agent 架构，我在 <a href="/categories/Agent%E5%BC%80%E5%8F%91/">Agent 开发分类</a> 里写过四层架构拆解，感兴趣可以翻。</p><h2 id="最后：我的-70-25-5-三档混搭策略"><a href="#最后：我的-70-25-5-三档混搭策略" class="headerlink" title="最后：我的 70&#x2F;25&#x2F;5 三档混搭策略"></a>最后：我的 70&#x2F;25&#x2F;5 三档混搭策略</h2><p>讲完场景讲策略。我自己现在的混搭比例大概是这样：</p><ul><li><strong>70% 用 Claude</strong>（Sonnet 4.6 为主，Opus 4.7 在关键任务）：日常代码、文档处理、Agent、中文写作</li><li><strong>25% 用 GPT</strong>（GPT-5.4 和 o 系列）：多模态任务、数学 &#x2F; 形式推理、创意写作</li><li><strong>5% 用 Gemini</strong>（3.1 Pro）：超长文档批量处理、视频分析</li></ul><p>这个比例不是算出来的，是一年试下来自然形成的。不同人比例会不一样——如果你主要做图像处理，GPT 占比可能反过来；如果你做学术，Gemini 占比更高。</p><p><strong>为什么要混搭</strong>？两个原因：</p><ol><li>**没有单一模型能”全能最优”**。把所有鸡蛋放一个篮子里，在某个细分场景一定会吃亏</li><li><strong>单家 API 都会偶发挂掉</strong>。我 Q1 就遇到过 Anthropic 全球 1 小时的故障，如果你的生产系统只挂一家，那一小时就完蛋。手里有 3 家 key、路由层做好降级，可用性立刻拉满</li></ol><p>怎么选哪个做主力？简单原则：<strong>把你花时间最多的那个场景对齐到最适合的那家</strong>。如果你 80% 时间在写代码，主力是 Claude；如果 80% 时间做设计分析图，主力是 GPT；如果 80% 时间审长合同，主力是 Gemini。</p><p>模型这事儿半年一变，这篇文章到 Q3 可能就要重写。AI 领域的一手动态我一般刷 <a class="link"   href="https://news.cocoloop.cn/" >news.cocoloop.cn<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>，比看各种推文省事儿，推荐给大家。</p><div class="cta-card">  <div class="cta-title">🚀 想看更多模型选型实战？</div>  <div class="cta-desc">本站持续跟进 Claude 家族最新动态和横向评测。想看完整的 AI 应用案例推荐去 <a class="link"   href="https://www.cocoloop.cn/" >www.cocoloop.cn<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>，模型选型相关问答可以看 <a class="link"   href="https://ask.cocoloop.cn/" >ask.cocoloop.cn<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>。</div></div>]]>
    </content>
    <id>https://claude.cocoloop.cn/posts/claude-vs-gpt-gemini-2026q2/</id>
    <link href="https://claude.cocoloop.cn/posts/claude-vs-gpt-gemini-2026q2/"/>
    <published>2026-04-14T03:00:00.000Z</published>
    <summary>2026 年 Q2 这三家模型都更新了旗舰版。这篇不堆跑分，按六个真实使用场景给倾向性建议：代码、长文档、多模态、推理、中文写作、Agent，最后给一个我自己在用的 70/25/5 三档混合策略。</summary>
    <title>Claude Opus 4.7 vs GPT-5.4 vs Gemini 3.1：2026 Q2 怎么选模型</title>
    <updated>2026-04-19T01:30:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Claude 中文知识站</name>
    </author>
    <category term="Claude-Code" scheme="https://claude.cocoloop.cn/categories/Claude-Code/"/>
    <category term="Claude Code" scheme="https://claude.cocoloop.cn/tags/Claude-Code/"/>
    <category term="CLAUDE.md" scheme="https://claude.cocoloop.cn/tags/CLAUDE-md/"/>
    <category term="配置文件" scheme="https://claude.cocoloop.cn/tags/%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6/"/>
    <category term="最佳实践" scheme="https://claude.cocoloop.cn/tags/%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5/"/>
    <content>
      <![CDATA[<p>第一次用 Claude Code 的时候，我根本不知道 CLAUDE.md 是干啥的。项目根目录莫名其妙多了个文件，我以为是 Claude Code 的缓存，还一度想把它丢进 .gitignore。</p><p>后来在一次协作翻车之后我才意识到这东西有多重要。那次的情况是：我和同事在同一个 repo 里协作，我本地跑 Claude Code 改一个接口改得风生水起，他拉下来跑的时候却发现 Claude Code 一直把代码往完全错误的方向推。排查了俩小时才搞明白——我本地有一份 CLAUDE.md，里面写了一堆项目约定；他没有这份文件（我没 commit），所以他的 Claude 完全不知道这个项目的规矩，只能按通用最佳实践瞎写。</p><p>从那天起我开始认真研究 CLAUDE.md。这东西本质上是给 Claude Code 的<strong>项目说明书</strong>，写得好能让 AI 协作翻倍提效，写得不好能把 AI 带到沟里。这篇把我这半年的经验总结一下。</p><h2 id="一、CLAUDE-md-是什么，为什么重要"><a href="#一、CLAUDE-md-是什么，为什么重要" class="headerlink" title="一、CLAUDE.md 是什么，为什么重要"></a>一、CLAUDE.md 是什么，为什么重要</h2><p>简单说，CLAUDE.md 是 Claude Code 在启动时会自动读入、作为 system context 的一部分注入到模型的文件。它告诉 Claude：</p><ul><li>这个项目用什么技术栈</li><li>代码风格有什么约定</li><li>哪些文件&#x2F;目录不能动</li><li>常用命令是什么（跑测试、部署、lint）</li><li>有什么”坑”要提前知道</li></ul><p><strong>它解决的核心问题是：让 Claude 在一个陌生项目里不再按通用默认行事，而是按这个项目的规矩行事</strong>。</p><p>你可以理解成”给新人入职的 README，只不过读者是 AI”。</p><p>但和 README 有一个关键区别——<strong>README 是可选阅读，CLAUDE.md 是强制注入</strong>。意味着你写进去的每一个字都会消耗 token、都会影响模型行为。这就决定了 CLAUDE.md 不能当 README 写，它必须更精炼、更有指令性。</p><h2 id="二、11-级优先级：从哪读到哪"><a href="#二、11-级优先级：从哪读到哪" class="headerlink" title="二、11 级优先级：从哪读到哪"></a>二、11 级优先级：从哪读到哪</h2><p>这个东西官方文档藏得有点深，我整理一下我理解的顺序（从高到低，高优先级会覆盖低优先级）：</p><ol><li><strong>当前命令的 CLI 参数</strong> —— 最高优先级，临时强制</li><li><strong><code>.claude/settings.local.json</code></strong> —— 本地机器的 Claude 配置（不入 git）</li><li><strong>项目根 <code>CLAUDE.md</code></strong> —— 当前项目规则</li><li>**父目录 <code>CLAUDE.md</code>**（monorepo 场景）</li><li><strong>祖父目录 <code>CLAUDE.md</code></strong> —— 依次往上找到 repo 根或 home</li><li><strong><code>~/.claude/CLAUDE.md</code></strong> —— 用户级全局配置</li><li><strong><code>.claude/settings.json</code></strong> —— 项目共享配置</li><li><strong><code>~/.claude/settings.json</code></strong> —— 用户全局配置  </li><li><strong>环境变量</strong>（如 <code>ANTHROPIC_MODEL</code>）</li><li><strong>Claude Code 内置默认</strong></li><li><strong>模型本身的 default behavior</strong> —— 最底层兜底</li></ol><p>这个顺序不用硬记，但要理解两条核心原则：</p><ul><li><strong>越具体、越靠近当前文件的，优先级越高</strong></li><li><strong>项目级（CLAUDE.md）和用户级（~&#x2F;.claude）会叠加，但冲突时项目级优先</strong></li></ul><p>实际用起来有一个容易忽略的细节——<strong>Claude Code 在启动时会自顶向下把所有层级的 CLAUDE.md 串联起来</strong>，不是只读最近的那一份。这意味着你在子目录里的 CLAUDE.md 不是”覆盖”祖父目录的，而是”追加”。如果祖父目录写了”代码注释用中文”，子目录里不写相关规则，那中文注释规则依然生效。</p><p>这个机制在 monorepo 场景下特别有用。你可以在 repo 根写通用规则（”所有包都用 TypeScript strict 模式”），然后在每个 package 子目录里写各自的特殊规则（”api 包禁止引入 zod 之外的 validation 库”）。</p><h2 id="三、坑-1：写得太多，反而把-Claude-整懵了"><a href="#三、坑-1：写得太多，反而把-Claude-整懵了" class="headerlink" title="三、坑 1：写得太多，反而把 Claude 整懵了"></a>三、坑 1：写得太多，反而把 Claude 整懵了</h2><p>这是我第一个大坑。发现 CLAUDE.md 好用之后，我开始往里面疯狂写东西——项目架构、技术栈细节、每个目录的作用、每个核心函数的职责、过往几次重构的历史……写到快 2000 行。</p><p>然后 Claude Code 开始变得<strong>又慢又飘</strong>。</p><p>原因很简单：<strong>CLAUDE.md 是要完整注入到每次请求的 context 里的</strong>。你写 2000 行，意味着每次 Claude 启动都要消化这 2000 行。问题是：</p><ul><li><strong>信息太多，重点被稀释</strong>。关键规则（比如”不要改 legacy_util.py”）被淹没在一堆描述性内容里</li><li><strong>Token 成本爆炸</strong>。2000 行大概 15K token，每次请求都是这个基础成本</li><li>**模型开始”过度解读”**。写得越多，Claude 越容易从无关内容里脑补奇怪的推论</li><li><strong>维护成本翻倍</strong>。项目演化时，你要同步更新 CLAUDE.md，内容越多越容易遗漏</li></ul><p>我后来把 CLAUDE.md 砍到 150 行以内，执行规则、关键约束、常用命令——其他什么都不写。效果立刻恢复正常，而且 Claude 的判断更稳定了。</p><p><strong>原则：CLAUDE.md 写关键信息，不写全部信息</strong>。详细架构文档放 docs&#x2F; 目录，让 Claude 需要的时候自己去读。你可以在 CLAUDE.md 里留一句：<code>需要深入了解架构时，请先阅读 /docs/architecture.md</code>，把”读不读”的判断权交给模型。</p><p>有人问过我具体怎么判断该不该写进 CLAUDE.md。我的标准是——<strong>如果 Claude 不知道这条规则就有可能写出错误代码，才写进去；如果只是”知道了更好”的背景信息，不写</strong>。这个筛选标准帮我砍掉了 80% 的冗余内容。</p><h2 id="四、坑-2：user-级和项目级配置打架"><a href="#四、坑-2：user-级和项目级配置打架" class="headerlink" title="四、坑 2：user 级和项目级配置打架"></a>四、坑 2：user 级和项目级配置打架</h2><p>第二个坑更隐蔽。</p><p>我在 <code>~/.claude/CLAUDE.md</code> 里写了我个人的偏好——比如”回答我时默认用中文””代码注释用中文””import 顺序按 isort 风格”等等。这是我的个人习惯。</p><p>但有一次我接了一个外包项目，他们的 repo 里有自己的 CLAUDE.md，明确写了”代码注释一律英文”。结果：我本地 Claude 写出来的代码里，注释一会儿中文一会儿英文，完全不统一。</p><p>排查后发现问题是——<strong>两个文件的规则都被注入了</strong>，然后 Claude 自己做了一个折中：”一部分用中文，一部分用英文”。</p><p>解决思路：</p><p>**1. 把 user 级 CLAUDE.md 写成”偏好”而不是”规则”**。<br>用 “我通常更喜欢…” 这种语气，不用 “必须…” 这种硬性措辞。这样项目级规则能比较干净地覆盖它。</p><p><strong>2. 项目级 CLAUDE.md 明确声明优先级</strong>。<br>我现在写项目级 CLAUDE.md 的第一行一般是：</p><div class="code-container" data-rel="Markdown"><figure class="iseeu highlight markdown"><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="section"># 项目规则</span></span><br><span class="line"></span><br><span class="line">本文件中的所有规则优先于 user-level CLAUDE.md。冲突时以本文件为准。</span><br></pre></td></tr></table></figure></div><p>显式写出来，模型会认账。</p><p><strong>3. 真的要强制，用 <code>--override-user-memory</code></strong> 启动参数（这个 flag 从某个版本开始支持，具体版本号我不确定，先试再说）</p><p><strong>4. 做好 user 级配置的定期清理</strong>。<br>我现在每季度会把 <code>~/.claude/CLAUDE.md</code> 重读一遍，删掉那些已经不符合自己当前工作习惯的老规则。这个文件一旦塞多了很容易被遗忘，时间一长就变成各种项目的”通用毒瘤”。</p><p>再补一个小技巧：如果你经常切换不同客户&#x2F;团队的项目，可以在 <code>~/.claude/CLAUDE.md</code> 里完全不写任何强规则，只写自己的<strong>语言偏好</strong>和<strong>沟通风格偏好</strong>。技术决策全部交给项目级 CLAUDE.md 去定，冲突就少了。</p><h2 id="五、坑-3：-include-循环与隐式依赖"><a href="#五、坑-3：-include-循环与隐式依赖" class="headerlink" title="五、坑 3：@include 循环与隐式依赖"></a>五、坑 3：@include 循环与隐式依赖</h2><p>CLAUDE.md 支持 <code>@path/to/file</code> 语法，可以把其他文件的内容拉进来。这玩意儿很强大，但我踩过一个搞笑的坑。</p><p>当时我为了复用，把一些通用规则写在 <code>~/.claude/common.md</code> 里，然后 user 级 CLAUDE.md 里写：</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">@~/.claude/common.md</span><br></pre></td></tr></table></figure></div><p>项目级 CLAUDE.md 里也想复用，又写：</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">@~/.claude/common.md</span><br></pre></td></tr></table></figure></div><p>结果 common.md 被 include 了两次，规则重复。Claude 看到”代码风格 A”出现两次，当作重要信号，反而开始过度强调这个规则。</p><p>更惨的情况是：我有一次 common.md 里 include 了 base.md，base.md 里又 include 了 common.md，形成循环。Claude Code 直接报错启动不了。</p><p><strong>原则：</strong></p><ul><li><strong>@include 要有层级意识</strong>。下游 include 上游，不要互相 include</li><li><strong>不要重复 include 同一个文件</strong></li><li><strong>深层嵌套尽量避免</strong>。一级 include 够用了，两级以上容易出事</li><li><strong>include 进来的内容也要算 token</strong>。有人以为 @include 是懒加载——错了，是 eager 的，启动就全部注入</li></ul><p>一个实用建议：<strong>如果你想做规则复用，与其用 @include，不如用 shell script 在启动时生成 CLAUDE.md</strong>。把”规则碎片库”放在一个统一目录，写一个脚本根据当前项目类型拼装出定制化 CLAUDE.md。这比 @include 的控制力强一个数量级。</p><h2 id="六、一个我实际在用的-CLAUDE-md-模板"><a href="#六、一个我实际在用的-CLAUDE-md-模板" class="headerlink" title="六、一个我实际在用的 CLAUDE.md 模板"></a>六、一个我实际在用的 CLAUDE.md 模板</h2><p>这是我现在大部分 Node &#x2F; TypeScript 项目的骨架：</p><div class="code-container" data-rel="Markdown"><figure class="iseeu highlight markdown"><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></pre></td><td class="code"><pre><span class="line"><span class="section"># [项目名] — CLAUDE.md</span></span><br><span class="line"></span><br><span class="line">本文件优先于 user-level CLAUDE.md。</span><br><span class="line"></span><br><span class="line"><span class="section">## 项目本质</span></span><br><span class="line">一句话说明这个项目是做什么的。</span><br><span class="line"></span><br><span class="line"><span class="section">## 技术栈</span></span><br><span class="line"><span class="bullet">-</span> Runtime: Node 20</span><br><span class="line"><span class="bullet">-</span> Framework: Fastify 5</span><br><span class="line"><span class="bullet">-</span> ORM: Drizzle</span><br><span class="line"><span class="bullet">-</span> Test: Vitest</span><br><span class="line"></span><br><span class="line"><span class="section">## 关键约束</span></span><br><span class="line"><span class="bullet">-</span> 所有对外 API 必须有 zod schema 校验</span><br><span class="line"><span class="bullet">-</span> 禁止引入新的第三方 validation 库（我们用 zod）</span><br><span class="line"><span class="bullet">-</span> 数据库迁移走 drizzle-kit，不手动改 schema</span><br><span class="line"></span><br><span class="line"><span class="section">## 不要改</span></span><br><span class="line"><span class="bullet">-</span> <span class="code">`/src/legacy/`</span> 目录下所有文件（迁移中，容易出事）</span><br><span class="line"><span class="bullet">-</span> <span class="code">`package.json`</span> 里的 node 版本</span><br><span class="line"></span><br><span class="line"><span class="section">## 常用命令</span></span><br><span class="line"><span class="bullet">-</span> 跑测试：<span class="code">`pnpm test`</span></span><br><span class="line"><span class="bullet">-</span> 起开发：<span class="code">`pnpm dev`</span></span><br><span class="line"><span class="bullet">-</span> 数据库迁移：<span class="code">`pnpm db:migrate`</span></span><br><span class="line"></span><br><span class="line"><span class="section">## 风格</span></span><br><span class="line"><span class="bullet">-</span> import 用绝对路径（<span class="code">`@/xxx`</span>）</span><br><span class="line"><span class="bullet">-</span> 错误用 Result 类型，不 throw</span><br><span class="line"><span class="bullet">-</span> 文件名用 kebab-case</span><br><span class="line"></span><br><span class="line"><span class="section">## 遇到不确定的时候</span></span><br><span class="line"><span class="bullet">-</span> 先看 <span class="code">`/docs/architecture.md`</span></span><br><span class="line"><span class="bullet">-</span> 新增 API 前先看 <span class="code">`/src/api/_template.ts`</span></span><br></pre></td></tr></table></figure></div><p>这份大概 50 行左右。不追求完整，追求关键。</p><p>展开一下每个小节的写作原则：</p><ul><li><strong>项目本质</strong>：一句话就够，目的是给 Claude 一个定位锚点</li><li><strong>技术栈</strong>：只列关键版本，不写”为什么选这个”</li><li><strong>关键约束</strong>：写死的红线，违反了一定有问题</li><li><strong>不要改</strong>：负面清单，明确点名</li><li><strong>常用命令</strong>：Claude 要跑测试、lint 时直接复制这些命令，不用猜</li><li><strong>风格</strong>：写 3-5 条最重要的风格偏好，多了反而模糊</li><li><strong>遇到不确定的时候</strong>：告诉 Claude 要去哪看，相当于给它的”自助服务入口”</li></ul><h2 id="七、配合-Claude-Code-的几个小技巧"><a href="#七、配合-Claude-Code-的几个小技巧" class="headerlink" title="七、配合 Claude Code 的几个小技巧"></a>七、配合 Claude Code 的几个小技巧</h2><p><strong>1. 把 CLAUDE.md 放进 git</strong>。<br>这应该是常识但很多人不做。这东西不 commit，团队协作就废了。</p><p><strong>2. 定期 review</strong>。<br>项目演化，CLAUDE.md 也要演化。我每两周会打开 CLAUDE.md 看一眼，删掉已经不适用的规则、补上新的坑。这东西不是一次性写完就完事的。</p><p><strong>3. 新人加入项目时让 Claude 读一遍 CLAUDE.md 做导读</strong>。<br>这招挺好用——直接让 Claude 基于 CLAUDE.md 给新人做一次项目 walkthrough，省了半天时间。</p><p>**4. 结合 <code>.claude/commands/</code>**。<br>把常用的 prompt 做成 slash command，这块和 CLAUDE.md 配合使用效率爆炸。详细玩法我之前在 <a href="/categories/Claude-Code/">Claude-Code 分类</a> 下的几篇文章里讲过。</p><p>**5. 给 CLAUDE.md 加一个”更新日期”**。<br>在文件顶部或底部写一行 <code>最后更新：2026-04-15</code>，Claude 看到会自动把这个时间点作为”当前项目约定的参考线”。老旧 CLAUDE.md 如果没标时间，很容易误导模型。</p><p>**6. 善用 CLAUDE.md 做 Claude 的”行为纠偏”**。<br>如果你发现 Claude 某个行为反复让你不爽（比如老是主动改你没让改的文件），就在 CLAUDE.md 里加一条明确禁止。这个文件不仅是项目说明，也是你和 Claude 之间的”行为协议”。</p><h2 id="八、最后"><a href="#八、最后" class="headerlink" title="八、最后"></a>八、最后</h2><p>CLAUDE.md 这个东西的价值，在于它让 AI 协作<strong>有了项目特化的能力</strong>。通用大模型有它的通用智能，但每个项目有每个项目的土规矩，这些土规矩靠 prompt 临时讲讲讲不完，靠文档让 AI 自己去读效率又低——CLAUDE.md 就是那个<strong>固化土规矩</strong>的载体。</p><p>写好它的核心心法就一句话：<strong>写关键信息，不写全部信息；写规则，不写描述</strong>。</p><p>想看更多 Claude Code 的实战玩法，<a class="link"   href="https://claudecode.cocoloop.cn/" >claudecode.cocoloop.cn<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 是一个专门做深度内容聚合的站点，我平时也会去翻那边的更新；想看国内 AI 工程师社区的讨论可以去 <a class="link"   href="https://ask.cocoloop.cn/" >ask.cocoloop.cn<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 看看。</p><p>再送一个彩蛋——<strong>CLAUDE.md 其实也适合用在非 Claude Code 的场景</strong>。我现在很多个人项目的仓库根目录都放一份 CLAUDE.md，哪怕我暂时不用 Claude Code，只是用网页版 Claude。需要让 AI 理解这个项目时，直接把 CLAUDE.md 内容贴进对话框作为 system prompt 就好了。这个文件正在慢慢变成一种<strong>跨工具的项目元信息标准</strong>。</p><div class="cta-card">  <div class="cta-title">Claude Code 深度玩家都在看</div>  <div class="cta-desc">本站 Claude-Code 板块持续更新实战玩法。想看 Claude Code 专题深度内容，访问 <a class="link"   href="https://claudecode.cocoloop.cn/" >claudecode.cocoloop.cn<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>；想在中文社区里问问题，去 <a class="link"   href="https://ask.cocoloop.cn/" >ask.cocoloop.cn<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>。</div></div>]]>
    </content>
    <id>https://claude.cocoloop.cn/posts/claude-md-project-config/</id>
    <link href="https://claude.cocoloop.cn/posts/claude-md-project-config/"/>
    <published>2026-04-08T07:50:00.000Z</published>
    <summary>CLAUDE.md 是 Claude Code 的项目级配置，一共有 11 层优先级。我从完全不写到瞎堆一气到终于写对，踩过三个大坑：配置过载、user 级冲突、@include 循环。这篇给模板和避坑指南。</summary>
    <title>CLAUDE.md 写法大全：11 级优先级与我踩过的三个大坑</title>
    <updated>2026-04-17T02:05:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Claude 中文知识站</name>
    </author>
    <category term="Agent开发" scheme="https://claude.cocoloop.cn/categories/Agent%E5%BC%80%E5%8F%91/"/>
    <category term="Agent SDK" scheme="https://claude.cocoloop.cn/tags/Agent-SDK/"/>
    <category term="架构" scheme="https://claude.cocoloop.cn/tags/%E6%9E%B6%E6%9E%84/"/>
    <category term="Anthropic" scheme="https://claude.cocoloop.cn/tags/Anthropic/"/>
    <category term="生产实践" scheme="https://claude.cocoloop.cn/tags/%E7%94%9F%E4%BA%A7%E5%AE%9E%E8%B7%B5/"/>
    <content>
      <![CDATA[<p>三月底的时候 Anthropic 悄悄发了一版 Agent SDK 1.4，配套文档里第一次把”四层架构”写进去了。之前大家做 Agent 基本都是野路子——谁有经验谁按自己理解搞，抽象到底该切几刀、每刀切在哪儿，全凭个人品味。</p><p>我过去一年接过三四个 Agent 项目，踩过的架构坑可太多了。有个项目一开始把工具调用、Prompt 组装、状态管理全塞在一个类里，改到第三个功能的时候那个类已经 2000 多行，谁都不敢动。后来我照着 Agent SDK 的思路重构，砍到四个模块，才算活过来。</p><p>这篇文章把 Agent SDK 官方的四层架构拆开讲，每一层我尽量给出<strong>接口是什么样</strong>、<strong>扩展点在哪里</strong>、<strong>生产上怎么用</strong>。如果你正在从零搭一个 Agent，这套骨架可以直接抄。</p><h2 id="架构总览：四层是哪四层"><a href="#架构总览：四层是哪四层" class="headerlink" title="架构总览：四层是哪四层"></a>架构总览：四层是哪四层</h2><p>简单说就是：</p><ol><li><strong>应用层（Application）</strong>：用户意图、任务定义、UI 对接</li><li><strong>Agent 层（Agent）</strong>：规划、工具选择、对话管理</li><li><strong>运行时（Runtime）</strong>：执行循环、重试、超时、熔断</li><li><strong>服务层（Service）</strong>：模型 API、工具实现、持久化</li></ol><p>每一层对下层依赖、对上层提供接口，之间用清晰的数据结构交互。下面挨个拆。</p><h2 id="一、应用层：把”用户要什么”翻译成”Agent-能处理什么”"><a href="#一、应用层：把”用户要什么”翻译成”Agent-能处理什么”" class="headerlink" title="一、应用层：把”用户要什么”翻译成”Agent 能处理什么”"></a>一、应用层：把”用户要什么”翻译成”Agent 能处理什么”</h2><p>这一层最容易被忽视，因为它看起来”没什么技术含量”。但我踩坑最多的就是这里。</p><p>应用层的核心职责是<strong>任务定义</strong>——把用户的模糊需求翻译成 Agent 能吃的结构化输入。比如用户说”帮我把这个项目重构一下”，这在 Agent 眼里是完全不可执行的。应用层要做的是：</p><ol><li>识别意图（重构）</li><li>约束范围（哪些文件？哪些不能动？）</li><li>定义成功标准（测试全过？性能不降？代码行数减少？）</li><li>配置资源上限（最多跑多久？最多多少次 LLM 调用？）</li></ol><p>实际代码里一般长这样：</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> anthropic_agent_sdk <span class="keyword">import</span> TaskSpec, ResourceBudget</span><br><span class="line"></span><br><span class="line">task = TaskSpec(</span><br><span class="line">    intent=<span class="string">&quot;refactor_module&quot;</span>,</span><br><span class="line">    scope=&#123;</span><br><span class="line">        <span class="string">&quot;target_files&quot;</span>: [<span class="string">&quot;src/payment/*.py&quot;</span>],</span><br><span class="line">        <span class="string">&quot;excluded_files&quot;</span>: [<span class="string">&quot;src/payment/legacy_bridge.py&quot;</span>],</span><br><span class="line">    &#125;,</span><br><span class="line">    success_criteria=[</span><br><span class="line">        <span class="string">&quot;pytest tests/payment passes&quot;</span>,</span><br><span class="line">        <span class="string">&quot;line_count_delta &lt;= 0&quot;</span>,</span><br><span class="line">    ],</span><br><span class="line">    budget=ResourceBudget(</span><br><span class="line">        max_llm_calls=<span class="number">50</span>,</span><br><span class="line">        max_duration_seconds=<span class="number">1800</span>,</span><br><span class="line">        max_tokens=<span class="number">1_000_000</span>,</span><br><span class="line">    ),</span><br><span class="line">)</span><br></pre></td></tr></table></figure></div><p>应用层的关键扩展点是<strong>意图分类器</strong>和<strong>成功判定器</strong>。意图分类器可以是一个小模型（Haiku 非常合适）做路由，不同意图走不同的 Agent 配置。成功判定器可以是纯代码（比如跑一下测试）、也可以是 LLM 自己判（LLM-as-judge）。</p><p>我的建议是：<strong>能用代码判的绝对不要用 LLM 判</strong>。LLM-as-judge 看起来灵活，但不稳定、还费钱。</p><h2 id="二、Agent-层：规划、选工具、记状态"><a href="#二、Agent-层：规划、选工具、记状态" class="headerlink" title="二、Agent 层：规划、选工具、记状态"></a>二、Agent 层：规划、选工具、记状态</h2><p>这是大家最熟的一层，但也是最容易写烂的一层。Agent 层对外只有一个核心接口：</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><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="keyword">class</span> <span class="title class_">Agent</span>:</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">run</span>(<span class="params">self, task: TaskSpec</span>) -&gt; TaskResult:</span><br><span class="line">        ...</span><br></pre></td></tr></table></figure></div><p>它内部要做三件事：</p><p><strong>1. Planning（规划）</strong></p><p>拿到 task 之后，Agent 要先产出一个执行计划。Agent SDK 官方推荐的是<strong>分层规划</strong>——先出一个 high-level plan（3-5 步），每一步再在运行时动态展开成具体的子任务。</p><p>这比”一步到位画详细计划”好太多了。我之前试过让 Claude 一次性产出 50 步的详细计划，结果前 5 步执行完之后，环境已经和它最初假设的完全不一样了，后面 45 步全白搭。分层规划让 Agent 每次只需要对下一步做细节规划，灵活性高很多。</p><p><strong>2. 工具选择</strong></p><p>SDK 1.4 里引入了 <code>ToolPicker</code> 抽象。它的作用是：当你注册了 50 个工具的时候，不要把这 50 个工具的描述全塞进 prompt——那样既浪费 token 又会让模型 confused。ToolPicker 会根据当前任务阶段只暴露相关工具。</p><p>简化版长这样：</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><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="keyword">class</span> <span class="title class_">ContextAwareToolPicker</span>:</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">pick</span>(<span class="params">self, task_context</span>):</span><br><span class="line">        <span class="keyword">if</span> task_context.phase == <span class="string">&quot;exploration&quot;</span>:</span><br><span class="line">            <span class="keyword">return</span> [<span class="variable language_">self</span>.tools[<span class="string">&quot;read_file&quot;</span>], <span class="variable language_">self</span>.tools[<span class="string">&quot;grep&quot;</span>]]</span><br><span class="line">        <span class="keyword">if</span> task_context.phase == <span class="string">&quot;modification&quot;</span>:</span><br><span class="line">            <span class="keyword">return</span> [<span class="variable language_">self</span>.tools[<span class="string">&quot;edit&quot;</span>], <span class="variable language_">self</span>.tools[<span class="string">&quot;write&quot;</span>]]</span><br><span class="line">        <span class="keyword">if</span> task_context.phase == <span class="string">&quot;verification&quot;</span>:</span><br><span class="line">            <span class="keyword">return</span> [<span class="variable language_">self</span>.tools[<span class="string">&quot;run_tests&quot;</span>], <span class="variable language_">self</span>.tools[<span class="string">&quot;read_file&quot;</span>]]</span><br></pre></td></tr></table></figure></div><p><strong>3. 状态管理</strong></p><p>Agent 的状态不只是对话历史。完整的状态应该包括：</p><ul><li>已读取的文件及其内容快照（避免重复读）</li><li>已做的修改列表（方便回滚）</li><li>已失败的尝试（避免重复犯错）</li><li>资源消耗计数（token、时间、API 调用数）</li></ul><p>这一层也是 Prompt Caching 落地的主战场。你可以设计成<strong>前面是不变的 system prompt + 任务定义 + 工具定义，后面是动态变化的对话历史</strong>，在”系统+任务+工具”的末尾打一个 cache_control，就能把最大的静态部分缓存起来。我在之前讲 <a href="/categories/%E6%88%90%E6%9C%AC%E4%BC%98%E5%8C%96/">成本优化</a> 的时候详细写过这招。</p><h2 id="三、运行时：核心循环-生产韧性"><a href="#三、运行时：核心循环-生产韧性" class="headerlink" title="三、运行时：核心循环 + 生产韧性"></a>三、运行时：核心循环 + 生产韧性</h2><p>运行时是 Agent SDK 最”工程化”的一层。它不懂业务，只做三件事：<strong>跑循环、处理错误、管资源</strong>。</p><p>核心循环是这样的伪代码：</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">while</span> <span class="keyword">not</span> task.is_done() <span class="keyword">and</span> budget.has_remaining():</span><br><span class="line">    <span class="comment"># 1. 收集上下文</span></span><br><span class="line">    context = agent.gather_context(task, state)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 2. 执行（模型调用或工具调用）</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        step_result = agent.execute(context)</span><br><span class="line">    <span class="keyword">except</span> TransientError <span class="keyword">as</span> e:</span><br><span class="line">        retry(e)</span><br><span class="line">        <span class="keyword">continue</span></span><br><span class="line">    <span class="keyword">except</span> FatalError <span class="keyword">as</span> e:</span><br><span class="line">        <span class="keyword">return</span> TaskResult.failed(e)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 3. 验证</span></span><br><span class="line">    verification = verify(step_result, task.success_criteria)</span><br><span class="line">    state.update(step_result, verification)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> verification.passed:</span><br><span class="line">        <span class="keyword">return</span> TaskResult.success(state)</span><br></pre></td></tr></table></figure></div><p>三个阶段——<strong>收集上下文 → 执行 → 验证</strong>——这是 Agent SDK 官方文档反复强调的核心循环。我实操下来最大的心得是：**”验证”这一步绝对不能省**。</p><p>很多人写 Agent 就是”让模型说它做完了就算完了”。这是灾难。模型经常”幻觉性完成”——它告诉你测试过了，实际上它根本没跑测试。必须在 runtime 里显式验证。</p><h3 id="熔断和指数退避的落地"><a href="#熔断和指数退避的落地" class="headerlink" title="熔断和指数退避的落地"></a>熔断和指数退避的落地</h3><p>生产环境最容易出问题的是两种情况：</p><ul><li><strong>API 间歇性故障</strong>：模型服务偶发 5xx、429</li><li><strong>Agent 陷入死循环</strong>：同一个错误反复试</li></ul><p>熔断器（Circuit Breaker）解决第一种。简化实现：</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><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"><span class="keyword">class</span> <span class="title class_">CircuitBreaker</span>:</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, failure_threshold=<span class="number">5</span>, reset_timeout=<span class="number">60</span></span>):</span><br><span class="line">        <span class="variable language_">self</span>.failures = <span class="number">0</span></span><br><span class="line">        <span class="variable language_">self</span>.threshold = failure_threshold</span><br><span class="line">        <span class="variable language_">self</span>.reset_timeout = reset_timeout</span><br><span class="line">        <span class="variable language_">self</span>.state = <span class="string">&quot;CLOSED&quot;</span></span><br><span class="line">        <span class="variable language_">self</span>.opened_at = <span class="literal">None</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">call</span>(<span class="params">self, fn, *args, **kwargs</span>):</span><br><span class="line">        <span class="keyword">if</span> <span class="variable language_">self</span>.state == <span class="string">&quot;OPEN&quot;</span>:</span><br><span class="line">            <span class="keyword">if</span> time.time() - <span class="variable language_">self</span>.opened_at &gt; <span class="variable language_">self</span>.reset_timeout:</span><br><span class="line">                <span class="variable language_">self</span>.state = <span class="string">&quot;HALF_OPEN&quot;</span></span><br><span class="line">            <span class="keyword">else</span>:</span><br><span class="line">                <span class="keyword">raise</span> CircuitOpenError()</span><br><span class="line"></span><br><span class="line">        <span class="keyword">try</span>:</span><br><span class="line">            result = fn(*args, **kwargs)</span><br><span class="line">            <span class="keyword">if</span> <span class="variable language_">self</span>.state == <span class="string">&quot;HALF_OPEN&quot;</span>:</span><br><span class="line">                <span class="variable language_">self</span>.state = <span class="string">&quot;CLOSED&quot;</span></span><br><span class="line">                <span class="variable language_">self</span>.failures = <span class="number">0</span></span><br><span class="line">            <span class="keyword">return</span> result</span><br><span class="line">        <span class="keyword">except</span> Exception:</span><br><span class="line">            <span class="variable language_">self</span>.failures += <span class="number">1</span></span><br><span class="line">            <span class="keyword">if</span> <span class="variable language_">self</span>.failures &gt;= <span class="variable language_">self</span>.threshold:</span><br><span class="line">                <span class="variable language_">self</span>.state = <span class="string">&quot;OPEN&quot;</span></span><br><span class="line">                <span class="variable language_">self</span>.opened_at = time.time()</span><br><span class="line">            <span class="keyword">raise</span></span><br></pre></td></tr></table></figure></div><p>指数退避配合 jitter 解决重试风暴：</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><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="keyword">def</span> <span class="title function_">backoff_with_jitter</span>(<span class="params">attempt, base=<span class="number">1</span>, max_delay=<span class="number">60</span></span>):</span><br><span class="line">    delay = <span class="built_in">min</span>(base * (<span class="number">2</span> ** attempt), max_delay)</span><br><span class="line">    jitter = random.uniform(<span class="number">0</span>, delay * <span class="number">0.3</span>)</span><br><span class="line">    <span class="keyword">return</span> delay + jitter</span><br></pre></td></tr></table></figure></div><p>我现在的生产配置一般是：熔断阈值 5 次、重置 60 秒；重试最多 3 次、base 1 秒、max 30 秒。这个参数在我跑的几个项目上稳定了半年没出过事。</p><h3 id="死循环检测"><a href="#死循环检测" class="headerlink" title="死循环检测"></a>死循环检测</h3><p>Agent 陷死循环的特征是<strong>连续 N 步的 action 和 state 没有实质变化</strong>。简单做法是对每步的 action hash，如果相邻 3 步 hash 一样（或者语义相似度 &gt; 0.95），就强制打断让 Agent 换思路。更彻底的做法是 runtime 里带一个 “review loop”——每 10 步停下来反思”我们在朝目标推进吗”，如果判断没进展就 abort。</p><h2 id="四、服务层：模型、工具、持久化"><a href="#四、服务层：模型、工具、持久化" class="headerlink" title="四、服务层：模型、工具、持久化"></a>四、服务层：模型、工具、持久化</h2><p>服务层负责对接外部——LLM API、数据库、第三方工具。这一层的设计原则是<strong>可替换</strong>。</p><p>以模型为例，服务层暴露一个接口：</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><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="keyword">class</span> <span class="title class_">ModelProvider</span>(<span class="title class_ inherited__">Protocol</span>):</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">complete</span>(<span class="params">self, messages, tools, **kwargs</span>) -&gt; ModelResponse: ...</span><br></pre></td></tr></table></figure></div><p>然后可以有 <code>AnthropicProvider</code>、<code>RouterProvider</code>（同时挂多个模型、按场景路由）、<code>MockProvider</code>（测试用）。上层完全不知道下面是哪家。</p><p>我的 RouterProvider 实现里一般会挂两个策略：</p><ul><li><strong>按任务难度路由</strong>：简单任务 Haiku、中等 Sonnet、复杂 Opus</li><li><strong>按失败降级</strong>：Opus 失败自动降到 Sonnet，Sonnet 再失败降到 Haiku</li></ul><p>这种混搭可以把成本控制在一个相对稳定的区间。生产上我跑的 Agent 平均成本比”纯 Opus”低 60%，比”纯 Sonnet”还能再低 15-20%。</p><p>工具这一层也要注意——<strong>工具的实现和声明要分离</strong>。工具声明（名字、参数、描述）给 LLM 看；工具实现（实际代码）是服务层的职责。这样你可以在不同环境下用不同实现（开发环境用 mock、生产用真实 API），声明完全不变。</p><p>持久化我不展开了，Agent SDK 给了一个 <code>StateStore</code> 抽象接口，你可以接 Redis、Postgres、甚至本地 SQLite。核心是<strong>能随时把 Agent 的完整状态 dump 出来</strong>，出问题能复现。</p><h2 id="写在最后"><a href="#写在最后" class="headerlink" title="写在最后"></a>写在最后</h2><p>四层架构听起来工程味很重，但实际跑起来你会发现<strong>它省下的时间远大于额外的抽象成本</strong>。一个没分层的 Agent 遇到 bug，你得在两千行代码里大海捞针；一个分好层的 Agent，bug 的位置基本一眼能看出在哪层。</p><p>Agent SDK 现在还在快速演进，但四层这个骨架我觉得短期不会变。如果你在做 Agent 相关项目，<a class="link"   href="https://openclaw.cocoloop.cn/" >openclaw.cocoloop.cn<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 上有一些开源实现可以参考，源码读下来很能启发架构思考。</p><p>最后给一个建议：**不要上来就追求”完美架构”**。第一版能跑就行，跑起来之后按痛点重构——哪一层经常要改，就说明那一层的抽象没做好，用痛点来驱动架构演进，比纸上谈兵画图靠谱得多。</p><div class="cta-card">  <div class="cta-title">🚀 想系统学 Agent 开发？</div>  <div class="cta-desc">本站持续更新 Agent 架构和最佳实践。更多 Agent 框架实战可以看 <a class="link"   href="https://openclaw.cocoloop.cn/" >openclaw.cocoloop.cn<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>，开发者踩坑问答推荐 <a class="link"   href="https://ask.cocoloop.cn/" >ask.cocoloop.cn<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>。</div></div>]]>
    </content>
    <id>https://claude.cocoloop.cn/posts/agent-sdk-architecture/</id>
    <link href="https://claude.cocoloop.cn/posts/agent-sdk-architecture/"/>
    <published>2026-04-08T07:45:00.000Z</published>
    <summary>Claude Agent SDK 最近更新把架构图彻底清晰化了。这篇把四层架构从应用层到服务层拆开讲，每一层的职责、接口、扩展点都给出可直接参考的例子，顺带讲讲生产环境里的熔断和指数退避怎么落地。</summary>
    <title>Claude Agent SDK 四层架构拆解：官方最佳实践到底长什么样</title>
    <updated>2026-04-18T02:10:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Claude 中文知识站</name>
    </author>
    <category term="Tool与MCP" scheme="https://claude.cocoloop.cn/categories/Tool%E4%B8%8EMCP/"/>
    <category term="MCP" scheme="https://claude.cocoloop.cn/tags/MCP/"/>
    <category term="Function Calling" scheme="https://claude.cocoloop.cn/tags/Function-Calling/"/>
    <category term="Agent架构" scheme="https://claude.cocoloop.cn/tags/Agent%E6%9E%B6%E6%9E%84/"/>
    <category term="协议" scheme="https://claude.cocoloop.cn/tags/%E5%8D%8F%E8%AE%AE/"/>
    <content>
      <![CDATA[<p>前两周我跟一个做 Agent 产品的朋友吃饭，他甩给我一句话：”MCP 不就是 Function Calling 换了个皮吗？我们已经有 tool use 了，整这个 MCP 协议是 Anthropic 在刷存在感吧。”</p><p>我当时嘴里正嚼着东西，差点呛住。这误解在开发者圈里太常见了，甚至连一些写过相关代码的人也会这么觉得。但如果你真的在生产环境里把两种方式都用过，就会明白它们差的不是一点半点——<strong>维度根本不一样</strong>。</p><p>Function Calling 是工具；MCP 是给工具定一个标准插口。你可以说螺丝刀和螺丝的规范是一回事吗？当然不是。</p><p>这篇我想把五个最本质的差异一条一条拆给你看，最后说说实际项目选型怎么想。</p><h2 id="差异一：协议层-vs-应用层"><a href="#差异一：协议层-vs-应用层" class="headerlink" title="差异一：协议层 vs 应用层"></a>差异一：协议层 vs 应用层</h2><p>这是最根本的一条，想通了这一点其它四条都顺了。</p><p>Function Calling 是 OpenAI 2023 年 6 月发的一个 API 特性，它的本质是：<strong>模型输出结构化 JSON，你的应用代码去执行</strong>。Anthropic、Google、阿里、智谱……现在都有自己的 tool use &#x2F; function calling API，但注意——<strong>这是每一家自己 API 里的一个功能</strong>。你的代码和 xx 家模型的 API 深度耦合。</p><p>MCP（Model Context Protocol）不一样。它是 Anthropic 2024 年 11 月开源出来的一个<strong>通信协议</strong>，基于 JSON-RPC 2.0，规定了 Client 和 Server 之间怎么发现工具、怎么调用工具、怎么传递上下文、怎么处理流式响应。它本身<strong>不绑定任何模型、任何厂商</strong>。</p><p>打个比方：</p><ul><li>Function Calling 像每个品牌充电器的私有接口。苹果 lightning、华为 Type-C 以前的自家协议、早期安卓的 micro USB——每家自己一套</li><li>MCP 像 USB-C。协议标准化之后，任何设备对任何设备都能用</li></ul><p>USB-C 这个比喻最早是 Anthropic 官方自己提的，我一开始觉得有营销味，用多了之后发现还挺贴切。</p><h2 id="差异二：有状态-vs-无状态"><a href="#差异二：有状态-vs-无状态" class="headerlink" title="差异二：有状态 vs 无状态"></a>差异二：有状态 vs 无状态</h2><p>Function Calling 是一次性交易。你给模型一个 tools 数组，模型决定调哪个、给你返回 JSON，你执行完把结果再塞回对话。<strong>工具本身没有”会话”概念</strong>，每次调用都是独立的。</p><p>MCP Server 是一个<strong>长连接的服务</strong>。它可以：</p><ul><li>维护一个数据库连接池，整个会话期间复用</li><li>缓存用户身份信息，不用每次鉴权</li><li>推送 <code>notifications/resources/updated</code> 告诉客户端”我这边的资源变了”</li><li>在多次调用之间保持工作目录、临时文件这些状态</li></ul><p>举个最实际的例子：你要做一个”代码仓库分析”工具，让 Claude 能读取项目结构、打开文件、跑测试。</p><ul><li>Function Calling 版本：每次调用 <code>read_file</code> 都要把完整路径当参数传进去，模型要自己记住当前在哪个仓库</li><li>MCP 版本：Server 启动时 <code>cd</code> 到仓库根目录，之后所有调用都是相对路径；Server 还可以主动推送”文件变更”事件让模型知道有新的 commit</li></ul><p><strong>这个差异在 Agent 长时任务里会被放大</strong>。任务跑 30 分钟、跨越 200 轮对话，有状态和无状态是两种完全不同的编程模型。</p><h2 id="差异三：可发现-vs-硬编码"><a href="#差异三：可发现-vs-硬编码" class="headerlink" title="差异三：可发现 vs 硬编码"></a>差异三：可发现 vs 硬编码</h2><p>你有没有写过这种代码：</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><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">tools = [</span><br><span class="line">    &#123;<span class="string">&quot;name&quot;</span>: <span class="string">&quot;search_web&quot;</span>, <span class="string">&quot;description&quot;</span>: <span class="string">&quot;...&quot;</span>, <span class="string">&quot;parameters&quot;</span>: &#123;...&#125;&#125;,</span><br><span class="line">    &#123;<span class="string">&quot;name&quot;</span>: <span class="string">&quot;send_email&quot;</span>, <span class="string">&quot;description&quot;</span>: <span class="string">&quot;...&quot;</span>, <span class="string">&quot;parameters&quot;</span>: &#123;...&#125;&#125;,</span><br><span class="line">    &#123;<span class="string">&quot;name&quot;</span>: <span class="string">&quot;query_db&quot;</span>, <span class="string">&quot;description&quot;</span>: <span class="string">&quot;...&quot;</span>, <span class="string">&quot;parameters&quot;</span>: &#123;...&#125;&#125;,</span><br><span class="line">]</span><br><span class="line">response = client.messages.create(tools=tools, ...)</span><br></pre></td></tr></table></figure></div><p>这就是 Function Calling 的典型写法——<strong>工具列表写死在客户端代码里</strong>。你想加一个工具？改代码、重新部署。你想让不同用户看到不同的工具？自己写权限过滤逻辑。</p><p>MCP 的核心 API 之一是 <code>tools/list</code>——客户端启动时问 Server：”你都有啥工具？”Server 返回一个动态列表。这意味着：</p><ul><li>在 Server 侧加一个新工具，所有连接的客户端<strong>不用改任何代码</strong>就能用</li><li>Server 可以根据当前用户、当前权限，返回<strong>不同子集</strong>的工具列表</li><li>工具的描述、参数 schema 都可以在运行时更新</li></ul><p>我最近在做的一个内部项目，用 MCP 接了 6 个 Server：知识库、CRM、邮件、日程、Git、监控。运营同学的客户端能看到前 3 个，工程师能看到全部 6 个，运维只看到监控——都是同一份客户端代码，只是 Server 侧发的工具清单不一样。换 Function Calling 的话，光这套权限逻辑就得写几百行。</p><h2 id="差异四：跨-LLM-vs-单家绑定"><a href="#差异四：跨-LLM-vs-单家绑定" class="headerlink" title="差异四：跨 LLM vs 单家绑定"></a>差异四：跨 LLM vs 单家绑定</h2><p>这点对做产品的人尤其重要。</p><p>我之前做过一个客户项目，用 GPT-4 的 Function Calling 做了一整套工具集成。后来客户要改成 Claude——<strong>工具定义格式不一样</strong>（OpenAI 用 JSON Schema，Anthropic 用的是类似但不完全一样的格式），消息结构也不一样（OpenAI 的 <code>tool_calls</code> vs Anthropic 的 <code>tool_use</code> content block），全部代码重写一遍，花了一周。</p><p>MCP 协议本身是厂商中立的。只要客户端实现了 MCP 协议，它就能连任何 MCP Server；你的 Server 也可以同时服务给 Claude Desktop、Cursor、Cline、甚至某些支持 MCP 的 OpenAI 兼容 Client。</p><p><strong>对 Server 开发者来说，写一次，所有生态都能用</strong>。这是真正的网络效应，也是为什么我判断 MCP 会比 Function Calling 活得久。</p><p>当然现在阶段 OpenAI 自家还没有正式支持 MCP（2026 年初还是这个状态），但第三方适配层已经有一堆了，转换成本比当年重写 Function Calling 低多了。</p><h2 id="差异五：服务端自治-vs-客户端编排"><a href="#差异五：服务端自治-vs-客户端编排" class="headerlink" title="差异五：服务端自治 vs 客户端编排"></a>差异五：服务端自治 vs 客户端编排</h2><p>这条比较抽象但很关键。</p><p>Function Calling 模式下，<strong>所有编排逻辑都在你的客户端代码里</strong>：什么时候调工具、调哪个、失败重试、结果怎么传回模型——这些都是你写的应用代码在决定。模型只负责”生成 JSON”，你负责”真正做事”。</p><p>MCP 下，Server 有更多自主权。它可以：</p><ul><li>定义自己的 <code>resources</code>（只读数据源），让模型直接引用而不是通过工具调用</li><li>定义 <code>prompts</code>（预制的 prompt 模板），让用户直接选用</li><li>通过 <code>sampling</code> API 主动<strong>反向</strong>请求客户端帮它跑一次 LLM 推理（比如 Server 自己需要做一次翻译）</li><li>发送 <code>progress</code> 通知告诉客户端”我这个任务进度 30%”</li></ul><p>这些能力是 Function Calling 完全没有的。说白了，Function Calling 把模型当大脑、把工具当手；MCP 把 Server 也当作一个有智能的参与方，大家是协作关系。</p><h2 id="选型建议：什么时候用哪个"><a href="#选型建议：什么时候用哪个" class="headerlink" title="选型建议：什么时候用哪个"></a>选型建议：什么时候用哪个</h2><p>拆完差异，回到实际问题——你到底该选哪个？</p><p><strong>选 Function Calling 的场景</strong>：</p><ul><li>单次 API 调用能搞定的任务，比如”帮我写邮件时调一次日历查空闲”</li><li>快速原型、一次性脚本</li><li>只给自己或少数内部工具用</li><li>模型厂商锁定不是问题（比如你们公司就认 OpenAI）</li></ul><p><strong>选 MCP 的场景</strong>：</p><ul><li>要给非开发者终端用户用（他们装 Claude Desktop &#x2F; Cursor 就能用你的工具）</li><li>工具需要共享给多个应用，一次开发多处复用</li><li>有长时任务、需要状态和流式响应</li><li>在搞 Agent 产品，希望兼容未来更多客户端</li></ul><p>真实世界里，我现在新项目几乎都走 MCP 了。开发成本没高多少（FastMCP 这种框架已经很顺手），但获得的可移植性和生态红利很可观。关于 FastMCP 的具体用法，我在 <a href="/categories/Tool%E4%B8%8EMCP/">Tool与MCP 分类</a> 下面那篇”30 分钟手搓 MCP Server”里有完整的代码示例可以参考。</p><p>如果你正在做 Agent 方向的产品，还可以去 <a href="/categories/Agent%E5%BC%80%E5%8F%91/">Agent开发 分类</a> 看看那边关于 Skills 和 Agent 架构的文章，跟 MCP 组合起来用会有更多想象空间。</p><h2 id="最后说点我的个人判断"><a href="#最后说点我的个人判断" class="headerlink" title="最后说点我的个人判断"></a>最后说点我的个人判断</h2><p>MCP 现在还在早期——协议版本还在迭代（最新是 2025-06-18 draft），生态工具链不算成熟，debug 也比 Function Calling 麻烦（多一层协议就多一层坑）。</p><p>但我的感觉是：<strong>这波标准化是挡不住的</strong>。Function Calling 这种”每家一套 API”的做法，在行业成熟度低的时候是必然现象，就跟早期移动端充电器一样；但当生态规模到了一定阶段，标准化协议一定会胜出。苹果最后也上了 Type-C，对吧。</p><p>做选型决策的时候，我现在的默认选项是 MCP；只有在”真的只需要一次性、工具很少、没有复用需求”的场景才退回 Function Calling。</p><p>这不是什么信仰，是算过账的——多花 20% 的开发成本，换来 3 年后不用大重构，这买卖稳赚。</p><div class="cta-card">  <div class="cta-title">Agent 生态正在爆发式演化</div>  <div class="cta-desc">想跟进 MCP 协议的最新动态和厂商适配进展，推荐关注 <a class="link"   href="https://news.cocoloop.cn/" >news.cocoloop.cn<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 的 AI 快讯板块；想看更多 Agent 架构讨论，可以去 <a class="link"   href="https://www.cocoloop.cn/" >www.cocoloop.cn<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 翻一翻。</div></div>]]>
    </content>
    <id>https://claude.cocoloop.cn/posts/mcp-vs-function-calling/</id>
    <link href="https://claude.cocoloop.cn/posts/mcp-vs-function-calling/"/>
    <published>2026-04-05T03:30:00.000Z</published>
    <summary>很多人以为 MCP 就是换皮 Function Calling，这个判断错得离谱。把两者放在一张桌子上对比五个关键差异，顺便聊聊选型时怎么判断你到底需要哪个。</summary>
    <title>MCP 会是 AI 世界的 USB-C 吗？和 Function Calling 到底差在哪</title>
    <updated>2026-04-15T08:40:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Claude 中文知识站</name>
    </author>
    <category term="Agent开发" scheme="https://claude.cocoloop.cn/categories/Agent%E5%BC%80%E5%8F%91/"/>
    <category term="Skills" scheme="https://claude.cocoloop.cn/tags/Skills/"/>
    <category term="品牌文案" scheme="https://claude.cocoloop.cn/tags/%E5%93%81%E7%89%8C%E6%96%87%E6%A1%88/"/>
    <category term="业务落地" scheme="https://claude.cocoloop.cn/tags/%E4%B8%9A%E5%8A%A1%E8%90%BD%E5%9C%B0/"/>
    <category term="SKILL.md" scheme="https://claude.cocoloop.cn/tags/SKILL-md/"/>
    <content>
      <![CDATA[<p>这个项目的起因特别真实——我老婆是她们公司市场部负责人，某天晚上她一边改文案一边叹气：”这个实习生又把 B 端产品的官网 banner 写成了小红书卖货文案的语气，产品经理又发火了。”</p><p>我随口问了一句：”你们公司没有品牌 tone &amp; manner 手册吗？”</p><p>她一脸苦笑：”有啊，一份 40 页的 PDF。谁会每写一条文案就翻一遍？”</p><p>就这一句话点醒我了。这不就是 Claude Skills 完美适配的场景吗？——一套规则、需要严格遵守、人类执行起来很累、但对 AI 来说只是 reading task。那晚我就开始动手，花了大概两周（零碎时间）做了一个「品牌文案专家」Skill。现在她们市场部三个人日常都在用，实习生再也没犯过低级错误。</p><p>这篇想完整记录这个事儿——从需求分析到 SKILL.md 落地到上线后的反馈，给正在想给业务团队做 AI 工具的同学一个参考。</p><h2 id="一、这个需求到底是个什么问题"><a href="#一、这个需求到底是个什么问题" class="headerlink" title="一、这个需求到底是个什么问题"></a>一、这个需求到底是个什么问题</h2><p>先说清楚她们公司的情况。公司主营两条产品线：</p><ul><li><strong>A 产品</strong>：给金融机构的合规审计 SaaS，B 端、客单价百万级、买家是银行风控总监。官网、白皮书、案例都要”稳重、专业、权威”</li><li><strong>B 产品</strong>：个人理财 App，C 端、年轻白领、社媒投放为主。需要”亲切、有梗、偶尔调皮”</li></ul><p>问题出在<strong>同一套文案人马同时服务两条线</strong>。实习生写 A 产品的时候带着 B 产品的语气——“银行合规好难？让我们一起搞定！”——产品经理看到当场黑脸。反过来写 B 产品的时候又回到”本产品致力于为用户提供专业的理财解决方案”——运营看到又想哭。</p><p>传统解决方案？写 tone 手册、做培训、reviewer 卡稿。都试过，人工成本高、效果还不稳定。</p><h2 id="二、为什么选-Skill，不选别的"><a href="#二、为什么选-Skill，不选别的" class="headerlink" title="二、为什么选 Skill，不选别的"></a>二、为什么选 Skill，不选别的</h2><p>最早我想到的其实是<strong>改系统 prompt</strong>——在她们 ChatGPT 企业账号的 default prompt 里塞一大段品牌规则。但有几个问题：</p><ul><li>写一万字 prompt 成本吃不消，每次请求都烧</li><li>两条产品线混在一个 prompt 里，模型容易串味</li><li>规则一改全员得手动更新，没版本控制</li></ul><p>然后想到 <strong>RAG</strong>——把品牌手册切片、embedding、按需检索。问题是 tone &amp; manner 是个<strong>整体风格</strong>，按关键词检索出来都是断章，拼不出完整画面。</p><p>Skill 就很对路：</p><ul><li><strong>按需加载</strong>：用户说”写 A 产品文案”才激活 A 的 Skill，不混淆</li><li><strong>完整上下文</strong>：主 SKILL.md 一次性把 tone 完整载入，不会断章</li><li><strong>版本化</strong>：git 管理，改了一次全员同步</li><li><strong>描述触发</strong>：description 里写清楚”什么时候用我”，模型自动选择</li></ul><p>关于 Skills 的底层机制为啥适合这种场景，我在 <a href="/categories/Agent%E5%BC%80%E5%8F%91/">Agent开发 分类</a> 里那篇深度拆解讲得更细，这里就不重复了。</p><h2 id="三、SKILL-md-到底怎么写"><a href="#三、SKILL-md-到底怎么写" class="headerlink" title="三、SKILL.md 到底怎么写"></a>三、SKILL.md 到底怎么写</h2><p>这是核心问题。我给她们做的那个 A 产品 Skill 完整结构：</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu 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><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">brand-voice-product-a/</span><br><span class="line">├── SKILL.md</span><br><span class="line">├── references/</span><br><span class="line">│   ├── banned-words.md         # 禁用词清单</span><br><span class="line">│   ├── approved-tone-examples.md  # 20 个正例</span><br><span class="line">│   ├── rejected-examples.md    # 20 个反例加点评</span><br><span class="line">│   └── scenario-templates.md   # 5 类场景文案模板</span><br><span class="line">└── .version</span><br></pre></td></tr></table></figure></div><p><code>SKILL.md</code> 我来完整贴一下（脱敏过，公司名换成了占位符）：</p><div class="code-container" data-rel="Markdown"><figure class="iseeu highlight markdown"><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><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line">---</span><br><span class="line">name: brand-voice-product-a</span><br><span class="line"><span class="section">description: 为 XX 金融合规 SaaS（产品 A）撰写或审阅营销文案。适用于官网 banner、白皮书摘要、客户案例、社媒、BD 邮件等场景。当用户提到&quot;A 产品&quot;&quot;合规审计 SaaS&quot;&quot;XX 平台&quot;并需要文案撰写或修改时使用。</span></span><br><span class="line"><span class="section">---</span></span><br><span class="line"></span><br><span class="line"><span class="section"># 产品 A 品牌文案专家</span></span><br><span class="line"></span><br><span class="line">你正在为 XX 公司的合规审计 SaaS 产品线撰写营销文案。这是一个<span class="strong">**严肃的 B 端产品**</span>，目标读者是银行/证券/保险机构的风控、合规、审计部门负责人。</span><br><span class="line"></span><br><span class="line"><span class="section">## 品牌基调（Brand Voice）</span></span><br><span class="line"></span><br><span class="line">三个关键词：<span class="strong">**专业、稳重、克制**</span>。</span><br><span class="line"></span><br><span class="line"><span class="bullet">-</span> 避免所有&quot;兴奋感&quot;和&quot;营销口吻&quot;</span><br><span class="line"><span class="bullet">-</span> 不使用感叹号（极特殊场景除外）</span><br><span class="line"><span class="bullet">-</span> 不使用&quot;革命性&quot;&quot;颠覆&quot;&quot;绝佳&quot;这类夸张形容</span><br><span class="line"><span class="bullet">-</span> 不假设读者情绪，直接讲事实和价值</span><br><span class="line"></span><br><span class="line">参照行业标杆：埃森哲、普华永道、Palantir 的官网文案。</span><br><span class="line"></span><br><span class="line"><span class="section">## 三条铁律</span></span><br><span class="line"></span><br><span class="line"><span class="bullet">1.</span> <span class="strong">**第一段必须给出核心价值**</span>，不要铺垫行业背景</span><br><span class="line"><span class="bullet">2.</span> <span class="strong">**数字比形容词优先**</span>：能用&quot;效率提升 47%&quot;绝不用&quot;大幅提升&quot;</span><br><span class="line"><span class="bullet">3.</span> <span class="strong">**案例用具体机构名**</span>（已脱敏的情况下），不说&quot;某大型银行&quot;</span><br><span class="line"></span><br><span class="line"><span class="section">## 必查清单</span></span><br><span class="line"></span><br><span class="line">写完任何一段文案，自查：</span><br><span class="line"></span><br><span class="line"><span class="bullet">-</span> [ ] 有无感叹号？（除了致谢类场景全部改掉）</span><br><span class="line"><span class="bullet">-</span> [ ] 有无&quot;让我们&quot;&quot;一起&quot;&quot;轻松&quot;这类 C 端词汇？</span><br><span class="line"><span class="bullet">-</span> [ ] 有无夸张程度副词（非常、极其、最）？</span><br><span class="line"><span class="bullet">-</span> [ ] 有无数字支撑？</span><br><span class="line"><span class="bullet">-</span> [ ] 第一句话是否讲价值？</span><br><span class="line"></span><br><span class="line"><span class="section">## 引用文件</span></span><br><span class="line"></span><br><span class="line">详细的禁用词清单见 <span class="code">`references/banned-words.md`</span>。</span><br><span class="line">好文案正例看 <span class="code">`references/approved-tone-examples.md`</span>。</span><br><span class="line">常见翻车反例和点评看 <span class="code">`references/rejected-examples.md`</span>。</span><br><span class="line">不同场景（banner/邮件/案例）模板见 <span class="code">`references/scenario-templates.md`</span>。</span><br><span class="line"></span><br><span class="line"><span class="section">## 输出格式</span></span><br><span class="line"></span><br><span class="line">根据任务类型返回：</span><br><span class="line"></span><br><span class="line"><span class="bullet">-</span> <span class="strong">**撰写**</span>：直接给最终文案，不给多版本（怕市场同事选困难症）</span><br><span class="line"><span class="bullet">-</span> <span class="strong">**审阅**</span>：先给出修改后的版本，再列 3-5 条&quot;问题所在&quot;</span><br></pre></td></tr></table></figure></div><p>B 产品那个 Skill 结构一样，内容全反——个性化、有梗、允许偶尔玩谐音——就不单独贴了。</p><h2 id="四、references-文件的几个关键点"><a href="#四、references-文件的几个关键点" class="headerlink" title="四、references 文件的几个关键点"></a>四、references 文件的几个关键点</h2><p>主 SKILL.md 只是总纲，真正的”肌肉”在 references 里。几个我踩过的坑：</p><h3 id="banned-words-md-不要只列禁用词"><a href="#banned-words-md-不要只列禁用词" class="headerlink" title="banned-words.md 不要只列禁用词"></a>banned-words.md 不要只列禁用词</h3><p>一开始我只列了”禁止用词”清单。后来发现模型会漏掉一些变体——比如禁了”让我们”，它会写成”我们一起来”，绕过检查但语气还是错的。</p><p>后来改成<strong>禁用词 + 禁用句式 + 语气关键词</strong>三类：</p><div class="code-container" data-rel="Markdown"><figure class="iseeu highlight markdown"><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"><span class="section">## 禁用词</span></span><br><span class="line"></span><br><span class="line"><span class="bullet">-</span> 让我们、我们一起、不妨、来吧</span><br><span class="line"><span class="bullet">-</span> 超级、爆款、神器、救星</span><br><span class="line"><span class="bullet">-</span> 赶紧、立刻、马上（转化类除外）</span><br><span class="line"></span><br><span class="line"><span class="section">## 禁用句式</span></span><br><span class="line"></span><br><span class="line"><span class="bullet">-</span> 反问句（&quot;你还在为 XX 烦恼吗？&quot;）</span><br><span class="line"><span class="bullet">-</span> 卖惨句式（&quot;再也不用&quot;）</span><br><span class="line"><span class="bullet">-</span> 召唤句式（&quot;点击了解&quot;&quot;立即咨询&quot;——改成陈述&quot;预约演示请访问...&quot;）</span><br><span class="line"></span><br><span class="line"><span class="section">## 禁用语气信号</span></span><br><span class="line"></span><br><span class="line"><span class="bullet">-</span> emoji（B 端全部禁用）</span><br><span class="line"><span class="bullet">-</span> 过度修辞（类比要克制）</span><br><span class="line"><span class="bullet">-</span> 网络流行语（出圈、破防、绝绝子……）</span><br></pre></td></tr></table></figure></div><h3 id="approved-examples-至少放-20-条"><a href="#approved-examples-至少放-20-条" class="headerlink" title="approved-examples 至少放 20 条"></a>approved-examples 至少放 20 条</h3><p>少于 20 条模型泛化能力不够。每条我都标了<strong>为什么这么写</strong>：</p><div class="code-container" data-rel="Markdown"><figure class="iseeu highlight markdown"><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="section">### 例 1 - 官网主 banner</span></span><br><span class="line"></span><br><span class="line">原文：</span><br><span class="line">&quot;为金融机构构建全流程合规审计基础设施&quot;</span><br><span class="line"></span><br><span class="line">为什么好：</span><br><span class="line"><span class="bullet">-</span> 一句话把产品定义说清楚</span><br><span class="line"><span class="bullet">-</span> &quot;基础设施&quot;隐含了&quot;深度集成、长期使用&quot;</span><br><span class="line"><span class="bullet">-</span> 无情绪词、无感叹号</span><br></pre></td></tr></table></figure></div><h3 id="rejected-examples-比-approved-更重要"><a href="#rejected-examples-比-approved-更重要" class="headerlink" title="rejected-examples 比 approved 更重要"></a>rejected-examples 比 approved 更重要</h3><p>这个是我后来加的。模型看到”什么是好的”不一定记得住，但看到”什么是错的以及错在哪”效果好得多。</p><div class="code-container" data-rel="Markdown"><figure class="iseeu highlight markdown"><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="section">### 反例 1</span></span><br><span class="line"></span><br><span class="line">错误文案：</span><br><span class="line">&quot;还在头疼合规审计报告？XX 来帮你搞定！&quot;</span><br><span class="line"></span><br><span class="line">错在哪：</span><br><span class="line"><span class="bullet">-</span> 反问句（营销口吻）</span><br><span class="line"><span class="bullet">-</span> &quot;头疼&quot;带情绪假设</span><br><span class="line"><span class="bullet">-</span> &quot;搞定&quot;过于口语</span><br><span class="line"><span class="bullet">-</span> 感叹号</span><br><span class="line"></span><br><span class="line">正确版本：</span><br><span class="line">&quot;XX 支持合规审计全流程自动化，平均缩短人工报告编制时间 60%。&quot;</span><br></pre></td></tr></table></figure></div><h2 id="五、测试怎么做"><a href="#五、测试怎么做" class="headerlink" title="五、测试怎么做"></a>五、测试怎么做</h2><p>这步特别容易被忽略，但决定了 Skill 能不能真正上线。</p><p>我自己造了一批<strong>触发测试集</strong>——30 条各种各样的任务描述，一半该触发这个 Skill，一半不该触发：</p><ul><li>应触发：「帮我写 A 产品官网 banner」「改一下这段合规审计 SaaS 的案例文案」「产品 A 的 BD 邮件开头怎么写」</li><li>不应触发：「帮我写一封请假邮件」「给 B 产品小红书笔记出个标题」</li></ul><p>跑下来第一版触发准确率只有 73%。问题出在 <code>description</code> 写得太泛——“金融文案”这种词把 B 产品的理财 App 也套进来了。改了三版 description 才把准确率拉到 95% 以上。</p><p><strong>description 字段是 Skill 能不能被正确选中的关键</strong>，值得花时间反复调。我的经验：</p><ul><li>明确列产品名 &#x2F; 关键词</li><li>说清楚场景边界</li><li>避免过于通用的词（”营销””内容”这种别单独用）</li></ul><h2 id="六、上线后的真实反馈"><a href="#六、上线后的真实反馈" class="headerlink" title="六、上线后的真实反馈"></a>六、上线后的真实反馈</h2><p>上线三周了，收集到一些真实用户（市场部三个人）的反馈：</p><p><strong>正向反馈</strong>：</p><ul><li>实习生那边，产品 PM 审稿打回率从约 40% 掉到 8%</li><li>我老婆自己写稿速度快了约 30%（因为不用反复核对 tone 手册）</li><li>最意外的：<strong>新入职的人上手时间从 2 周变成 2 天</strong>——因为 Skill 本身就是 onboarding 手册</li></ul><p><strong>负向反馈</strong>：</p><ul><li>写「混合场景」（比如 A 产品在年轻人媒体投放）的时候，两个 Skill 都不太贴，需要人工裁剪</li><li>偶尔模型”太听话”，稍微有感情的地方也被它改得死板，需要人工回调一下</li><li>Skill 覆盖不到的完全新场景（比如第一次做播客脚本），还是得人来主导</li></ul><p><strong>还没解决的问题</strong>：</p><ul><li>不同 Claude 客户端对 Skills 的支持度不一致。Claude Desktop 原生支持最好，有些第三方 Client 触发不太稳</li><li>Skill 更新后要让所有人同步，目前靠我老婆在群里发 git pull 命令（够土但有用）</li></ul><h2 id="七、给想做类似事情的你几个建议"><a href="#七、给想做类似事情的你几个建议" class="headerlink" title="七、给想做类似事情的你几个建议"></a>七、给想做类似事情的你几个建议</h2><p>如果你也想给业务团队做一个类似的 Skill，我的踩坑总结：</p><p><strong>第一，别一上来写太完美</strong>。MVP 先跑起来，用户用起来之后反馈远比闭门造车值钱。我那个第一版只有 SKILL.md 一个文件，references 都是后续加的。</p><p><strong>第二，description 是命脉</strong>。这一行决定 Skill 能不能被正确激活，花时间反复测。</p><p><strong>第三，反例比正例更值钱</strong>。模型对”别怎么做”的记忆比”怎么做”更深。</p><p><strong>第四，留个人工兜底</strong>。Skill 不是万能的，总有它不擅长的场景。告诉用户”遇到 XX 情况直接找人”比硬让模型发挥好。</p><p><strong>第五，版本化管理</strong>。我用 git 管了这套 Skill 已经改了 18 个 commit，每次改动都能追溯。</p><p>想看更多 Claude 在企业落地的案例，可以去 <a class="link"   href="https://www.cocoloop.cn/" >www.cocoloop.cn<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 翻；想跟进 Skills 相关的最新功能更新，<a class="link"   href="https://news.cocoloop.cn/" >news.cocoloop.cn<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 上有不少一手信息。</p><p>最后说点感触。</p><p>以前我们做企业 AI 工具，总觉得要做一个”大脑”——能自动理解一切、自动决策。干了这个项目之后我反而觉得，<strong>更好的方式是把企业已有的隐性知识显性化、结构化，让模型当个靠谱的执行者</strong>。</p><p>你们公司一定有很多「老员工脑子里的规矩」没写下来——Skills 就是把这些东西沉淀下来的最好容器。做一个，就能让新人快速上手；做十个，就是整个团队的共享肌肉。</p><p>这事儿不酷炫，但特别管用。</p><div class="cta-card">  <div class="cta-title">把团队经验变成可复用的 AI 能力</div>  <div class="cta-desc">更多 Agent 和 Skills 的业务落地案例在 <a class="link"   href="https://www.cocoloop.cn/" >www.cocoloop.cn<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 持续更新；想和同行交流实战经验，欢迎来 <a class="link"   href="https://ask.cocoloop.cn/" >ask.cocoloop.cn<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 提问。</div></div>]]>
    </content>
    <id>https://claude.cocoloop.cn/posts/custom-skill-brand-writer/</id>
    <link href="https://claude.cocoloop.cn/posts/custom-skill-brand-writer/"/>
    <published>2026-04-02T01:50:00.000Z</published>
    <summary>市场同事写文案总犯品牌基调错误，把严肃产品说得太轻佻、把年轻品牌写得太正式。这篇完整记录我用 Claude Skill 封装品牌 voice guide 的过程，包括 SKILL.md 怎么写、测试怎么做、上线之后的反馈。</summary>
    <title>自定义 Skill 实战：给市场团队做一个永不出错的品牌文案专家</title>
    <updated>2026-04-16T09:10:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Claude 中文知识站</name>
    </author>
    <category term="Prompt工程" scheme="https://claude.cocoloop.cn/categories/Prompt%E5%B7%A5%E7%A8%8B/"/>
    <category term="Claude" scheme="https://claude.cocoloop.cn/tags/Claude/"/>
    <category term="XML" scheme="https://claude.cocoloop.cn/tags/XML/"/>
    <category term="Markdown" scheme="https://claude.cocoloop.cn/tags/Markdown/"/>
    <category term="Prompt工程" scheme="https://claude.cocoloop.cn/tags/Prompt%E5%B7%A5%E7%A8%8B/"/>
    <content>
      <![CDATA[<p>这事儿是我去年底帮一个法律科技公司做合同条款抽取时遇到的。他们要从合同里抽出 “甲方名称 &#x2F; 乙方名称 &#x2F; 合同金额 &#x2F; 签订日期 &#x2F; 违约条款” 这五个字段，然后入库。</p><p>我一开始写的 prompt 是很标准的 Markdown 风格：</p><div class="code-container" data-rel="Markdown"><figure class="iseeu highlight markdown"><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="section">## 任务</span></span><br><span class="line">从下面的合同文本中抽取指定字段。</span><br><span class="line"></span><br><span class="line"><span class="section">## 要求</span></span><br><span class="line"><span class="bullet">-</span> 返回 JSON 格式</span><br><span class="line"><span class="bullet">-</span> 找不到的字段返回 null</span><br><span class="line"><span class="bullet">-</span> 金额统一转成人民币数字</span><br><span class="line"></span><br><span class="line"><span class="section">## 合同文本</span></span><br><span class="line">（此处插入合同 3000 字）</span><br><span class="line"></span><br><span class="line"><span class="section">## 输出字段</span></span><br><span class="line">party<span class="emphasis">_a, party_</span>b, amount, date, penalty<span class="emphasis">_clause</span></span><br></pre></td></tr></table></figure></div><p>跑了 500 个样本，准确率 71%。老板看完脸色不太好。</p><p>我折腾了一下午改 prompt，换措辞、加例子、调顺序，最多也就爬到 75%。然后我想起 Anthropic 官方文档里反复强调的一句话：”Claude was fine-tuned with XML tags.”。我就死马当活马医，把整个 prompt 的结构改成 XML：</p><div class="code-container" data-rel="Xml"><figure class="iseeu highlight xml"><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></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">task</span>&gt;</span>从合同文本中抽取指定字段<span class="tag">&lt;/<span class="name">task</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">requirements</span>&gt;</span></span><br><span class="line">- 返回 JSON 格式</span><br><span class="line">- 找不到的字段返回 null  </span><br><span class="line">- 金额统一转成人民币数字</span><br><span class="line"><span class="tag">&lt;/<span class="name">requirements</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">contract</span>&gt;</span></span><br><span class="line">（此处插入合同 3000 字）</span><br><span class="line"><span class="tag">&lt;/<span class="name">contract</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">output_fields</span>&gt;</span></span><br><span class="line">party_a, party_b, amount, date, penalty_clause</span><br><span class="line"><span class="tag">&lt;/<span class="name">output_fields</span>&gt;</span></span><br></pre></td></tr></table></figure></div><p>同样的 500 个样本，准确率直接跳到 89%。我当时盯着屏幕看了很久，觉得不可思议——<strong>仅仅换了分隔符，效果差了将近 20 个百分点</strong>。</p><p>从那之后，我写 Claude 的 prompt 再也不用 Markdown 了。这篇把我理解的原因、可复制的模板、几个关键细节讲清楚。</p><h2 id="一、为什么差这么多？训练数据的秘密"><a href="#一、为什么差这么多？训练数据的秘密" class="headerlink" title="一、为什么差这么多？训练数据的秘密"></a>一、为什么差这么多？训练数据的秘密</h2><p>这个问题 Anthropic 没有官方给出技术解释，但从他们的文档、论文、和员工公开访谈里能拼出一个大概的图像。</p><p><strong>Claude 在 Anthropic 内部训练时，大量使用 XML 标签作为结构分隔符</strong>。这是他们 Constitutional AI 训练流程里的一个工程习惯——用 <code>&lt;human&gt;...&lt;/human&gt;</code> 和 <code>&lt;assistant&gt;...&lt;/assistant&gt;</code> 分隔角色，用 <code>&lt;instruction&gt;...&lt;/instruction&gt;</code> 分隔指令，用 <code>&lt;context&gt;...&lt;/context&gt;</code> 分隔背景信息。</p><p>这些标签在训练数据里出现了<strong>数百万次</strong>，形成了强烈的分布偏好。模型看到 <code>&lt;xxx&gt;...&lt;/xxx&gt;</code> 这种结构时，会非常明确地”知道”这是一段独立的、需要被单独对待的内容。</p><p>而 Markdown 的 <code>#</code> <code>##</code> <code>---</code> 这些符号呢？它们在训练数据里也出现很多，但<strong>它们同时出现在模型需要生成的文本里</strong>——模型在很多场景下就是在生成 Markdown 文档本身。这就导致了一个混淆：模型看到 <code>##</code> 时，它不确定这是”输入的结构分隔符”还是”用户想让我生成的内容的一部分”。</p><p>相比之下，XML 标签在训练语料里<strong>几乎只作为结构分隔符出现</strong>，语义非常干净。这就是为什么 XML 的边界感更强。</p><p>GPT 系列的情况不太一样——OpenAI 训练时没有特别偏向 XML，所以对它来说 Markdown 和 XML 差别不大。这是 Claude 特有的属性。Gemini 的情况介于两者之间，XML 有一定效果但不如在 Claude 上显著。这也侧面说明了<strong>prompt 风格和模型是强绑定的</strong>，没有放之四海皆准的”最佳 prompt 格式”。</p><h2 id="二、具体差在哪儿？我做过的消融实验"><a href="#二、具体差在哪儿？我做过的消融实验" class="headerlink" title="二、具体差在哪儿？我做过的消融实验"></a>二、具体差在哪儿？我做过的消融实验</h2><p>我后来做过一个小型消融实验，同一个任务分别用五种格式跑：</p><table><thead><tr><th>格式</th><th>准确率</th></tr></thead><tbody><tr><td>纯文本（全部堆在一起）</td><td>58%</td></tr><tr><td>Markdown 标题分段</td><td>71%</td></tr><tr><td>Markdown + 三连下划线分隔</td><td>74%</td></tr><tr><td>JSON 式大括号</td><td>79%</td></tr><tr><td>XML 标签</td><td>89%</td></tr></tbody></table><p>这个结果让我意识到几件事：</p><p><strong>1. 任何结构都比没结构好</strong>。纯文本到 Markdown 就有 13 个百分点提升，说明”分段”本身就很重要。</p><p><strong>2. XML 的优势主要体现在边界清晰</strong>。模型知道 <code>&lt;contract&gt;</code> 和 <code>&lt;/contract&gt;</code> 之间的东西是一个完整的块，不会和外面的指令混起来。Markdown 的 <code>## 合同文本</code> 开始了，但什么时候结束呢？下一个 <code>##</code> 吗？模型要自己推断，容易出错。</p><p><strong>3. 差距在输入越长时越明显</strong>。短 prompt（500 token 以内）Markdown 和 XML 差个 5-8 个百分点，长 prompt（3000+ token）就能拉到 15-20 个百分点。因为长输入里边界判断的重要性被放大。</p><p><strong>4. 结构的语义信息也有加成</strong>。同样用 XML，把外层标签从 <code>&lt;data&gt;</code> 改成 <code>&lt;legal_contract&gt;</code>，准确率能再涨 2-3 个点。因为语义化的标签名本身给了模型关于内容性质的提示——模型知道”这是合同而不是随便的文本”，处理态度就不一样。</p><h2 id="三、我现在用的标准-XML-模板"><a href="#三、我现在用的标准-XML-模板" class="headerlink" title="三、我现在用的标准 XML 模板"></a>三、我现在用的标准 XML 模板</h2><p>把这套经验固化一下，我现在写 Claude prompt 的基础模板长这样：</p><div class="code-container" data-rel="Xml"><figure class="iseeu highlight xml"><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="tag">&lt;<span class="name">role</span>&gt;</span></span><br><span class="line">你是一个 [具体角色描述]。</span><br><span class="line">你的任务是 [一句话任务说明]。</span><br><span class="line"><span class="tag">&lt;/<span class="name">role</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">instructions</span>&gt;</span></span><br><span class="line">1. [具体步骤 1]</span><br><span class="line">2. [具体步骤 2]</span><br><span class="line">3. [具体步骤 3]</span><br><span class="line"><span class="tag">&lt;/<span class="name">instructions</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">context</span>&gt;</span></span><br><span class="line">[所有需要的背景信息、知识、数据]</span><br><span class="line"><span class="tag">&lt;/<span class="name">context</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">examples</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">example</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">input</span>&gt;</span>[示例输入]<span class="tag">&lt;/<span class="name">input</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">output</span>&gt;</span>[示例输出]<span class="tag">&lt;/<span class="name">output</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">example</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">example</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">input</span>&gt;</span>[示例输入 2]<span class="tag">&lt;/<span class="name">input</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">output</span>&gt;</span>[示例输出 2]<span class="tag">&lt;/<span class="name">output</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">example</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">examples</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">input</span>&gt;</span></span><br><span class="line">[本次要处理的实际输入]</span><br><span class="line"><span class="tag">&lt;/<span class="name">input</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">output_format</span>&gt;</span></span><br><span class="line">[明确的输出格式要求，最好给个 JSON schema]</span><br><span class="line"><span class="tag">&lt;/<span class="name">output_format</span>&gt;</span></span><br></pre></td></tr></table></figure></div><p>这个模板有几个原则：</p><p><strong>1. 标签名要有语义</strong>。不要用 <code>&lt;tag1&gt; &lt;tag2&gt;</code> 这种无意义的名字。<code>&lt;contract&gt;</code> <code>&lt;resume&gt;</code> <code>&lt;invoice&gt;</code> 这种直接点明内容类型的最好——模型能用标签本身获取额外信息。</p><p><strong>2. 可以嵌套</strong>。<code>&lt;examples&gt;</code> 里套 <code>&lt;example&gt;</code>，<code>&lt;example&gt;</code> 里再套 <code>&lt;input&gt;</code> 和 <code>&lt;output&gt;</code>。Claude 对嵌套结构识别很稳定，两到三层嵌套都没问题。</p><p><strong>3. 输入放靠后的位置</strong>。研究表明 Claude 对 prompt 末尾的内容注意力最强（recency bias）。所以真正要处理的 <code>&lt;input&gt;</code> 放在靠后位置，更稳定。</p><p><strong>4. 指令和数据严格分离</strong>。<code>&lt;instructions&gt;</code> 里只写”怎么做”，不要混入具体数据。具体数据放 <code>&lt;context&gt;</code> 或 <code>&lt;input&gt;</code>。这条原则在做 prompt injection 防御时也格外重要——指令和数据混在一起，用户注入攻击就容易得手。</p><p><strong>5. 用空行增加可读性</strong>。XML 标签之间加空行不影响模型理解，但能让 prompt 人类看着舒服、方便后续维护。</p><h2 id="四、几个容易翻车的点"><a href="#四、几个容易翻车的点" class="headerlink" title="四、几个容易翻车的点"></a>四、几个容易翻车的点</h2><p><strong>1. 标签不要和要处理的内容冲突</strong>。<br>比如你要处理一份 HTML 文档，HTML 本身就有大量 <code>&lt;div&gt;</code> <code>&lt;span&gt;</code> 标签。这时候你包装数据的标签名要用<strong>不会出现在 HTML 里的</strong>，比如 <code>&lt;html_document&gt;</code> 而不是 <code>&lt;content&gt;</code>，避免混淆。</p><p><strong>2. 不要用自闭合标签</strong>。<br>Claude 对 <code>&lt;tag/&gt;</code> 这种自闭合形式识别率不如 <code>&lt;tag&gt;&lt;/tag&gt;</code>。老老实实开闭配对。</p><p><strong>3. 中文标签会翻车</strong>。<br>我试过用中文标签名（比如 <code>&lt;角色&gt;...&lt;/角色&gt;</code>），准确率不如英文标签。因为训练数据里 XML 标签绝大多数是英文，模型的偏好是在英文上建立的。<strong>内容可以中文，标签名一定英文</strong>。</p><p><strong>4. 和 Markdown 混用没问题，但别混淆层级</strong>。<br>XML 包外层结构，内部 <code>&lt;instructions&gt;</code> 里可以用 Markdown 列表，这是没问题的。但不要一个任务一半用 XML 框一半用 Markdown 标题框，那样模型会懵。</p><p><strong>5. 标签不要太多也不要太少</strong>。<br>我见过两种极端：一种是整个 prompt 就一对 <code>&lt;task&gt;...&lt;/task&gt;</code> 把所有东西包进去，这等于没分块；另一种是每一句话都包一个标签，过度工程化。<strong>一般 4-8 对顶层标签是比较舒服的量</strong>。</p><p><strong>6. 不要在 XML 标签里写 markdown 反引号代码块的开头</strong>。<br>很少人会撞上但确实存在：如果你在 <code>&lt;code&gt;...&lt;/code&gt;</code> 里直接写代码，大部分时候没问题；但如果代码里本身含有 <code>&lt;</code> <code>&gt;</code> 符号（比如 Go 的泛型或 HTML 片段），模型可能会错乱。这时候要么用 CDATA 风格（<code>&lt;![CDATA[...]]&gt;</code>，Claude 认），要么外层标签改名绕开冲突。</p><h2 id="五、不仅仅是输入，输出也能用-XML"><a href="#五、不仅仅是输入，输出也能用-XML" class="headerlink" title="五、不仅仅是输入，输出也能用 XML"></a>五、不仅仅是输入，输出也能用 XML</h2><p>有个更进一步的技巧：<strong>让 Claude 用 XML 组织它的输出</strong>，再解析出来。</p><p>比如我要求 Claude 先思考再回答：</p><div class="code-container" data-rel="Xml"><figure class="iseeu highlight xml"><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="tag">&lt;<span class="name">instructions</span>&gt;</span></span><br><span class="line">请按以下格式输出：</span><br><span class="line"><span class="tag">&lt;<span class="name">thinking</span>&gt;</span>你的推理过程<span class="tag">&lt;/<span class="name">thinking</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">answer</span>&gt;</span>最终答案<span class="tag">&lt;/<span class="name">answer</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">instructions</span>&gt;</span></span><br></pre></td></tr></table></figure></div><p>这比让它用 “思考：… 答案：…” 这种 Markdown 风格要稳定得多。后端解析也很简单，正则一抓一个准。</p><p>这招在 Agent 场景里特别好用——你可以让模型输出 <code>&lt;tool_call&gt;</code>、<code>&lt;reasoning&gt;</code>、<code>&lt;plan&gt;</code> 这种结构化标签，程序化地拆开。这部分实战我另一篇讲 Agent 的文章里有更多例子，想看可以翻 <a href="/categories/Prompt%E5%B7%A5%E7%A8%8B/">Prompt工程分类</a>。</p><p>延伸的一个小 trick：<strong>给 Claude 预设输出开头</strong>。比如你在 API 调用里把 assistant 的开头预填为 <code>&lt;answer&gt;</code>，Claude 会自动从那里续写，不会再输出啰嗦的开场白。配合 stop sequence <code>&lt;/answer&gt;</code> 使用，一次调用就能稳定拿到干净的答案内容，适合做结构化抽取的生产环境。</p><h2 id="六、进阶：XML-Tool-Use-的组合拳"><a href="#六、进阶：XML-Tool-Use-的组合拳" class="headerlink" title="六、进阶：XML + Tool Use 的组合拳"></a>六、进阶：XML + Tool Use 的组合拳</h2><p>如果你用的是 Claude 的 tool use 功能，其实你已经在用 XML 了——Anthropic 的 tool call 格式底层就是 XML。你在 system prompt 里用 XML 组织指令，和工具调用的格式天然一致，模型处理起来更流畅。</p><p>我最近在做的一个 Agent 项目就是这个玩法：</p><ul><li>system prompt 用 XML 定义角色、规则、工具使用准则</li><li>tool schema 按 Anthropic 的 XML tool 格式定义</li><li>中间步骤让模型输出 <code>&lt;scratchpad&gt;...&lt;/scratchpad&gt;</code> 做思考</li><li>最终结果用 <code>&lt;final_answer&gt;...&lt;/final_answer&gt;</code> 包装</li></ul><p>整套 prompt 从头到尾都是 XML 结构，模型的一致性特别好。转战 Claude 之后我再也不想回去搞 GPT 那套花里胡哨的 function calling schema 了。</p><h2 id="七、最后说两句"><a href="#七、最后说两句" class="headerlink" title="七、最后说两句"></a>七、最后说两句</h2><p>XML over Markdown 这个小技巧看着不起眼，但在生产环境里能直接拉高 10-15 个百分点的准确率，值回票价。这种”训练数据偏好”导致的工程 trick 还有不少，比如 Claude 对 “Here is the answer:” 这种引导句的敏感度、对 <code>&lt;system&gt;</code> 标签的权重倾斜、对 “step by step” 这种链式思考触发词的反应等等。我会持续把踩到的这类坑整理出来。</p><p>如果你是 Claude 新手，建议把上面那个标准模板存下来，下次写 prompt 直接填空。光这一点，你 prompt 的效果就会比 80% 的同行好。想看更多 Claude 实战内容可以顺带访问一下 <a class="link"   href="https://www.cocoloop.cn/" >www.cocoloop.cn<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 和 <a class="link"   href="https://openclaw.cocoloop.cn/" >openclaw.cocoloop.cn<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>，后者是专门聚焦 Anthropic 生态的一个子站。</p><p>最后分享一个心得：<strong>prompt 格式和模型版本是绑死的</strong>。Claude 3 Opus 时代最有效的 XML 模板，到了 Sonnet 4.6 上效果会微妙地变化，新模型对结构的宽容度更高一些。每次换模型版本，建议把自己最常用的几个 prompt 拉出来回归测一遍，别想当然。</p><div class="cta-card">  <div class="cta-title">想把 Prompt 写到 90 分以上？</div>  <div class="cta-desc">本站 Prompt 工程板块持续更新 Claude 实战技巧。相关 AI 深度内容可访问 <a class="link"   href="https://openclaw.cocoloop.cn/" >openclaw.cocoloop.cn<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>，AI 行业新闻访问 <a class="link"   href="https://news.cocoloop.cn/" >news.cocoloop.cn<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>。</div></div>]]>
    </content>
    <id>https://claude.cocoloop.cn/posts/claude-xml-over-markdown/</id>
    <link href="https://claude.cocoloop.cn/posts/claude-xml-over-markdown/"/>
    <published>2026-04-02T01:25:00.000Z</published>
    <summary>同一个 prompt，我用 Markdown 分隔段落跑，准确率 71%；改成 XML 标签分隔，准确率 89%。差距不是误差范围。这篇讲 Claude 为什么对 XML 这么偏爱，以及我现在用的标准 XML 模板。</summary>
    <title>为什么 Claude 只吃 XML 不吃 Markdown？一个被忽视的训练数据秘密</title>
    <updated>2026-04-16T03:10:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Claude 中文知识站</name>
    </author>
    <category term="成本优化" scheme="https://claude.cocoloop.cn/categories/%E6%88%90%E6%9C%AC%E4%BC%98%E5%8C%96/"/>
    <category term="Claude" scheme="https://claude.cocoloop.cn/tags/Claude/"/>
    <category term="API" scheme="https://claude.cocoloop.cn/tags/API/"/>
    <category term="成本优化" scheme="https://claude.cocoloop.cn/tags/%E6%88%90%E6%9C%AC%E4%BC%98%E5%8C%96/"/>
    <category term="Prompt Caching" scheme="https://claude.cocoloop.cn/tags/Prompt-Caching/"/>
    <content>
      <![CDATA[<p>去年八月我有一个客户项目，每天要处理 3000 多份 PDF 文档，做字段抽取。上线第一周账单直接给我整破防——<strong>一周烧了 $780</strong>。客户给的预算是一个月 $500，我算了下按这速度一个月得 $3300+，项目直接要赔钱。</p><p>那时候我正好看到 Anthropic 更新了 Prompt Caching 的文档，抱着试试的心态改了几行代码。改完跑了一天，第二天打开账单那一刻我真的惊了——<strong>单日成本从 $110 降到 $18</strong>。不是看错，是真的降了 83%。</p><p>从那天起我就成了 Prompt Caching 的重度用户，这东西在我这儿已经是”每个项目上线前必做的检查项”。这篇文章想把我这一年踩过的坑、摸出来的最佳实践全部摊开，给还没用过的人一个能直接照抄的参考。</p><h2 id="一、先把价格结构讲清楚"><a href="#一、先把价格结构讲清楚" class="headerlink" title="一、先把价格结构讲清楚"></a>一、先把价格结构讲清楚</h2><p>很多文章讲 Prompt Caching 第一句就是”能省 90%”，但<strong>不告诉你是在什么条件下省的</strong>。先把价格表拉清楚：</p><p>以 Claude Sonnet 4.6 为例（Opus 4.7 按比例推算）：</p><ul><li><strong>普通 input</strong>：$3.00 &#x2F; MTok</li><li><strong>cache write（5 分钟 TTL）</strong>：$3.75 &#x2F; MTok（比普通贵 25%）</li><li><strong>cache write（1 小时 TTL）</strong>：$6.00 &#x2F; MTok（比普通贵 100%）</li><li><strong>cache read</strong>：$0.30 &#x2F; MTok（是普通的 1&#x2F;10）</li><li><strong>output</strong>：$15.00 &#x2F; MTok（这个不受影响）</li></ul><p>读到这里你应该明白 Prompt Caching 的”生意逻辑”了——<strong>写入要额外多花钱，但读取便宜到惊人</strong>。关键问题是：<strong>你得读几次才划算？</strong></p><p>算一下：以 5 分钟 TTL 为例，假设有 100K token 的 context。</p><ul><li>不缓存：每次都花 $0.30，100 次就是 $30</li><li>用缓存：第一次写入 $0.375，后面 99 次每次 $0.03，总共 $0.375 + $2.97 &#x3D; $3.345</li></ul><p>也就是 **100 次调用省了 89%<strong>。但是——</strong>如果你只调用 1 次，反而多花了 25%**。这就是为什么 Prompt Caching 不是无脑开就好的。</p><p>我自己总结的一个记忆点是：<strong>2 次命中就回本</strong>。</p><ul><li>1 次 write + 1 次 read &#x3D; $0.375 + $0.03 &#x3D; $0.405</li><li>2 次普通 &#x3D; $0.60</li><li>**省 33%**，够本还有赚</li></ul><p>也就是说，只要你这段上下文在 5 分钟内至少会被读到 2 次，缓存就值得开。这个阈值极低，<strong>99% 的生产场景都能达到</strong>。</p><h2 id="二、5-分钟-TTL-和-1-小时-TTL-怎么选"><a href="#二、5-分钟-TTL-和-1-小时-TTL-怎么选" class="headerlink" title="二、5 分钟 TTL 和 1 小时 TTL 怎么选"></a>二、5 分钟 TTL 和 1 小时 TTL 怎么选</h2><p>这是另一个容易被忽略的决策。</p><p>5 分钟 TTL 是<strong>默认</strong>的。它的逻辑是：每次成功命中，TTL 会被”续期”回 5 分钟。所以只要你的请求间隔不超过 5 分钟，这个缓存可以一直活着。</p><p>1 小时 TTL 是<strong>付费</strong>的——写入贵一倍。它的适用场景很具体：<strong>两次请求之间间隔会超过 5 分钟，但不会超过 1 小时</strong>。</p><p>实际项目里我这么判断：</p><ul><li><strong>聊天机器人场景</strong>：5 分钟绝对够，用户跑来跑去发消息，5 分钟之内大概率会有下一条</li><li><strong>批量处理 job</strong>：看批量的节奏。如果是 1 分钟一批，5 分钟足够；如果是半小时跑一次，用 1 小时 TTL 更划算</li><li><strong>客服工单 &#x2F; 低频查询</strong>：1 小时 TTL 合适，因为用户第二次问可能间隔几十分钟</li><li><strong>一次性任务</strong>：别用缓存，纯粹浪费那 25% 的写入溢价</li></ul><p><strong>有个反直觉的坑</strong>：不要觉得”1 小时肯定比 5 分钟保险”。1 小时 TTL 写入贵一倍，如果你的实际命中率不高，<strong>多花的写入钱会吃掉所有省的读取钱</strong>。我在一个项目上吃过这个亏——当时怕 cache miss 把 TTL 都设成 1 小时，结果实际命中率只有 35%，账单比 5 分钟 TTL 版本还贵了 40%。</p><h2 id="三、cache-control-到底放哪里"><a href="#三、cache-control-到底放哪里" class="headerlink" title="三、cache_control 到底放哪里"></a>三、cache_control 到底放哪里</h2><p>这是实操里最容易错的地方。Anthropic 的 API 要求你在<strong>请求体里用 <code>cache_control: &#123;&quot;type&quot;: &quot;ephemeral&quot;&#125;</code> 标记出哪些是要缓存的 block</strong>。但放的位置大有讲究。</p><p>核心规则只有一条：<strong>缓存从请求最开始一直延伸到标记位置</strong>。你标记的是”这段之前的所有内容都要缓存”的结束点。</p><p>举个例子，假设你的请求是这样结构：</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu 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><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">[system prompt: 2K]</span><br><span class="line">[大段文档 A: 50K]</span><br><span class="line">[大段文档 B: 30K]</span><br><span class="line">[用户当前的问题: 200]</span><br></pre></td></tr></table></figure></div><p>你要问自己：<strong>哪些部分是多次请求之间不变的？</strong></p><p>如果文档 A 是每次调用都一样的（比如产品手册），文档 B 也是，只有用户问题在变，那就在文档 B 末尾打标记：</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><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">messages = [</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="string">&quot;role&quot;</span>: <span class="string">&quot;user&quot;</span>,</span><br><span class="line">        <span class="string">&quot;content&quot;</span>: [</span><br><span class="line">            &#123;<span class="string">&quot;type&quot;</span>: <span class="string">&quot;text&quot;</span>, <span class="string">&quot;text&quot;</span>: <span class="string">&quot;&lt;manual&gt;...文档A...&lt;/manual&gt;&quot;</span>&#125;,</span><br><span class="line">            &#123;<span class="string">&quot;type&quot;</span>: <span class="string">&quot;text&quot;</span>, <span class="string">&quot;text&quot;</span>: <span class="string">&quot;&lt;policy&gt;...文档B...&lt;/policy&gt;&quot;</span>,</span><br><span class="line">             <span class="string">&quot;cache_control&quot;</span>: &#123;<span class="string">&quot;type&quot;</span>: <span class="string">&quot;ephemeral&quot;</span>&#125;&#125;,</span><br><span class="line">            &#123;<span class="string">&quot;type&quot;</span>: <span class="string">&quot;text&quot;</span>, <span class="string">&quot;text&quot;</span>: <span class="string">&quot;用户问题：&#123;question&#125;&quot;</span>&#125;</span><br><span class="line">        ]</span><br><span class="line">    &#125;</span><br><span class="line">]</span><br></pre></td></tr></table></figure></div><p>system prompt 单独也可以标，这里不展开。</p><p><strong>最多可以标 4 个缓存断点</strong>。这在”部分变部分不变”的场景特别有用。比如：</p><ul><li>断点 1：system prompt（永远不变）</li><li>断点 2：用户档案（同一用户之内不变）</li><li>断点 3：会话历史前 N 轮（每轮往后推）</li><li>断点 4：当前轮工具调用结果</li></ul><p>这种多断点设计我在做长会话 Agent 的时候用过，命中率能拉到 75% 以上。</p><h2 id="四、什么样的请求适合缓存"><a href="#四、什么样的请求适合缓存" class="headerlink" title="四、什么样的请求适合缓存"></a>四、什么样的请求适合缓存</h2><p>不是所有 API 请求都值得开缓存。我总结了三个适合的场景：</p><p><strong>第一，大段静态上下文 + 小段动态输入</strong>。典型代表是文档问答——每次上下文都是那几万字的手册，只有用户问题在变。这种场景缓存命中率天然就高。</p><p><strong>第二，多轮对话</strong>。只要你的对话超过 3-4 轮，前面的历史 + system prompt 缓存起来就能省很多。我一个做客服机器人的朋友，把这个开了之后月账单从 $1800 降到 $460。</p><p><strong>第三，批量并行调用</strong>。比如同一个 prompt 模板，不同的用户数据并行跑一百份。第一个请求写入缓存，后面 99 个全是 cache hit，省钱爽到飞起。</p><p><strong>不适合缓存的场景</strong>也要明确：</p><ul><li>上下文每次都变（比如每个请求都是独立的短问答）</li><li>context 太短（低于 1024 token，Anthropic 有最小缓存长度限制）</li><li>高度敏感的数据不想留在服务端缓存里（虽然官方文档说缓存是隔离的，但合规要求严格的场景自己判断）</li></ul><h2 id="五、一个真实的-before-after-账单对比"><a href="#五、一个真实的-before-after-账单对比" class="headerlink" title="五、一个真实的 before&#x2F;after 账单对比"></a>五、一个真实的 before&#x2F;after 账单对比</h2><p>回到开头那个 PDF 处理项目。我把优化前后的数据摊开：</p><p><strong>优化前（每份 PDF 一次独立请求）：</strong></p><ul><li>每份 PDF 平均 context 40K token</li><li>每天 3000 份</li><li>每天 input 消耗：12000 万 token（120M）</li><li>日账单：约 120 × $3 &#x3D; $360（实际因为输出 token，综合算下来 $110 左右按入口看）</li></ul><p><strong>优化后（相同的抽取模板用 caching）：</strong></p><ul><li>system prompt + 抽取规范（约 8K token）整段缓存</li><li>每份 PDF 的正文还是要现读（不能缓存，因为每份不一样）</li><li>缓存命中率：~95%</li><li>日账单：$18</li></ul><p>省了 83%。客户爽到直接给我加了一个模块的单。</p><p>这个数字的前提是我做了两件事：</p><ol><li><strong>把所有”跨请求不变的”部分整合到 prompt 前半段</strong>。很多人一开始把”当前这份 PDF 内容”放在最前面，这样根本没法缓存——小改动</li><li><strong>用 5 分钟 TTL，因为 3000 份 PDF 基本是 7x24 在跑，请求间隔远小于 5 分钟</strong></li></ol><h2 id="六、最后几个实操建议"><a href="#六、最后几个实操建议" class="headerlink" title="六、最后几个实操建议"></a>六、最后几个实操建议</h2><ol><li><strong>上线前先看 cache 命中率</strong>。Anthropic API 返回里有 <code>cache_read_input_tokens</code> 和 <code>cache_creation_input_tokens</code> 两个字段，监控这俩就知道缓存是不是真的在工作</li><li><strong>不要过度设计</strong>。一开始只标一个断点就行，跑起来有数据之后再看要不要加</li><li><strong>注意模型版本切换会让缓存失效</strong>。从 Sonnet 4.5 升到 4.6 的时候，所有缓存都要重建。这时候预热缓存的成本别忘了算</li><li><strong>本地调试先别开缓存</strong>。测试阶段频繁改 prompt，开了反而浪费写入费用</li></ol><p>Prompt Caching 说白了就是把”重复的 context 只付一次近似全价，之后打 1 折”。这事儿技术上不难，但<strong>很多人根本没去看文档</strong>，默认就用普通 API。我在 <a href="/categories/">Claude API 知识地图</a> 里看到这块的关注度其实不高，大部分人还停留在”换模型省钱”的层面——其实单是把 Prompt Caching 开好，省的钱就比换模型多得多。</p><p>降本这件事，<a class="link"   href="https://www.cocoloop.cn/" >cocoloop.cn<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 主站之前整理过一批案例，如果你想系统了解 AI 应用的成本优化路径，可以去翻翻。</p><div class="cta-card">  <div class="cta-title">🚀 想深挖更多成本优化技巧？</div>  <div class="cta-desc">本站持续更新 Claude API 成本优化实战。想看更多 AI 一手资讯，推荐访问 <a class="link"   href="https://news.cocoloop.cn/" >news.cocoloop.cn<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>；想看 API 相关问答，可以去 <a class="link"   href="https://ask.cocoloop.cn/" >ask.cocoloop.cn<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>。</div></div>]]>
    </content>
    <id>https://claude.cocoloop.cn/posts/prompt-caching-deep-guide/</id>
    <link href="https://claude.cocoloop.cn/posts/prompt-caching-deep-guide/"/>
    <published>2026-04-02T01:15:00.000Z</published>
    <summary>Prompt Caching 是我用 Claude API 这一年里降本效果最猛的单点优化。这篇把价格结构、TTL 选择、cache_control 放哪里、before/after 账单全部摊开讲一遍，踩过的坑也一并交代。</summary>
    <title>Prompt Caching 保姆级教程：2 次命中就回本的隐藏省钱技巧</title>
    <updated>2026-04-17T08:40:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Claude 中文知识站</name>
    </author>
    <category term="Tool与MCP" scheme="https://claude.cocoloop.cn/categories/Tool%E4%B8%8EMCP/"/>
    <category term="Python" scheme="https://claude.cocoloop.cn/tags/Python/"/>
    <category term="MCP" scheme="https://claude.cocoloop.cn/tags/MCP/"/>
    <category term="FastMCP" scheme="https://claude.cocoloop.cn/tags/FastMCP/"/>
    <category term="企业落地" scheme="https://claude.cocoloop.cn/tags/%E4%BC%81%E4%B8%9A%E8%90%BD%E5%9C%B0/"/>
    <content>
      <![CDATA[<p>说实话这事儿是被运营部门逼出来的。</p><p>我们公司有个内部订单系统，MySQL 库里挂着几千万行数据。运营组的小姑娘几乎每天都要问技术：”帮我查一下昨天 XX 渠道的退款单数””帮我拉一下 3 月 GMV 按城市分组”。一开始还好，后来一天能来十几次，我们这边排期排不过来，她那边也急，经常下班前还在等一张报表。</p><p>上个月我心一横，花了一个下午给她搭了个 MCP Server，直接让 Claude Desktop 接到内网 MySQL 上。现在她自己用自然语言问，Claude 帮她写 SQL、跑 SQL、甚至画个简单的 Markdown 表格出来。这篇想把整个过程完整写一遍——不是教科书式的”hello world”，是真真正正上了生产、正在跑的那版。</p><h2 id="一、为什么选-MCP，不选-Function-Calling"><a href="#一、为什么选-MCP，不选-Function-Calling" class="headerlink" title="一、为什么选 MCP，不选 Function Calling"></a>一、为什么选 MCP，不选 Function Calling</h2><p>先澄清一个事儿。这个需求技术上确实可以用 Function Calling 直接做——写个 Python 脚本，调 Claude API，把 execute_sql 定义成一个 tool，让模型生成 SQL 然后你本地执行。我一开始也是这么想的。</p><p>但有几个问题绕不开：</p><ul><li>运营小姑娘不是程序员，她用的是 Claude Desktop 客户端，不可能让她打开终端跑你的脚本</li><li>公司之后还要接第二个工具（查 CRM）、第三个工具（发企业微信通知），每加一个都得改脚本</li><li>权限控制散在代码里，谁能查什么表、哪些字段要脱敏，改一次要重新部署</li></ul><p>MCP 正好解决这几件事。它是<strong>协议层</strong>的东西，Server 一次写好，任何支持 MCP 的客户端都能接——Claude Desktop、Cursor、Continue、Cline，甚至自研的 Agent。关于 MCP 和 Function Calling 到底差在哪，我在 <a href="/categories/Tool%E4%B8%8EMCP/">Tool与MCP 分类</a> 里还有一篇专门拆过，这里就不展开了。</p><h2 id="二、技术栈选型：为什么是-FastMCP"><a href="#二、技术栈选型：为什么是-FastMCP" class="headerlink" title="二、技术栈选型：为什么是 FastMCP"></a>二、技术栈选型：为什么是 FastMCP</h2><p>Anthropic 官方 SDK 是 <code>mcp</code> 这个包，能用但偏底层，你得自己处理 JSON-RPC 的细节。社区里有个叫 FastMCP 的封装，用起来就跟写 Flask 差不多，一个装饰器搞定一个 tool。生产项目我一律用 FastMCP，开发效率差了不止一个量级。</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pip install fastmcp pymysql python-dotenv</span><br></pre></td></tr></table></figure></div><p>就这么简单。Python 3.10+ 就行。</p><h2 id="三、最小可运行版本：20-行代码接通数据库"><a href="#三、最小可运行版本：20-行代码接通数据库" class="headerlink" title="三、最小可运行版本：20 行代码接通数据库"></a>三、最小可运行版本：20 行代码接通数据库</h2><p>先上最原始的版本，让整个链路跑通：</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><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></pre></td><td class="code"><pre><span class="line"><span class="comment"># server.py</span></span><br><span class="line"><span class="keyword">import</span> os</span><br><span class="line"><span class="keyword">import</span> pymysql</span><br><span class="line"><span class="keyword">from</span> fastmcp <span class="keyword">import</span> FastMCP</span><br><span class="line"><span class="keyword">from</span> dotenv <span class="keyword">import</span> load_dotenv</span><br><span class="line"></span><br><span class="line">load_dotenv()</span><br><span class="line">mcp = FastMCP(<span class="string">&quot;internal-sql&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">get_conn</span>():</span><br><span class="line">    <span class="keyword">return</span> pymysql.connect(</span><br><span class="line">        host=os.getenv(<span class="string">&quot;DB_HOST&quot;</span>),</span><br><span class="line">        user=os.getenv(<span class="string">&quot;DB_USER&quot;</span>),</span><br><span class="line">        password=os.getenv(<span class="string">&quot;DB_PASS&quot;</span>),</span><br><span class="line">        database=os.getenv(<span class="string">&quot;DB_NAME&quot;</span>),</span><br><span class="line">        charset=<span class="string">&quot;utf8mb4&quot;</span>,</span><br><span class="line">        cursorclass=pymysql.cursors.DictCursor,</span><br><span class="line">    )</span><br><span class="line"></span><br><span class="line"><span class="meta">@mcp.tool()</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">query_sql</span>(<span class="params">sql: <span class="built_in">str</span></span>) -&gt; <span class="built_in">list</span>[<span class="built_in">dict</span>]:</span><br><span class="line">    <span class="string">&quot;&quot;&quot;执行只读 SQL 查询，返回结果行列表&quot;&quot;&quot;</span></span><br><span class="line">    <span class="keyword">with</span> get_conn() <span class="keyword">as</span> conn:</span><br><span class="line">        <span class="keyword">with</span> conn.cursor() <span class="keyword">as</span> cur:</span><br><span class="line">            cur.execute(sql)</span><br><span class="line">            <span class="keyword">return</span> cur.fetchall()</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">&quot;__main__&quot;</span>:</span><br><span class="line">    mcp.run()</span><br></pre></td></tr></table></figure></div><p>配上 <code>.env</code>：</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu 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><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">DB_HOST=10.0.1.15</span><br><span class="line">DB_USER=readonly_bot</span><br><span class="line">DB_PASS=xxx</span><br><span class="line">DB_NAME=orders</span><br></pre></td></tr></table></figure></div><p>在 Claude Desktop 的配置文件里加一段（Mac 是 <code>~/Library/Application Support/Claude/claude_desktop_config.json</code>）：</p><div class="code-container" data-rel="Json"><figure class="iseeu 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;mcpServers&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;internal-sql&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;command&quot;</span><span class="punctuation">:</span> <span class="string">&quot;python&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;args&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;/path/to/server.py&quot;</span><span class="punctuation">]</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></div><p>重启 Claude Desktop，你就能在输入框看到一个小锤子图标，里面有 <code>query_sql</code> 这个工具。问它”帮我查最近 7 天退款最多的前 10 个订单”，它就会自己写 SQL 调用 tool，然后把结果整理成表格给你。</p><p>这一版能跑，但<strong>离生产还差十万八千里</strong>。下面是我真实踩过的坑。</p><h2 id="四、坑一：权限——这玩意儿敢不敢让-Claude-随便写-SQL"><a href="#四、坑一：权限——这玩意儿敢不敢让-Claude-随便写-SQL" class="headerlink" title="四、坑一：权限——这玩意儿敢不敢让 Claude 随便写 SQL"></a>四、坑一：权限——这玩意儿敢不敢让 Claude 随便写 SQL</h2><p>这是我第一版上线当天就翻车的地方。</p><p>Claude 很聪明，但它不知道你公司的”业务约束”。运营小姑娘问了一句”把测试订单都删掉”，它还真就写了个 <code>DELETE FROM orders WHERE ...</code>。还好我当时用的是只读账号，SQL 执行直接报了权限错误。</p><p>教训是三层防御一个都不能少：</p><p><strong>第一层，数据库账号只给 SELECT 权限</strong>。这是地板，永远不能塌。</p><div class="code-container" data-rel="Sql"><figure class="iseeu 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></pre></td><td class="code"><pre><span class="line"><span class="keyword">CREATE</span> <span class="keyword">USER</span> <span class="string">&#x27;readonly_bot&#x27;</span>@<span class="string">&#x27;%&#x27;</span> IDENTIFIED <span class="keyword">BY</span> <span class="string">&#x27;xxx&#x27;</span>;</span><br><span class="line"><span class="keyword">GRANT</span> <span class="keyword">SELECT</span> <span class="keyword">ON</span> orders.<span class="operator">*</span> <span class="keyword">TO</span> <span class="string">&#x27;readonly_bot&#x27;</span>@<span class="string">&#x27;%&#x27;</span>;</span><br><span class="line"><span class="comment">-- 敏感表直接不给</span></span><br><span class="line"><span class="keyword">REVOKE</span> <span class="keyword">SELECT</span> <span class="keyword">ON</span> orders.user_identity <span class="keyword">FROM</span> <span class="string">&#x27;readonly_bot&#x27;</span>@<span class="string">&#x27;%&#x27;</span>;</span><br></pre></td></tr></table></figure></div><p><strong>第二层，代码里白名单校验 SQL</strong>。用 <code>sqlparse</code> 解析，只允许 SELECT：</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> sqlparse</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">is_readonly</span>(<span class="params">sql: <span class="built_in">str</span></span>) -&gt; <span class="built_in">bool</span>:</span><br><span class="line">    parsed = sqlparse.parse(sql)</span><br><span class="line">    <span class="keyword">if</span> <span class="keyword">not</span> parsed:</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">False</span></span><br><span class="line">    stmt_type = parsed[<span class="number">0</span>].get_type()</span><br><span class="line">    <span class="keyword">return</span> stmt_type == <span class="string">&quot;SELECT&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="meta">@mcp.tool()</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">query_sql</span>(<span class="params">sql: <span class="built_in">str</span></span>) -&gt; <span class="built_in">list</span>[<span class="built_in">dict</span>]:</span><br><span class="line">    <span class="keyword">if</span> <span class="keyword">not</span> is_readonly(sql):</span><br><span class="line">        <span class="keyword">raise</span> ValueError(<span class="string">&quot;仅支持 SELECT 查询&quot;</span>)</span><br><span class="line">    <span class="comment"># ... 原逻辑</span></span><br></pre></td></tr></table></figure></div><p><strong>第三层，敏感字段在返回层脱敏</strong>。手机号、身份证、邮箱这类东西，数据库里有，但返回给 Claude 之前要处理：</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><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">SENSITIVE_COLS = &#123;<span class="string">&quot;phone&quot;</span>, <span class="string">&quot;id_card&quot;</span>, <span class="string">&quot;email&quot;</span>&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">mask_row</span>(<span class="params">row: <span class="built_in">dict</span></span>) -&gt; <span class="built_in">dict</span>:</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">        k: (v[:<span class="number">3</span>] + <span class="string">&quot;****&quot;</span> + v[-<span class="number">2</span>:] <span class="keyword">if</span> k <span class="keyword">in</span> SENSITIVE_COLS <span class="keyword">and</span> <span class="built_in">isinstance</span>(v, <span class="built_in">str</span>) <span class="keyword">and</span> <span class="built_in">len</span>(v) &gt; <span class="number">5</span> <span class="keyword">else</span> v)</span><br><span class="line">        <span class="keyword">for</span> k, v <span class="keyword">in</span> row.items()</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure></div><p>这三层加起来，运营组再怎么折腾也不会把线上数据搞挂。</p><h2 id="五、坑二：超时——大表一跑就卡死整个-Claude"><a href="#五、坑二：超时——大表一跑就卡死整个-Claude" class="headerlink" title="五、坑二：超时——大表一跑就卡死整个 Claude"></a>五、坑二：超时——大表一跑就卡死整个 Claude</h2><p>早期版本我没做超时控制。结果有一次她问”把去年所有订单按用户维度聚合”，Claude 写了个没加 LIMIT 的聚合 SQL，直接把 MCP Server 卡住了 40 秒。Claude Desktop 那边超时断开，整个会话都崩了。</p><p>修复方案两步走：</p><p><strong>数据库层加 max_execution_time</strong>：</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><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">@mcp.tool()</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">query_sql</span>(<span class="params">sql: <span class="built_in">str</span>, limit: <span class="built_in">int</span> = <span class="number">1000</span></span>) -&gt; <span class="built_in">list</span>[<span class="built_in">dict</span>]:</span><br><span class="line">    <span class="keyword">if</span> <span class="keyword">not</span> is_readonly(sql):</span><br><span class="line">        <span class="keyword">raise</span> ValueError(<span class="string">&quot;仅支持 SELECT 查询&quot;</span>)</span><br><span class="line">    <span class="keyword">with</span> get_conn() <span class="keyword">as</span> conn:</span><br><span class="line">        <span class="keyword">with</span> conn.cursor() <span class="keyword">as</span> cur:</span><br><span class="line">            cur.execute(<span class="string">&quot;SET SESSION MAX_EXECUTION_TIME=10000&quot;</span>)  <span class="comment"># 10 秒</span></span><br><span class="line">            <span class="keyword">if</span> <span class="string">&quot;limit&quot;</span> <span class="keyword">not</span> <span class="keyword">in</span> sql.lower():</span><br><span class="line">                sql = <span class="string">f&quot;SELECT * FROM (<span class="subst">&#123;sql&#125;</span>) t LIMIT <span class="subst">&#123;limit&#125;</span>&quot;</span></span><br><span class="line">            cur.execute(sql)</span><br><span class="line">            <span class="keyword">return</span> [mask_row(r) <span class="keyword">for</span> r <span class="keyword">in</span> cur.fetchall()]</span><br></pre></td></tr></table></figure></div><p><strong>行数上限硬编码</strong>。Claude 要是真给你返回 10 万行，上下文就爆了。默认 1000 行，需要更多的话让用户显式传参。</p><h2 id="六、坑三：日志——出了事儿要能复盘"><a href="#六、坑三：日志——出了事儿要能复盘" class="headerlink" title="六、坑三：日志——出了事儿要能复盘"></a>六、坑三：日志——出了事儿要能复盘</h2><p>这个是我朋友血泪教训。他们那边有次数据被疑似”泄露”，老板要追查每一次查询，但 MCP Server 完全没打日志，只好翻 MySQL 的 general log，工作量巨大。</p><p>我的做法是每次调用都打结构化日志，包括 SQL、调用方、执行时间、返回行数：</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> logging</span><br><span class="line"><span class="keyword">import</span> json</span><br><span class="line"><span class="keyword">import</span> time</span><br><span class="line"><span class="keyword">from</span> pathlib <span class="keyword">import</span> Path</span><br><span class="line"></span><br><span class="line">log_path = Path(<span class="string">&quot;/var/log/mcp-sql/audit.log&quot;</span>)</span><br><span class="line">log_path.parent.mkdir(parents=<span class="literal">True</span>, exist_ok=<span class="literal">True</span>)</span><br><span class="line"></span><br><span class="line">audit = logging.getLogger(<span class="string">&quot;audit&quot;</span>)</span><br><span class="line">audit.addHandler(logging.FileHandler(log_path))</span><br><span class="line">audit.setLevel(logging.INFO)</span><br><span class="line"></span><br><span class="line"><span class="meta">@mcp.tool()</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">query_sql</span>(<span class="params">sql: <span class="built_in">str</span>, limit: <span class="built_in">int</span> = <span class="number">1000</span></span>) -&gt; <span class="built_in">list</span>[<span class="built_in">dict</span>]:</span><br><span class="line">    t0 = time.time()</span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        <span class="keyword">if</span> <span class="keyword">not</span> is_readonly(sql):</span><br><span class="line">            <span class="keyword">raise</span> ValueError(<span class="string">&quot;仅支持 SELECT 查询&quot;</span>)</span><br><span class="line">        <span class="comment"># ... 执行</span></span><br><span class="line">        elapsed = time.time() - t0</span><br><span class="line">        audit.info(json.dumps(&#123;</span><br><span class="line">            <span class="string">&quot;ts&quot;</span>: <span class="built_in">int</span>(t0),</span><br><span class="line">            <span class="string">&quot;sql&quot;</span>: sql,</span><br><span class="line">            <span class="string">&quot;rows&quot;</span>: <span class="built_in">len</span>(result),</span><br><span class="line">            <span class="string">&quot;ms&quot;</span>: <span class="built_in">int</span>(elapsed * <span class="number">1000</span>),</span><br><span class="line">            <span class="string">&quot;status&quot;</span>: <span class="string">&quot;ok&quot;</span>,</span><br><span class="line">        &#125;, ensure_ascii=<span class="literal">False</span>))</span><br><span class="line">        <span class="keyword">return</span> result</span><br><span class="line">    <span class="keyword">except</span> Exception <span class="keyword">as</span> e:</span><br><span class="line">        audit.info(json.dumps(&#123;</span><br><span class="line">            <span class="string">&quot;ts&quot;</span>: <span class="built_in">int</span>(t0),</span><br><span class="line">            <span class="string">&quot;sql&quot;</span>: sql,</span><br><span class="line">            <span class="string">&quot;status&quot;</span>: <span class="string">&quot;error&quot;</span>,</span><br><span class="line">            <span class="string">&quot;error&quot;</span>: <span class="built_in">str</span>(e),</span><br><span class="line">        &#125;, ensure_ascii=<span class="literal">False</span>))</span><br><span class="line">        <span class="keyword">raise</span></span><br></pre></td></tr></table></figure></div><p>日志按天切，配合 Loki 或者直接 grep，出事追责分分钟。</p><h2 id="七、Docker-化：让它能在公司服务器上稳定跑"><a href="#七、Docker-化：让它能在公司服务器上稳定跑" class="headerlink" title="七、Docker 化：让它能在公司服务器上稳定跑"></a>七、Docker 化：让它能在公司服务器上稳定跑</h2><p>本地跑是给自己用的，上生产给全运营组用就得容器化。Dockerfile 非常朴素：</p><div class="code-container" data-rel="Dockerfile"><figure class="iseeu 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></pre></td><td class="code"><pre><span class="line"><span class="keyword">FROM</span> python:<span class="number">3.11</span>-slim</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 class="keyword">COPY</span><span class="language-bash"> requirements.txt .</span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> pip install --no-cache-dir -r requirements.txt</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">COPY</span><span class="language-bash"> server.py .</span></span><br><span class="line"><span class="keyword">COPY</span><span class="language-bash"> .<span class="built_in">env</span> .</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">CMD</span><span class="language-bash"> [<span class="string">&quot;python&quot;</span>, <span class="string">&quot;server.py&quot;</span>, <span class="string">&quot;--transport&quot;</span>, <span class="string">&quot;sse&quot;</span>, <span class="string">&quot;--port&quot;</span>, <span class="string">&quot;8080&quot;</span>]</span></span><br></pre></td></tr></table></figure></div><p>MCP 官方支持两种 transport：stdio（本地进程间）和 SSE（HTTP 长连）。给团队用一定要选 SSE 模式，放内网服务器上，所有人客户端配一个 URL 就行：</p><div class="code-container" data-rel="Json"><figure class="iseeu 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;mcpServers&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;internal-sql&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;url&quot;</span><span class="punctuation">:</span> <span class="string">&quot;http://10.0.1.30:8080/sse&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></div><h2 id="八、上线之后的真实反馈"><a href="#八、上线之后的真实反馈" class="headerlink" title="八、上线之后的真实反馈"></a>八、上线之后的真实反馈</h2><p>到现在用了快一个月。运营组的使用频率：日均 40-60 次查询，高峰期一小时 20 次。我这边完全不用管了，她自己跟 Claude 聊两句就拿到数据。</p><p>有几个没预料到的好处：</p><ul><li><strong>她开始学 SQL 了</strong>。看多了 Claude 生成的 SQL，她现在自己能读懂 JOIN 和 GROUP BY</li><li><strong>需求被过滤了一轮</strong>。以前来找我们的需求十个有三个是”她想错了”，Claude 会在执行前复述一遍”你是想查 XX 对吧？”，经常她就发现自己问反了</li><li><strong>跨部门传播</strong>。财务组听说了，现在在催我给她们也搞一个</li></ul><p>下一步我打算把 CRM 客户查询、企业微信消息推送也做成 MCP Tool，塞进同一个 Server。想了解更多 MCP 实战案例的话，可以去 <a class="link"   href="https://openclaw.cocoloop.cn/" >openclaw.cocoloop.cn<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 看看，那边有更多开源项目的分享。如果你对 Claude 在企业内部的深度集成感兴趣，<a class="link"   href="https://claudecode.cocoloop.cn/" >claudecode.cocoloop.cn<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 也有不少相关内容。</p><p>写到这里差不多把我知道的坑都倒完了。MCP 这东西说难不难，三十分钟确实能跑起来；说简单也不简单，真要用在生产上，权限、超时、日志、脱敏，每一环都得踩一遍才放心。</p><div class="cta-card">  <div class="cta-title">给 Claude 装上公司数据的翅膀</div>  <div class="cta-desc">更多 MCP 生态进展和企业落地案例，可以关注 <a class="link"   href="https://news.cocoloop.cn/" >news.cocoloop.cn<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>，也欢迎去 <a class="link"   href="https://ask.cocoloop.cn/" >ask.cocoloop.cn<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 提问交流实战问题。</div></div>]]>
    </content>
    <id>https://claude.cocoloop.cn/posts/mcp-server-internal-tools/</id>
    <link href="https://claude.cocoloop.cn/posts/mcp-server-internal-tools/"/>
    <published>2026-03-28T06:20:00.000Z</published>
    <summary>真实场景实战：给团队搭一个能让 Claude 查内网 MySQL 的 MCP Server。Python FastMCP 三十分钟跑起来，讲清权限、Docker、超时、日志这些上生产前必须踩的坑。</summary>
    <title>30 分钟手搓一个 MCP Server，让 Claude 直接查公司内网 SQL</title>
    <updated>2026-04-12T01:15:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Claude 中文知识站</name>
    </author>
    <category term="Prompt工程" scheme="https://claude.cocoloop.cn/categories/Prompt%E5%B7%A5%E7%A8%8B/"/>
    <category term="Prompt工程" scheme="https://claude.cocoloop.cn/tags/Prompt%E5%B7%A5%E7%A8%8B/"/>
    <category term="Context Engineering" scheme="https://claude.cocoloop.cn/tags/Context-Engineering/"/>
    <category term="Agent" scheme="https://claude.cocoloop.cn/tags/Agent/"/>
    <category term="工程实践" scheme="https://claude.cocoloop.cn/tags/%E5%B7%A5%E7%A8%8B%E5%AE%9E%E8%B7%B5/"/>
    <content>
      <![CDATA[<p>说一个让我自己有点尴尬的事。2023 年那会儿，我在公司内部做过一场分享，题目叫《Prompt Engineering 十二招》，里面讲的全是些”你是一个资深 XX””请一步一步思考””输出格式如下”这种现在看起来挺初级的东西。当时还挺受欢迎，后来这套 slides 还被隔壁部门借去讲过两次。</p><p>到了 2025 年下半年做 Agent 项目的时候，我突然发现那套思路彻底不够用了——我可以把单次请求的 prompt 调到完美，但 Agent 跑几十轮之后照样翻车；我可以给模型写一个漂亮的 system prompt，但真正决定它表现的是每一步我<strong>塞给它的上下文</strong>。</p><p>这时候我才反应过来：<strong>过去两年大家琢磨的 “Prompt Engineering”，其实只是 “Context Engineering” 的一个子集</strong>，而且是最小的那一块。</p><p>这篇我把自己这一年半从 Prompt 调教转向 Context 工程的思路转变讲清楚，以及我现在实际在用的四个支柱：Writing、Selection、Compression、Isolation。</p><h2 id="一、Prompt-Engineering-的天花板在哪"><a href="#一、Prompt-Engineering-的天花板在哪" class="headerlink" title="一、Prompt Engineering 的天花板在哪"></a>一、Prompt Engineering 的天花板在哪</h2><p>先回到起点。Prompt Engineering 解决的问题是：<strong>同样的模型、同样的输入数据，换个问法就能让输出质量差一倍</strong>。这个观察本身没错，现在也依然成立。</p><p>但它有两个死穴：</p><p><strong>第一个死穴：单轮视角</strong>。<br>Prompt Engineering 的训练场是 ChatGPT 这种对话框——我说一句，它回一句，我觉得不好，我改 prompt，再问一句。这套方法在<strong>信息已经齐全</strong>的场景下非常有效。但一旦进入 Agent、进入多轮、进入工具调用，你会发现模型表现好不好，已经不是”这句话怎么说”决定的了，而是”<strong>前面那 30 轮对话里它看到了什么</strong>“决定的。</p><p><strong>第二个死穴：把模型当成一个黑箱说服对象</strong>。<br>Prompt Engineering 的潜台词是”我得用某种魔法咒语哄着模型好好干活”。但模型本质上是一个函数 <code>f(context) -&gt; output</code>，它产出什么完全取决于你输入给它的 context。与其琢磨怎么把一句话说得更花，不如琢磨怎么把整个 context 组织得更好。</p><p>我自己的顿悟时刻是一次 debug——Agent 在第 25 轮突然开始胡说八道，我一开始以为是模型幻觉，仔细看日志才发现，它的 context 里已经有 180K token 了，其中 90% 是无关的旧工具调用结果，真正有用的信息被淹没在噪声里。<strong>这不是 prompt 的问题，这是 context 管理的问题</strong>。</p><p>还有一个更微妙的问题：Prompt Engineering 时代大家比的是”谁的 prompt 更巧”，结果是大家都在卷单 prompt 的极限，忽略了<strong>整个流水线的设计</strong>。真正生产级的 AI 系统，瓶颈不在于某个 prompt 能不能挤出最后 5% 的性能，而在于 context 流转的每一个环节是否稳定。这是两种完全不同的工程思维。</p><h2 id="二、Context-Engineering-的四个支柱"><a href="#二、Context-Engineering-的四个支柱" class="headerlink" title="二、Context Engineering 的四个支柱"></a>二、Context Engineering 的四个支柱</h2><p>我现在脑子里的框架是这么四块。这不是我发明的，Anthropic 和一些国外团队的分享里反复出现过这个分类，但我想用自己的项目例子讲一遍。</p><h3 id="支柱一：Writing（怎么写上下文）"><a href="#支柱一：Writing（怎么写上下文）" class="headerlink" title="支柱一：Writing（怎么写上下文）"></a>支柱一：Writing（怎么写上下文）</h3><p>这块是传统 Prompt Engineering 的地盘，但有几个新的工程化视角。</p><p><strong>Context 要分层</strong>：system 层写不变的（角色、规则），tool 层写能力，user 层写本轮输入。不要把所有东西都堆在 system prompt 里——那样 Prompt Caching 都没法用。</p><p><strong>Context 要版本化</strong>：我现在项目里的 prompt 模板都是 git 管理，每次改都要写 commit message。这听起来像废话，但<strong>你不版本化，你就没法 A&#x2F;B test，就没法回滚</strong>。</p><p><strong>Context 要分离配置和逻辑</strong>：模型叫什么名字、temperature 多少，这些是配置；”拿到用户问题后先做意图识别”这些是逻辑。两者混在一起写你会哭。</p><p><strong>Context 要有 schema 意识</strong>：与其用自然语言让模型”输出 JSON”，不如直接定义 tool schema 或用 structured output 强约束。自然语言指令越精确，说明你越没把工程学做好。</p><p>我 Claude Code 项目里的 CLAUDE.md 就是这么组织的，具体写法我在 <a href="/posts/claude-md-project-config/">《CLAUDE.md 写法大全》</a> 里讲。</p><h3 id="支柱二：Selection（选什么进上下文）"><a href="#支柱二：Selection（选什么进上下文）" class="headerlink" title="支柱二：Selection（选什么进上下文）"></a>支柱二：Selection（选什么进上下文）</h3><p>这是最关键、也最被低估的一块。</p><p>思路很朴素：<strong>模型的上下文窗口是有限的，你得选最有用的信息塞进去，而不是一股脑全扔</strong>。听起来像废话，但 90% 的 Agent 项目都没做好这件事。</p><p>我现在的业务 Agent 里，Selection 层长这样：</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">build_context</span>(<span class="params">user_query, history, tools_available</span>):</span><br><span class="line">    <span class="comment"># 1. 基于语义相似度从历史中召回相关轮次</span></span><br><span class="line">    relevant_history = semantic_search(</span><br><span class="line">        query=user_query, </span><br><span class="line">        corpus=history, </span><br><span class="line">        top_k=<span class="number">5</span></span><br><span class="line">    )</span><br><span class="line">    </span><br><span class="line">    <span class="comment"># 2. 基于意图识别选要暴露的工具（而不是全部塞进去）</span></span><br><span class="line">    intent = classify_intent(user_query)</span><br><span class="line">    tools = filter_tools_by_intent(tools_available, intent)</span><br><span class="line">    </span><br><span class="line">    <span class="comment"># 3. RAG 召回相关文档</span></span><br><span class="line">    docs = rag_retrieve(user_query, top_k=<span class="number">3</span>)</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">        <span class="string">&quot;history&quot;</span>: relevant_history,</span><br><span class="line">        <span class="string">&quot;tools&quot;</span>: tools,</span><br><span class="line">        <span class="string">&quot;docs&quot;</span>: docs</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure></div><p>几个反直觉的经验：</p><ul><li><strong>工具不是越多越好</strong>。我一开始给 Agent 塞了 40 多个 tool，发现它选错的概率很高。后来做了按意图筛选，每次只暴露 5-8 个最相关的，准确率反而上升</li><li><strong>历史不是越全越好</strong>。全量历史往里塞，模型会被早期无关的信息带偏。最近 N 轮 + 语义相关召回 K 轮，效果最好</li><li><strong>RAG 返回的 chunk 要排序</strong>。不是按 similarity score 排，是按 <strong>“模型最容易注意到”</strong> 的顺序排——最重要的放最前或最后，中间段落会被忽视（Lost in the Middle 效应）</li><li><strong>召回质量 &gt; 召回数量</strong>。很多团队一上来就把 top_k 调到 20，结果噪声一堆，精度反而变差。我现在标配是 top_k&#x3D;3~5，加一个 rerank 层</li></ul><p>还有一个务实的点——<strong>Selection 需要可观测性</strong>。你得能 log 出”这一次 context 由哪些片段组成”，出问题时才有排查线索。我在项目里搞了一个 context tracer，每次构建 context 都记录下来，debug 效率提升一倍不止。</p><h3 id="支柱三：Compression（怎么压缩）"><a href="#支柱三：Compression（怎么压缩）" class="headerlink" title="支柱三：Compression（怎么压缩）"></a>支柱三：Compression（怎么压缩）</h3><p>当 Selection 做完，你可能还是有 80K 的 context 要处理。这时候需要 Compression。</p><p>我常用的三种压缩手段：</p><p><strong>1. Summarization Cascade</strong>。<br>每 10 轮对话，用 Haiku 把前面的对话总结成 500 字以内的摘要，替换掉原文。这招在长对话场景里能把 context 压缩 90% 以上，信息损失在可接受范围。Haiku 做这种总结任务完全够用，不需要动 Sonnet。</p><p><strong>2. Structured Representation</strong>。<br>把工具调用结果从”自然语言的一大段描述”换成<strong>结构化 JSON</strong>。同样的信息，JSON 比自然语言省 50-70% 的 token。更极端的做法是把长结果 “卸载” 到外部存储，context 里只保留一个引用 ID，下次需要再读——这是 Claude 最近出的 memory tool 的核心思路。</p><p><strong>3. Prompt Caching</strong>。<br>这个严格来说不是压缩，是<strong>计费层面的压缩</strong>——固定的 context 部分命中 cache 之后，input token 成本降到 10%，等效于节省了 90% 的输入预算。Anthropic 家 cache TTL 是 5 分钟，高频 Agent 场景非常吃香。</p><p><strong>4. 选择性遗忘</strong>。<br>不是所有历史都值得保留，有些中间态（比如失败的工具调用、无效的查询尝试）对后续决策毫无帮助，可以直接从 context 里删掉。我的一个 Agent 加了这个清理逻辑之后，context 平均长度降了 40%，稳定性还提升了。</p><h3 id="支柱四：Isolation（怎么隔离上下文）"><a href="#支柱四：Isolation（怎么隔离上下文）" class="headerlink" title="支柱四：Isolation（怎么隔离上下文）"></a>支柱四：Isolation（怎么隔离上下文）</h3><p>这块是我最近才开始重视的，也是 multi-agent 架构的核心。</p><p>朴素的做法是一个 Agent 一路跑到底，所有信息都在同一个 context 里。问题是：<strong>context 会越积越脏</strong>，不同子任务的中间产物会互相干扰。</p><p>Isolation 的思路是：<strong>不同职责拆成不同 sub-agent，每个 sub-agent 有自己独立的 context</strong>，主 Agent 只拿子 Agent 的最终结论，不碰它的过程。</p><p>比如我一个 research Agent 的架构：</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu 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><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">主 Agent（规划 + 汇总）</span><br><span class="line">   │</span><br><span class="line">   ├── 搜索 sub-agent（专注搜索，自己的 context 里全是搜索结果）</span><br><span class="line">   ├── 阅读 sub-agent（专注读长文，自己的 context 里是文档原文）</span><br><span class="line">   └── 写作 sub-agent（专注组织输出，只看主 Agent 给的 brief）</span><br></pre></td></tr></table></figure></div><p>每个 sub-agent 跑完之后，主 Agent 只把<strong>精炼后的结果</strong>拉回来。这样主 Agent 的 context 始终保持干净，几十轮跑下来都不会爆。</p><p>坏处是<strong>成本会增加</strong>（多次 API 调用），好处是<strong>稳定性和可观测性大幅提升</strong>——某个 sub-agent 翻车，你只调它自己的 prompt 就行，不会影响全局。</p><p>另一个隐藏收益是<strong>可以为不同 sub-agent 选不同模型</strong>。主 Agent 需要规划能力，用 Sonnet；搜索 sub-agent 做的是结构化任务，用 Haiku；写作 sub-agent 偶尔上 Opus 做深度生成。这种混合部署比单模型跑到底要划算得多。</p><h2 id="三、这四个支柱怎么搭在一起"><a href="#三、这四个支柱怎么搭在一起" class="headerlink" title="三、这四个支柱怎么搭在一起"></a>三、这四个支柱怎么搭在一起</h2><p>实际项目里这四块不是孤立的，是一个循环：</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu 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><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">Writing（写基础 context）</span><br><span class="line">   ↓</span><br><span class="line">Selection（每轮动态挑）</span><br><span class="line">   ↓  </span><br><span class="line">Compression（太长了就压）</span><br><span class="line">   ↓</span><br><span class="line">Isolation（复杂任务分出去）</span><br><span class="line">   ↓</span><br><span class="line">新的输出又成为下一轮的 context → 回到 Selection</span><br></pre></td></tr></table></figure></div><p>我的经验是：<strong>项目早期重点投 Writing 和 Selection，中后期重点投 Compression 和 Isolation</strong>。早期你 context 不会太大，关键是搭好基础结构；跑到后面规模上来了，压缩和隔离才成为瓶颈。</p><p>另一个维度的建议：<strong>投入顺序应该匹配业务规模</strong>。日活几百的 Agent 应用，Compression 和 Prompt Caching 能省下来的钱可能还不够你写这块代码的工时。日活过万之后，这些优化的 ROI 才开始体现。</p><h2 id="四、一个常被忽视的点：Context-的”时效性”"><a href="#四、一个常被忽视的点：Context-的”时效性”" class="headerlink" title="四、一个常被忽视的点：Context 的”时效性”"></a>四、一个常被忽视的点：Context 的”时效性”</h2><p>上面讲的四个支柱都是空间维度的——怎么组织信息。但还有一个时间维度：**context 里的信息有”新鲜度”**。</p><p>举个例子：Agent 在 10 轮之前查过某用户的订单状态，当时是”已发货”。现在第 20 轮又需要这个信息，是直接从 context 里读？还是重新查？</p><p>不同场景答案不同：</p><ul><li>用户基础信息（姓名、手机号）—— 缓存住，别重复查</li><li>订单状态、库存、价格 —— 最多用 5 分钟之前的缓存，再久就得重查</li><li>实时流数据（股价、监控指标）—— 每次都要重查</li></ul><p>这种时效性管理不在 prompt 层，而是在你的工具调用和状态管理层。<strong>Context Engineering 不是纯 prompt 工程，它是系统工程</strong>。</p><h2 id="五、工具和生态"><a href="#五、工具和生态" class="headerlink" title="五、工具和生态"></a>五、工具和生态</h2><p>这套思路背后其实已经有不少成熟工具了：</p><ul><li><strong>LangGraph &#x2F; AutoGen</strong> 这类框架核心就是帮你做 Isolation</li><li><strong>LlamaIndex</strong> 的 Context 管理是典型的 Selection</li><li><strong>Anthropic Claude 家族</strong>本身 Prompt Caching 就是 Compression</li><li><strong>MCP 协议</strong>的工具发现机制可以帮你做动态 Selection</li><li><strong>OpenAI Assistants API 的 threads</strong> 某种程度上也是一种 Context 存储抽象</li></ul><p>关于 MCP 的使用细节，站内 <a href="/categories/Tool%E4%B8%8EMCP/">Tool与MCP 分类</a> 下有几篇专门的文章。想看国际上关于 Context Engineering 的更多一手讨论，可以看 <a class="link"   href="https://hermes.cocoloop.cn/" >hermes.cocoloop.cn<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 上整理的一些长文（那边偏英文内容聚合）。</p><h2 id="六、一句话总结思路转变"><a href="#六、一句话总结思路转变" class="headerlink" title="六、一句话总结思路转变"></a>六、一句话总结思路转变</h2><p>过去我面对一个 AI 应用问题，第一反应是 “<strong>我怎么改 prompt 让模型答得对</strong>“。<br>现在我的第一反应是 “<strong>我要给模型看什么它才可能答得对</strong>“。</p><p>前者是说服，后者是供给。<strong>从说服到供给，这就是 Prompt Engineering 到 Context Engineering 的本质区别</strong>。</p><p>下一个范式升级是什么？我赌是 Memory Engineering——也就是怎么让模型跨会话、跨任务地积累和调用知识。这块 Anthropic 刚出的 Memory Tool 已经在铺路了，等我试得再深一点再写。</p><p>最后给一个务实建议：<strong>如果你现在还在靠一份几百字的 system prompt 撑着业务，就别继续卷 prompt 措辞了，往 Context Engineering 方向搬</strong>。工程化投入回报比那高一个数量级。</p><div class="cta-card">  <div class="cta-title">关注 AI 工程前沿范式</div>  <div class="cta-desc">本站持续更新 Agent / Context / MCP 相关实战。想看海外 AI 前沿动态可访问 <a class="link"   href="https://news.cocoloop.cn/" >news.cocoloop.cn<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>，想看 Claude Code 相关深度内容可以去 <a class="link"   href="https://claudecode.cocoloop.cn/" >claudecode.cocoloop.cn<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>。</div></div>]]>
    </content>
    <id>https://claude.cocoloop.cn/posts/prompt-to-context-engineering/</id>
    <link href="https://claude.cocoloop.cn/posts/prompt-to-context-engineering/"/>
    <published>2026-03-28T03:40:00.000Z</published>
    <summary>我从 2023 年开始琢磨 prompt 调教，到 2025 年底彻底换了思路——重点不是怎么说，而是给什么、怎么组织、什么时候给。这篇把我理解的 Context Engineering 四个支柱用具体项目例子讲清楚。</summary>
    <title>从 Prompt Engineering 到 Context Engineering：AI 工程师的第二次范式升级</title>
    <updated>2026-04-14T08:20:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Claude 中文知识站</name>
    </author>
    <category term="Claude-Code" scheme="https://claude.cocoloop.cn/categories/Claude-Code/"/>
    <category term="Claude Code" scheme="https://claude.cocoloop.cn/tags/Claude-Code/"/>
    <category term="Cursor" scheme="https://claude.cocoloop.cn/tags/Cursor/"/>
    <category term="Cline" scheme="https://claude.cocoloop.cn/tags/Cline/"/>
    <category term="IDE" scheme="https://claude.cocoloop.cn/tags/IDE/"/>
    <category term="AI 编程" scheme="https://claude.cocoloop.cn/tags/AI-%E7%BC%96%E7%A8%8B/"/>
    <content>
      <![CDATA[<p>去年十二月我换了新电脑，重装环境的时候顺手把 Cursor、Cline（当时还叫 Claude Dev）、Claude Code CLI 三个都装上了。当时想的是挨个试一圈看哪个最顺手，没想到一试就是四个月，到今天为止三个都还在我机器里跑着，各自占据了不同的位置。</p><p>这四个月我大概写了三万行代码——两个接私活的项目、一个自己的开源玩具、公司一个中型重构。三种工具都被我当主力用过至少三周，翻车记录和真香时刻都不少。这篇文章不想搞那种”跑分表格三选一”的套路文，就聊聊我自己的切换逻辑。</p><h2 id="先说结论：我现在怎么用它们的"><a href="#先说结论：我现在怎么用它们的" class="headerlink" title="先说结论：我现在怎么用它们的"></a>先说结论：我现在怎么用它们的</h2><p>直接把结论放前面，免得有人看不下去。我现在的分工大概是这样：</p><ul><li><strong>Claude Code CLI</strong>：日常 70% 的活，尤其是需要”跨文件理解 + 改动可控”的任务</li><li><strong>Cursor</strong>：快速写新功能、起新项目、那种”白纸画图”的场景</li><li><strong>Cline</strong>：偶尔启动，专门对付那些需要”多轮自主执行”的任务，比如跑迁移脚本、批量改配置</li></ul><p>下面展开讲每个的优点、缺点、和我踩过的具体坑。</p><h2 id="一、Cursor：上手最快，但越用越有保留"><a href="#一、Cursor：上手最快，但越用越有保留" class="headerlink" title="一、Cursor：上手最快，但越用越有保留"></a>一、Cursor：上手最快，但越用越有保留</h2><p>Cursor 是我最早买年费的。说实话它的<strong>新手友好度是三个里最高的</strong>——装上就是一个魔改版 VSCode，Tab 键补全、Cmd+K 局部改、Cmd+L 聊天，三个核心交互学十分钟就会。</p><p>我用它写过一个 Next.js 的后台系统从零到上线，从体验上讲，前两周真的是”起飞”的感觉。Cursor 的 Composer 模式可以让你一句话生成一整个功能——从路由到组件到 API 都给你铺好。</p><p>但问题是<strong>它改动过于激进</strong>。</p><p>这事儿我印象特别深的一次：当时我让它帮我加一个”导出 CSV”的按钮，本来只是一个小需求，结果它一口气改了 11 个文件。里面有 3 个文件是<strong>我根本没让它动的</strong>——它觉得那些文件”为了保持一致性”也应该改一下。等我 review 的时候才发现，它顺手把我一个自定义的 hook 给重命名了，导致另外两个不相关的页面直接崩了。</p><p>这不是个例。后来我在 Cursor 社区也看到不少人反馈类似问题，它的 agent 模式特别喜欢”做得更多”。对新手来说这是优点，对有经验的开发者来说这是灾难——因为你根本不知道它背着你改了啥。</p><p>解决办法有两个：</p><ol><li>把 Cursor 的 agent 模式关掉，只用 Cmd+K 和 Tab，这样改动范围是你自己圈的</li><li>每次 commit 前必须 diff 全部过一遍，不要信任它的”概览”</li></ol><p>但这么用下来，其实等于把 Cursor 最大的卖点给阉割了。所以我慢慢就把它退到了”起新项目”这个位置——新项目没包袱，它激进也无所谓，反正还没什么东西可以被它搞坏。</p><h2 id="二、Cline：大型-repo-的噩梦"><a href="#二、Cline：大型-repo-的噩梦" class="headerlink" title="二、Cline：大型 repo 的噩梦"></a>二、Cline：大型 repo 的噩梦</h2><p>Cline 是开源的，我一开始特别喜欢它。原因是它<strong>把每一步操作都摊给你看</strong>——要读什么文件、要改什么、要跑什么命令，全部在 UI 里 approve 一次。对于”不太信任 AI”的我来说，这种透明度很舒服。</p><p>小项目上 Cline 真的很好用。我那个开源玩具（几十个文件、几千行代码）基本上是 Cline 陪我写的。它的 plan mode 会先分析问题、列一个方案，然后一步步执行。这种节奏对”有点复杂但不算太大”的任务特别合适。</p><p>但我在公司那个中型重构项目上用 Cline 的时候，彻底被劝退了。</p><p><strong>这个项目大概 1200 个文件、8 万行代码</strong>。Cline 每次启动都要扫描 repo，建索引。我一开始没注意，后来发现每次对话，它都要把相关文件塞进 context——本来还好，但它的”相关文件”判断有点粗，经常把一些八竿子打不着的文件也塞进来。</p><p>结果就是：</p><ul><li>每次 prompt 的 token 消耗飞起，一个 Sonnet 的 prompt 动不动 15K+ 起步</li><li>响应速度肉眼可见地慢，有时候要等 20 秒才开始输出</li><li>最致命的是**它读文件读到一半会”漏”**——可能是上下文管理的问题，有时候它看了 A 文件，问它 A 文件里某个函数的实现，它会一本正经地编一个出来</li></ul><p>我查了下 Cline 的 changelog，他们在 repo 索引这块一直在优化，但<strong>对几万行以上的代码库目前还是有结构性劣势</strong>。除非你愿意手动管理它能看哪些文件（比如 <code>.clineignore</code> 之类），不然大 repo 上它就是比 Cursor 和 Claude Code 要慢、要贵。</p><p>所以 Cline 现在对我来说是个”小工具”——遇到独立的、可以 scope 得很小的任务（比如写一个脚本、改一个配置文件），它的透明性真的很爽。但我不会用它做主力。</p><h2 id="三、Claude-Code-CLI：我的主力，但也不是没毛病"><a href="#三、Claude-Code-CLI：我的主力，但也不是没毛病" class="headerlink" title="三、Claude Code CLI：我的主力，但也不是没毛病"></a>三、Claude Code CLI：我的主力，但也不是没毛病</h2><p><a class="link"   href="https://claudecode.cocoloop.cn/" >Claude Code<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 是我现在 70% 时间在用的。它和前两个有个本质区别——它是<strong>CLI 工具</strong>，不是 IDE 插件。你在终端里跑它，让它在项目目录里自己读、自己改、自己跑测试。</p><p>这种设计一开始我很抗拒，觉得”没 UI 多难用啊”。用了两周之后我真香了，原因有三个：</p><p><strong>第一，它的”改动克制度”是三个里最好的</strong>。同样是加个导出按钮，Claude Code 就老老实实只改两三个相关文件，不会自作主张连带修改别的。这一点可能是因为 Anthropic 对 Sonnet 4.6 做了专门的工具调用训练，它对”任务边界”的理解比 GPT 家族更稳。</p><p><strong>第二，它的 CLAUDE.md 机制特别好用</strong>。你可以在项目根目录放一个 CLAUDE.md 写项目约定：用啥 package manager、风格偏好、某些目录不要碰、测试怎么跑。它每次启动都会读这个文件，相当于给它定制了一个”项目经理”。这招特别适合有老 repo 规范的团队。</p><p><strong>第三，它是 CLI，可以随便塞到脚本里跑</strong>。我有个 git pre-commit hook 就是调 Claude Code 做代码 review，发现问题就阻止提交。这种自动化用 IDE 插件根本做不了。</p><p>好，说几个坑。</p><p><strong>坑一：<code>--dangerously-skip-permissions</code> 到底怎么用？</strong></p><p>这个参数官方警告写得很吓人，”跳过所有权限检查”。很多人一看就不敢用，但<strong>老实说，不用这个参数，Claude Code 的体验会打七折</strong>——你会被无数个”是否允许执行 <code>npm test</code>“、”是否允许写入 <code>src/foo.ts</code>“的确认弹窗烦死。</p><p>我的实际用法是：</p><ol><li><strong>在 docker &#x2F; devcontainer 里跑</strong>。我有一个专门的 dev container，里面装好项目环境，挂载代码目录。Claude Code 加 <code>--dangerously-skip-permissions</code> 跑在里面，它再怎么 drop table 也出不了容器</li><li><strong>或者在干净的 git 仓库里跑</strong>。一切改动都在 git 里，跑完 review diff，不对就 <code>git reset --hard</code></li><li><strong>千万别在你生产 <code>~/.ssh</code> 所在的机器上直接裸跑这个参数</strong></li></ol><p>说白了，这个参数的正确打开方式是**”限制它能接触的范围”，而不是”信任它不搞事”**。容器 + git 双保险之后，我现在 99% 时间都开着这个参数，效率翻倍。</p><p><strong>坑二：长任务容易”偏航”</strong></p><p>让 Claude Code 跑一个超过一小时的任务（比如大规模重构），它偶尔会在半路上”忘记”最开始的需求，开始按自己的理解改东西。解决办法是<strong>把大任务拆成小段</strong>，每段结束让它 git commit 一次，你 review 完再继续下一段。</p><p><strong>坑三：国内网络不稳定</strong></p><p>Claude API 在国内直连时好时坏，我是接了一个香港的小 VPS 做中转。这个之前在 <a class="link"   href="https://ask.cocoloop.cn/" >ask.cocoloop.cn<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 有人问过，方案挺多的，不展开了。</p><h2 id="四、三个工具到底怎么选"><a href="#四、三个工具到底怎么选" class="headerlink" title="四、三个工具到底怎么选"></a>四、三个工具到底怎么选</h2><p>回到一开始那个问题——到底用哪个。我的建议是按<strong>场景</strong>而不是按”哪个最好”来选：</p><p><strong>如果你是完全的新手</strong>，从 Cursor 入门，它的学习曲线最友好。等你对 AI 编程的边界有感觉了，再考虑切换。</p><p><strong>如果你主要写小项目或者开源玩具</strong>，Cline 的透明性很舒服，免费版也够用，$0 起步。</p><p><strong>如果你在大型 repo 工作、追求可控性、或者想把 AI 编程嵌到 CI&#x2F;CD 里</strong>，Claude Code CLI 是目前最稳的选择。它不是最炫的，但它是<strong>最不容易让你背锅的</strong>。</p><p><strong>如果你预算够</strong>，就三个都装上，按任务切换。这听起来很折腾，但其实成本不高——这三个加起来一个月也就一两百刀，比起它们省下来的时间，这钱花得最值。</p><p>关于成本优化，我之前写过一篇关于<a href="/categories/%E6%88%90%E6%9C%AC%E4%BC%98%E5%8C%96/">成本优化</a>的总结，核心是混搭模型和用 Prompt Caching，有兴趣可以翻。</p><p>最后一句话：<strong>工具再强也是工具</strong>。我见过不少人迷信”某个工具能解决一切”，然后在一个不适合的场景上硬怼，怼到最后 AI 把项目搞烂还怪工具。AI 编程这东西，现阶段最重要的是你<strong>知道它边界在哪</strong>、<strong>知道什么时候该收手</strong>。三个工具摊开用，就是为了让你在不同边界上都有趁手的兵器。</p><div class="cta-card">  <div class="cta-title">🚀 想看更多 Claude Code 实战？</div>  <div class="cta-desc">本站持续更新 AI 编程工具对比和深度教程。想了解 Claude Code 的完整用法，可以去 <a class="link"   href="https://claudecode.cocoloop.cn/" >claudecode.cocoloop.cn<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>；想看真实用户踩坑问答，推荐去 <a class="link"   href="https://ask.cocoloop.cn/" >ask.cocoloop.cn<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>。</div></div>]]>
    </content>
    <id>https://claude.cocoloop.cn/posts/claude-code-vs-cursor-cline/</id>
    <link href="https://claude.cocoloop.cn/posts/claude-code-vs-cursor-cline/"/>
    <published>2026-03-22T06:30:00.000Z</published>
    <summary>三个 AI 编程工具轮流用了小半年，踩了不少坑。这篇不跑分不列表，只讲我真实的切换逻辑：哪些场景用哪个、每个的致命伤、以及 Claude Code 那个危险参数到底怎么用才不踩雷。</summary>
    <title>Claude Code vs Cursor vs Cline：写了三万行代码后的真实结论</title>
    <updated>2026-04-15T03:20:00.000Z</updated>
  </entry>
</feed>
