<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://hzxbzp.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://hzxbzp.github.io/" rel="alternate" type="text/html" hreflang="en" /><updated>2026-09-04T19:04:12+00:00</updated><id>https://hzxbzp.github.io/feed.xml</id><title type="html">Zhipeng Bao</title><subtitle>AI · Robotics · Autonomous Driving — Thoughts on technology and life</subtitle><author><name>Zhipeng Bao</name></author><entry xml:lang="en"><title type="html">When Answers Get Cheap: Four Things That Went Up in Price</title><link href="https://hzxbzp.github.io/blog/2026/09/when-answers-get-cheap/" rel="alternate" type="text/html" title="When Answers Get Cheap: Four Things That Went Up in Price" /><published>2026-09-04T00:00:00+00:00</published><updated>2026-09-04T00:00:00+00:00</updated><id>https://hzxbzp.github.io/blog/2026/09/when-answers-get-cheap</id><content type="html" xml:base="https://hzxbzp.github.io/blog/2026/09/when-answers-get-cheap/"><![CDATA[<p>Here’s the uncomfortable thing I’ve slowly come to accept: the part of my work I’m best at is the part that got cheap first.</p>

<p>These days I run almost everything through a model before I touch it — draft the explanation, scaffold the code, compress a forty-page report into ten lines. Most of the time what comes back is hard to fault, and it arrives faster than I could have typed the first paragraph. But there’s a category of problem it has never once solved for me, and they all share one property: <strong>the problem was never in my prompt.</strong> It was still out in the world — in a workaround someone invented to avoid the official process, in a complaint nobody wrote down.</p>

<p>So the real question isn’t “will AI replace me.” It’s this: when the price of <em>producing an answer</em> collapses, where does human value actually move?</p>

<h2 id="1-answers-are-getting-cheaper-and-you-can-see-it-in-the-data">1. Answers are getting cheaper, and you can see it in the data</h2>

<p>Stanford’s Digital Economy Lab (Brynjolfsson, Chandar, Chen) tracked ADP payroll records covering millions of US workers through June 2026. A few findings are worth copying down verbatim:</p>

<ul>
  <li><strong>There’s no evidence of widespread, economy-wide job displacement.</strong> This is not “the machines came and everyone lost their job.”</li>
  <li><strong>But workers aged 22–25 in AI-exposed occupations show about 19% lower employment</strong> than same-age peers in less exposed work. Experienced workers in the same occupations show no comparable gap.</li>
  <li><strong>The decline comes from reduced hiring, not layoffs.</strong> The door is closing slowly; nobody is being pushed through it.</li>
  <li><strong>The dividing line is substitution vs. complementarity.</strong> Occupations where AI substitutes for the work show steep declines. Occupations where it complements the worker stay flat or grow.</li>
</ul>

<p>It’s a working paper, still being revised and argued over. But it sharpens the question a lot: <strong>in my particular seat, does AI do work <em>for</em> me or <em>instead of</em> me?</strong> Those sound similar and end very differently.</p>

<p>Follow that logic and the answer falls out on its own. If generating the answer is what’s deflating, then whatever is still appreciating must sit upstream or downstream of it — <strong>upstream is the question, downstream is deployment</strong>.</p>

<h2 id="2-the-value-is-with-whoever-finds-the-problem">2. The value is with whoever finds the problem</h2>

<p>In 1964, Getzels and Csikszentmihalyi at the University of Chicago ran an experiment that people are still citing. They put 31 art students in a studio with a table of 27 objects — grapes, a steel gearshift, an old book, a glass prism — and gave each of them an hour: pick your objects, build your own arrangement, draw it.</p>

<p>The students split cleanly into two groups.</p>

<p>One group <strong>started fast</strong>: chose objects, arranged them, sketched an outline, and spent the rest of the hour refining the composition they’d committed to in the first five minutes. They were solving a problem they had already set.</p>

<p>The other group <strong>fooled around uncomfortably long</strong>: picking objects up, turning them over, changing arrangements, switching materials, erasing, starting over. Some spent fifty minutes exploring before racing to finish. They weren’t solving the problem. They were looking for it.</p>

<p>Five years later the researchers followed up on 27 of them — gallery shows, dealer representation, museum acquisitions, whether they were still making art at all. The result was blunt: <strong>the problem-finders were meaningfully more successful, and of the 11 students who were least problem-finding, 8 had left art entirely.</strong></p>

<p>I like this study because it separates two things we usually blur together. Solving is one skill; seeing which problem is worth solving is another, and the second is rarer, ages better, and — new development — is much harder to hand to a model. Give an AI a well-defined problem and it will out-answer you. But defining it isn’t something it can do for you, because the raw material for the definition isn’t in the training corpus. It’s on site.</p>

<p>In practice that means one thing: <strong>go where the work actually happens.</strong></p>

<ul>
  <li>Building product? Sit in the support queue for a day and listen to people complain about your thing.</li>
  <li>Doing ops or admin? Just ask colleagues which process they hate most, and how they route around it.</li>
  <li>Running a shop? Work the register yourself for a few days.</li>
</ul>

<p>This holds at home too. When you help a kid with homework, the “site” isn’t the notebook of wrong answers — it’s the second they stall. Did they misread the question, is the concept missing, or are they just tired? When you look after an aging parent, the site isn’t the number on the lab report; it’s whether the way they take the stairs has changed. You can outsource the answer. You can’t outsource noticing.</p>

<h2 id="3-be-a-translator-not-a-career-changer">3. Be a translator, not a career-changer</h2>

<p>Spend enough time on site and you hit the next wall: you can see the real problem, but you don’t know whether the new tools can touch it — or where they’ll quietly fall over.</p>

<p>Harvard Business School and BCG ran a field experiment with 758 consultants (Dell’Acqua et al., roughly 7% of BCG’s individual-contributor staff). The result has two halves, and most people only remember the first:</p>

<ul>
  <li><strong>Inside the AI’s capability frontier</strong>: consultants using AI completed 12.2% more tasks, 25.1% faster, at more than 40% higher quality. The biggest gains went to the lowest performers, who improved by 43%.</li>
  <li><strong>Outside it</strong>: consultants using AI were <strong>19 percentage points <em>less</em> likely</strong> to reach the correct solution than those working without it.</li>
</ul>

<p>The authors call this boundary a <strong>jagged frontier</strong> — not a smooth line but a ragged one. Two tasks that look equally hard from the outside: the model nails one and confidently botches the other. And both outputs look exactly the same on the page.</p>

<p>This is precisely where a translator earns their keep. <strong>Knowing how to use AI isn’t the scarce thing. Knowing where it will fall over is</strong> — and that knowledge is made of domain expertise, not prompt tricks. An accountant doesn’t need to become a programmer, but an accountant who understands these tools can rebuild a department’s whole reconciliation process <em>and</em> know which two steps must never be signed off by a model. A teacher doesn’t need to train models, but a teacher who plans lessons with AI and knows exactly where it invents things is not replaceable by a colleague who doesn’t.</p>

<p>You don’t need to be top-tier in two fields. Being fluent enough to hold a real conversation in two fields already puts you somewhere very few people stand. For most people, <strong>grafting a layer of tool understanding onto the domain you already have beats burning it down and switching careers</strong> — it’s more realistic, and a far better return.</p>

<h2 id="4-follow-deployment-not-just-invention">4. Follow deployment, not just invention</h2>

<p>The first three are about how to work. This one is about where to stand.</p>

<p>Look at electrification. The light bulb was invented in 1879 and patented in 1880. By 1900, only 3% of American homes had electric lighting, and electric motors accounted for <strong>less than 5%</strong> of factory mechanical drive. The 50% threshold wasn’t crossed until the 1920s.</p>

<p>What happened in those forty years? Economic historian Paul David’s answer: at first, factory owners simply <strong>swapped the steam engine for a dynamo</strong> and kept everything else — the line shafting, the belts, the whole centralized drive layout. Naturally, productivity barely moved. The real turn was <em>unit drive</em>: an individual motor on each machine, which meant the floor could be rearranged, and buildings could be lighter, modular, single-story. And spreading that across industries and towns required, in David’s words, “building up a cadre of experienced factory architects and electrical engineers familiar with the new approach to manufacturing.”</p>

<p>Technology history keeps repeating this shape: <strong>the invention window is narrow and crowded with geniuses; the deployment window is far wider, stays open much longer, and is much friendlier to ordinary people.</strong> Electrical engineers in the electric era, web shops and sysadmins in the internet era, app developers in the mobile era — all of them made their living in the wider window.</p>

<p>AI’s deployment era has barely started. It needs more than model researchers. It needs lawyers who understand AI, doctors who understand AI, local officials who understand AI, shop owners who understand AI. You don’t have to squeeze into one of the five famous labs. <strong>Being the person in your own job who actually gets the new tool working is the seat this era leaves open for ordinary people.</strong></p>

<p>One more thing about that seat: deployment territory is structurally ambiguous. A new tool always gets stuck between two departments, and everyone involved can honestly say “that’s not my job.” As AI absorbs the tasks with clean boundaries, human value concentrates exactly in the messy places where someone has to step up and own the gap. “Not my job” used to be self-protection. It’s starting to look like self-elimination.</p>

<h2 id="5-learn-just-in-time-not-just-in-case">5. Learn just in time, not just in case</h2>

<p>Last, the method.</p>

<p>A lot of the anxiety right now takes the form of “which skills should I stockpile for the AI era?” — which turns into 300 bookmarked tutorials and a shelf of courses, none of it retained. I’ve done this. My bookmarks folder is the honest evidence.</p>

<p>The alternative is <strong>just-in-time learning</strong>: not learning everything first and then showing up, but learning today what today’s actual problem requires. Pick a real problem from your own life — a bookkeeping sheet for the family shop, turning a pile of travel notes into an itinerary, automating the weekly report you rebuild by hand every Monday — and learn only what that problem demands.</p>

<p>This isn’t only about retention. <strong>It’s also the only way to map that jagged frontier</strong>, because the edge is invisible until you walk into it. No amount of stockpiled tutorials will tell you where a model confidently invents things in <em>your</em> line of work. Watching it fail three times at your own task will.</p>

<h2 id="key-takeaways">Key Takeaways</h2>

<ol>
  <li><strong>Answers are deflating; questions are appreciating</strong> — producing a decent answer is nearly free now; finding and framing the real problem isn’t.</li>
  <li><strong>Ask the sharper question first: in my seat, does AI substitute for me or amplify me</strong> — the data shows substitution roles shrinking and complementary ones holding.</li>
  <li><strong>Real problems live on site</strong> — in the complaints, workarounds and small detours no dataset records; every inch closer you get is an inch of advantage over a model.</li>
  <li><strong>Translating beats switching careers</strong> — the scarce skill isn’t using AI, it’s knowing where it breaks, and that runs on the domain knowledge you already have.</li>
  <li><strong>Stop stockpiling skills; learn against a real problem</strong> — which happens to be the only way to find the edges of what AI can do.</li>
</ol>

<p style="font-size: 1.4em; font-style: italic; text-align: center; margin: 2rem 0;">You can outsource the answer. You cannot outsource noticing.</p>

<hr />

<h2 id="useful-resources">Useful Resources</h2>

<ul>
  <li>《半小时讲透 AI 时代的新职业：FDE》 / <em>Half an Hour on the AI Era’s New Job: the FDE</em> (轻科技, in Chinese) — where this line of thinking started. It’s about one specific role, but the interesting part is the general pattern underneath: people closest to the problem are getting more valuable</li>
  <li><a href="https://digitaleconomy.stanford.edu/publication/canaries-in-the-coal-mine-six-facts-about-the-recent-employment-effects-of-artificial-intelligence/">Canaries in the Coal Mine? Six Facts about the Recent Employment Effects of Artificial Intelligence (Stanford Digital Economy Lab, 2026)</a> — payroll evidence on young workers and AI exposure</li>
  <li><a href="https://papers.ssrn.com/sol3/papers.cfm?abstract_id=4573321">Navigating the Jagged Technological Frontier (Dell’Acqua et al., HBS/BCG)</a> — the 758-consultant field experiment, and the origin of the “jagged frontier”</li>
  <li><a href="https://thereader.mitpress.mit.edu/the-1960s-art-school-experiment-that-redefined-creativity/">The 1960s Art School Experiment That Redefined Creativity (MIT Press Reader)</a> — a very readable account of the Getzels &amp; Csikszentmihalyi problem-finding study</li>
  <li><a href="https://www.academia.edu/11211365/The_Dynamo_and_the_Computer_An_Historical_Perspective_on_the_Modern_Productivity_Paradox">The Dynamo and the Computer (Paul A. David, 1990)</a> — why electrification took forty years to pay off</li>
  <li><a href="https://www.aei.org/commentary/the-dynamo-the-computer-and-chatgpt-explaining-todays-productivity-paradox/">The Dynamo, the Computer, and ChatGPT (AEI)</a> — David’s argument applied to this round</li>
</ul>]]></content><author><name>Zhipeng Bao</name></author><category term="AI" /><category term="career" /><category term="learning" /><category term="problem-finding" /><category term="essay" /><summary type="html"><![CDATA[Here’s the uncomfortable thing I’ve slowly come to accept: the part of my work I’m best at is the part that got cheap first.]]></summary></entry><entry xml:lang="zh"><title type="html">当答案变便宜：AI 时代真正在涨价的四件事</title><link href="https://hzxbzp.github.io/zh/blog/2026/09/when-answers-get-cheap/" rel="alternate" type="text/html" title="当答案变便宜：AI 时代真正在涨价的四件事" /><published>2026-09-04T00:00:00+00:00</published><updated>2026-09-04T00:00:00+00:00</updated><id>https://hzxbzp.github.io/zh/blog/2026/09/zh-when-answers-get-cheap</id><content type="html" xml:base="https://hzxbzp.github.io/zh/blog/2026/09/when-answers-get-cheap/"><![CDATA[<p>我逐渐意识到一件有点扎心的事：我最擅长的那部分工作，正好是最先变便宜的那部分。</p>

<p>我现在几乎每天都会做同一个动作——把手上的活先丢给模型跑一遍。写一段说明、生成一份规范的代码骨架、把一篇长报告压成十行摘要，大多数时候它交出来的东西挑不出毛病，而且比我快得多。但有一类问题它从来没替我解决过，这类问题有个共同特征：<strong>它根本没出现在我的提示词里</strong>。它还在现场，在某个人绕开正规流程的小动作里，在一句没人当回事的抱怨里。</p>

<p>所以真正的问题不是”AI 会不会取代我”，而是：当”给出答案”这件事的价格塌到地板上，人的价值到底挪到哪儿去了？</p>

<h2 id="一答案在贬值这件事已经能在数据里看见">一、答案在贬值，这件事已经能在数据里看见</h2>

<p>斯坦福数字经济实验室今年的一项研究（Brynjolfsson、Chandar、Chen）用 ADP 的薪资数据追踪了数百万美国劳动者，一直到 2026 年 6 月。几个发现值得原样抄下来：</p>

<ul>
  <li><strong>没有出现全经济范围的大规模失业。</strong> 这一轮不是”机器来了大家都下岗”。</li>
  <li><strong>但 22 到 25 岁、身处 AI 高暴露岗位的年轻人，就业水平比低暴露岗位的同龄人低约 19%。</strong> 同样的岗位，经验丰富的人身上看不到这个缺口。</li>
  <li><strong>下滑主要来自”少招人”，不是”裁人”。</strong> 门在慢慢关，不是有人被推出去。</li>
  <li><strong>最关键的分野：AI 在这个岗位上是替代还是互补。</strong> 替代型岗位明显下滑；互补型岗位持平甚至继续增长。</li>
</ul>

<p>这是一篇仍在更新的工作论文，结论还会被继续检验。但它把问题问得比”AI 会不会取代人类”精确得多：<strong>在我这个位置上，AI 是替我干活，还是替代我干活？</strong> 这两件事听起来像，结果完全相反。</p>

<p>顺着这条线往下推，答案会自己浮出来：既然”生成答案”这一段在贬值，那还在涨价的，只能是答案上游和下游的东西——<strong>上游是问题，下游是落地</strong>。</p>

<h2 id="二值钱的是提出问题的人">二、值钱的是提出问题的人</h2>

<p>1964 年，芝加哥大学的 Getzels 和 Csikszentmihalyi 做过一个后来被反复引用的实验。他们请 31 名艺术学院学生在工作室里作画：桌上摆着 27 件杂物——葡萄、齿轮、一本旧书、一块玻璃棱镜——每人一小时，自己挑东西、自己组构图、自己画。</p>

<p>学生分成了泾渭分明的两类。</p>

<p>一类<strong>上手很快</strong>：迅速挑好物件、摆好、勾出轮廓，剩下的时间都在打磨最初那个构图。他们在解一道自己一开始就定好的题。</p>

<p>另一类<strong>磨蹭得让人着急</strong>：把东西拿起来翻来覆去看，换位置、换材料、擦掉重来，有人折腾了五十分钟才动笔，最后手忙脚乱地画完。他们不是在解题，他们在找那道题。</p>

<p>五年后研究者回访了其中 27 人，用画廊展出、有没有经纪代理、作品是否被美术馆收藏、还在不在画画来衡量。结果很干脆：<strong>“找问题”的那一类明显走得更远；而在最不”找问题”的 11 个人里，有 8 个已经彻底离开了艺术</strong>。</p>

<p>我很喜欢这个研究，因为它把一件模糊的事说清楚了：会解题是一种能力，能看出该解哪道题是另一种，而后者更稀缺、更耐久——现在还多了一条，它更难被外包给模型。你给 AI 一道定义清楚的题，它答得比你好；但把题目定义清楚这一步，它替不了你，因为定义题目的原料不在语料里，在现场。</p>

<p>落到具体动作上，无非是<strong>多往现场跑</strong>：</p>

<ul>
  <li>做产品的，去客服部门坐一天，听人怎么骂你的产品；</li>
  <li>做行政的，直接问同事最烦哪个流程、平时怎么绕过它；</li>
  <li>开店的，自己站几天收银台。</li>
</ul>

<p>这条在家里同样成立。辅导孩子作业时，”现场”不是错题本，而是他卡住的那一瞬间——是没读懂题，是概念没通，还是单纯困了？照顾老人时，”现场”不是体检报告上的指标，而是他最近上下楼梯的姿势有没有变。答案可以外包，觉察外包不了。</p>

<h2 id="三做翻译而不是推倒重来">三、做”翻译”，而不是推倒重来</h2>

<p>现场跑多了会遇到下一个坎：你看见了真问题，但你不知道新工具能不能解、会在哪里翻车。</p>

<p>哈佛商学院和波士顿咨询做过一个 758 人的实地实验（Dell’Acqua 等，约占 BCG 该层级顾问的 7%），结论有两半，很多人只记住了前一半：</p>

<ul>
  <li><strong>在 AI 能力边界之内</strong>：用 AI 的顾问多完成 12.2% 的任务，快 25.1%，质量高出 40% 以上；原本排名靠后的那批人提升最大，达到 43%。</li>
  <li><strong>在边界之外</strong>：用 AI 的顾问给出正确答案的概率，反而比不用的人<strong>低 19 个百分点</strong>。</li>
</ul>

<p>研究者把这条边界叫做”<strong>锯齿状的能力前沿</strong>“（jagged frontier）——它不是一条平滑的线，看起来差不多难的两件事，一件 AI 做得极好，另一件它会一本正经地做错。而且从外面看，两种输出长得一模一样。</p>

<p>这就是”翻译者”值钱的地方。<strong>不是”会用 AI”值钱，是”知道它在哪儿会翻车”值钱</strong>，而后者只能靠领域知识撑着。会计不需要成为程序员，但一个”懂点 AI 工具的会计”能把整个部门的对账流程重做一遍，而且知道哪几步绝对不能让模型自己签字；老师不需要会训练模型，但一个”会用 AI 备课、并且清楚它哪里会胡说”的老师，在同事里是替代不掉的。</p>

<p>不必在两个领域都做到顶尖，只要在两个领域都到”能对话”的程度，你就站在了一个很少有人站的位置上。对大多数人来说，<strong>在已有的领域上嫁接一层新工具的理解，比推倒重来转行现实得多，也划算得多</strong>。</p>

<h2 id="四跟着部署走而不只是跟着发明走">四、跟着”部署”走，而不只是跟着”发明”走</h2>

<p>如果说前面几条是关于怎么做事，这一条是关于站在哪儿。</p>

<p>回看电气化。灯泡 1879 年发明、1880 年拿到专利。可到 1900 年，全美只有 3% 的住宅用上了电灯，电动机在工厂机械动力里的占比<strong>还不到 5%</strong>；跨过 50% 这道坎，要等到 1920 年代。</p>

<p>中间那几十年发生了什么？经济史学家 Paul David 的解释是：一开始工厂主只是<strong>把蒸汽机换成了发电机</strong>，天轴、皮带、整套集中传动的布局原封不动——效率当然提不上来。真正的转折是”单机驱动”：每台设备配自己的电机，于是车间可以重新排布，厂房可以造得更轻、更模块化、只要一层。而把这套做法铺到各行各业、各个地方，用 David 的原话说，需要”<strong>培养出一批熟悉这种新造法的工厂建筑师和电气工程师</strong>“。</p>

<p>技术史一再重复这个结构：<strong>发明的窗口极窄，天才云集；部署的窗口宽得多、长得多，对普通人友好得多。</strong> 电气时代的电气工程师、互联网时代的建站公司和网管、移动时代的 App 开发者，都是在这个更宽的窗口里赚到了钱。</p>

<p>AI 的部署期才刚刚开始。它需要的不只是模型研究员，还有懂 AI 的律师、懂 AI 的医生、懂 AI 的乡镇干部、懂 AI 的小店老板。你不必挤进那几家明星公司——<strong>在自己的岗位上做那个”把新工具真正用起来的人”，就是这一轮留给普通人的位置</strong>。</p>

<p>顺带说一句，部署地带天然是边界模糊的：新工具卡在两个部门中间，谁都能说”这不归我管”。而当 AI 逐渐接管掉那些边界清晰的执行类任务之后，人的价值恰恰会集中在这些需要有人站出来兜底的地方。”这不归我管”在过去是一种自我保护，往后可能变成一种自我淘汰。</p>

<h2 id="五学习方式从囤货转向打仗">五、学习方式：从”囤货”转向”打仗”</h2>

<p>最后一条是方法。</p>

<p>很多人的焦虑是”AI 时代该囤哪些技能”，于是收藏了几百篇教程、买了一堆课，学完就忘。我自己也囤过，收藏夹是最诚实的证据。</p>

<p>更好的方式是<strong>带着问题学</strong>（行话叫 just-in-time learning，即时学习）：不是先学完再上场，而是为了解决眼前这个具体问题，当天学、当天用，缺什么补什么。找一个你真实生活里的问题就行——帮家里小店做个记账表，把一堆旅行攻略自动整理成行程表，把每周重复的那份报表自动生成。</p>

<p>这不只是记得牢的问题。<strong>它还是唯一能让你摸清那条”锯齿状边界”的办法</strong>——边界在哪儿，只有撞上去才知道。你囤再多教程，也不会知道模型在你这一行的哪个环节会一本正经地胡说；而你亲手让它做砸过三次，就知道了。</p>

<h2 id="key-takeaways">Key Takeaways</h2>

<ol>
  <li><strong>答案在贬值，问题在升值</strong> —— AI 让”生成一个像样的答案”变得几乎免费，稀缺的是发现和定义真问题的能力。</li>
  <li><strong>先问对问题：在我的岗位上，AI 是替代我还是放大我</strong> —— 数据显示，替代型岗位在收缩，互补型岗位没有。</li>
  <li><strong>真问题藏在现场</strong> —— 它藏在数据不记录的抱怨、绕路和小动作里，多往现场跑一寸，你相对模型的优势就厚一分。</li>
  <li><strong>做翻译者比转行现实</strong> —— 值钱的不是会用 AI，是知道它在哪儿会翻车，而那需要你原本就有的领域知识。</li>
  <li><strong>别囤技能，带着真实问题学</strong> —— 顺便，这也是唯一能摸清 AI 能力边界的办法。</li>
</ol>

<p style="font-size: 1.4em; font-style: italic; text-align: center; margin: 2rem 0;">答案可以外包，觉察不能。</p>

<hr />

<h2 id="useful-resources">Useful Resources</h2>

<ul>
  <li>《半小时讲透 AI 时代的新职业：FDE》（轻科技）—— 这篇文章的起点。它讲的是一个具体岗位，但真正有意思的是背后那条更普遍的规律：离问题最近的人，正在变得越来越值钱</li>
  <li><a href="https://digitaleconomy.stanford.edu/publication/canaries-in-the-coal-mine-six-facts-about-the-recent-employment-effects-of-artificial-intelligence/">Canaries in the Coal Mine? Six Facts about the Recent Employment Effects of Artificial Intelligence (Stanford Digital Economy Lab, 2026)</a> —— 年轻人、AI 暴露度与就业的实证追踪</li>
  <li><a href="https://papers.ssrn.com/sol3/papers.cfm?abstract_id=4573321">Navigating the Jagged Technological Frontier (Dell’Acqua et al., HBS/BCG)</a> —— 758 名顾问的实地实验，”锯齿状能力前沿”的出处</li>
  <li><a href="https://thereader.mitpress.mit.edu/the-1960s-art-school-experiment-that-redefined-creativity/">The 1960s Art School Experiment That Redefined Creativity (MIT Press Reader)</a> —— Getzels 与 Csikszentmihalyi 的”问题发现”研究，写得很好读</li>
  <li><a href="https://www.academia.edu/11211365/The_Dynamo_and_the_Computer_An_Historical_Perspective_on_the_Modern_Productivity_Paradox">The Dynamo and the Computer (Paul A. David, 1990)</a> —— 电气化为什么用了四十年才兑现</li>
  <li><a href="https://www.aei.org/commentary/the-dynamo-the-computer-and-chatgpt-explaining-todays-productivity-paradox/">The Dynamo, the Computer, and ChatGPT (AEI)</a> —— 把 David 的论证接到今天这一轮上</li>
</ul>]]></content><author><name>Zhipeng Bao</name></author><category term="AI" /><category term="career" /><category term="learning" /><category term="problem-finding" /><category term="essay" /><summary type="html"><![CDATA[我逐渐意识到一件有点扎心的事：我最擅长的那部分工作，正好是最先变便宜的那部分。]]></summary></entry><entry xml:lang="en"><title type="html">The Art of Talking to AI: A Practical Guide to Prompt Engineering</title><link href="https://hzxbzp.github.io/blog/2026/05/prompt-engineering-guide/" rel="alternate" type="text/html" title="The Art of Talking to AI: A Practical Guide to Prompt Engineering" /><published>2026-05-18T00:00:00+00:00</published><updated>2026-05-18T00:00:00+00:00</updated><id>https://hzxbzp.github.io/blog/2026/05/prompt-engineering-guide</id><content type="html" xml:base="https://hzxbzp.github.io/blog/2026/05/prompt-engineering-guide/"><![CDATA[<p>Same model, same question, wildly different answers. I discovered that the gap between a useless AI response and a brilliant one often has nothing to do with the model — it’s all about how you ask.</p>

<h2 id="the-story-one-assignment-six-techniques">The Story: One Assignment, Six Techniques</h2>

<p>My CS146S course (The Modern Software Developer) gave us a set of coding exercises that all shared the same structure: get Llama 3.1 (8B) to solve a task correctly. The twist? Each exercise required a <em>different prompting technique</em> — and the difference in results was shocking.</p>

<p>Same model. Same hardware. Completely different capabilities, just by changing the prompt.</p>

<p>Here are the six techniques I implemented, ordered from simplest to most powerful.</p>

<p><img src="/assets/images/blog/prompt-techniques-overview.svg" alt="Prompt techniques from basic to advanced" /></p>

<h2 id="1-few-shot-prompting-learn-by-example">1. Few-Shot Prompting: “Learn by Example”</h2>

<p><strong>The idea:</strong> Instead of explaining the rules, show the model examples of correct input-output pairs and let it figure out the pattern.</p>

<p>In my assignment, I needed Llama to reverse the word “httpstatus.” Instead of explaining reversal, I gave it examples:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">system_prompt</span> <span class="o">=</span> <span class="s">"""You reverse the letters of a word. 
Output ONLY the reversed word.

Word: httpstatus
Reversed: sutatsptth

Word: hello
Reversed: olleh

Word: httpstatus
Reversed: sutatsptth"""</span>
</code></pre></div></div>

<p><strong>Why it works:</strong> LLMs are pattern-completion machines. When they see a consistent pattern of input → output, they extrapolate. Few-shot prompting exploits this by giving the model a “template” to follow.</p>

<p><strong>Watch out for:</strong></p>
<ul>
  <li><strong>Example quality matters more than quantity.</strong> One wrong example can derail the model. Three clean, diverse examples usually beat ten repetitive ones.</li>
  <li><strong>Order affects results.</strong> Put simpler examples first, harder ones last. The model pays more attention to recent context.</li>
  <li><strong>It doesn’t teach understanding.</strong> The model mimics the pattern without truly “getting” it — which is why it still fails on edge cases like unusual tokenization (see <a href="/blog/2026/05/why-llms-cant-reverse-words/">my first blog post</a>).</li>
</ul>

<h2 id="2-chain-of-thought-think-step-by-step">2. Chain-of-Thought: “Think Step by Step”</h2>

<p><strong>The idea:</strong> Ask the model to show its reasoning process before giving the final answer.</p>

<p>I used this to solve 3^{12345} mod 100:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">system_prompt</span> <span class="o">=</span> <span class="s">"""You solve user's problem. Think step by step. 
Output the reasoning trace and the final answer."""</span>
</code></pre></div></div>

<p><strong>Why it works:</strong> When you force the model to generate intermediate steps, those steps become additional context that guides the final answer. It’s like giving the model a “scratch pad” — the act of writing out the reasoning helps it stay on track.</p>

<p><strong>Watch out for:</strong></p>
<ul>
  <li><strong>The reasoning might be fake.</strong> As I discovered (and <a href="/blog/2026/05/llm-right-answer-wrong-reasoning/">wrote about</a>), the model can generate plausible-looking steps that don’t actually support the conclusion. It may know the answer and build the reasoning backwards.</li>
  <li><strong>Longer outputs cost more.</strong> CoT increases token usage significantly. For simple tasks, it’s overkill.</li>
  <li><strong>Garbage in, garbage out.</strong> If the first step goes wrong, every subsequent step compounds the error.</li>
</ul>

<h2 id="3-self-consistency-ask-three-times-trust-the-majority">3. Self-Consistency: “Ask Three Times, Trust the Majority”</h2>

<p><strong>The idea:</strong> Have the model solve the same problem multiple times using different approaches, then pick the most common answer.</p>

<p>My implementation was the most elaborate prompt of the set:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">system_prompt</span> <span class="o">=</span> <span class="s">"""You will solve every problem multiple times 
using different reasoning approaches.

1. Reasoning 1: Solve step by step, directly.
   Answer: &lt;number&gt;

2. Reasoning 2: Solve again from scratch, 
   using a different framing (e.g. work backwards).
   Answer: &lt;number&gt;

3. Reasoning 3: Solve by checking concrete 
   positions or values.
   Answer: &lt;number&gt;

4. Compare the three answers. Pick the majority vote.
   Answer: &lt;number&gt;"""</span>
</code></pre></div></div>

<p>The code then ran this 5 times and took the majority answer across all runs.</p>

<p><strong>Why it works:</strong> Different reasoning paths hit different failure modes. If two out of three approaches agree, the shared answer is more likely to be correct. It’s the same logic behind “ask three doctors”: one might be wrong, but if two agree, trust them.</p>

<p><strong>Watch out for:</strong></p>
<ul>
  <li><strong>Cost multiplies.</strong> You’re using 3x the tokens per call, and running multiple calls. Budget accordingly.</li>
  <li><strong>Diversity matters.</strong> If all three “different” approaches are secretly the same method rephrased, you get no benefit. Be specific about <em>how</em> each approach should differ.</li>
  <li><strong>Not all tasks benefit.</strong> For creative writing or subjective tasks, there’s no “correct” answer to vote on.</li>
</ul>

<h2 id="4-rag-heres-what-you-need-to-know">4. RAG: “Here’s What You Need to Know”</h2>

<p><strong>The idea:</strong> Give the model external documents as context so it doesn’t have to rely on (potentially outdated or incorrect) training data.</p>

<p>My assignment required writing a function that calls a documented API. The key was feeding the API docs directly into the prompt:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">user_prompt</span> <span class="o">=</span> <span class="sa">f</span><span class="s">"""Context (use ONLY this information):
</span><span class="si">{</span><span class="n">api_docs</span><span class="si">}</span><span class="s">

Task: Write a Python function fetch_user_name(user_id, api_key) 
that calls the documented API.

Requirements:
- Use the documented Base URL and endpoint.
- Send the documented authentication header.
- Return only the user's name string."""</span>
</code></pre></div></div>

<p><strong>Why it works:</strong> LLMs hallucinate when they don’t have information. RAG solves this by providing the exact information the model needs, right in the prompt. No guessing, no hallucinating endpoints or parameters.</p>

<p><strong>Watch out for:</strong></p>
<ul>
  <li><strong>Context window limits.</strong> You can’t dump an entire codebase into a prompt. Choose the most relevant documents carefully.</li>
  <li><strong>“Use ONLY this information” is important.</strong> Without it, the model might mix context with training data and invent fields that don’t exist.</li>
  <li><strong>Retrieval quality is everything.</strong> RAG is only as good as the documents you feed it. Bad retrieval → bad answers, no matter how good the model is.</li>
</ul>

<h2 id="5-reflexion-learn-from-your-mistakes">5. Reflexion: “Learn From Your Mistakes”</h2>

<p><strong>The idea:</strong> Let the model generate an answer, test it, show it what went wrong, and ask it to fix the code.</p>

<p>My assignment implemented a two-pass loop: generate → test → show failures → regenerate. A key detail: <strong>the two passes use different system prompts.</strong> The first pass gets a simple generation prompt; the reflexion pass gets a specialized correction prompt with the failure context.</p>

<p><strong>Pass 1 — Initial generation</strong> (simple, no feedback):</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">system_prompt</span> <span class="o">=</span> <span class="s">"""You are a coding assistant. Output ONLY a single 
fenced Python code block that defines the function 
is_valid_password(password: str) -&gt; bool. No prose or comments."""</span>
</code></pre></div></div>

<p><strong>Pass 2 — Reflexion</strong> (given the previous code + what went wrong):</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">reflexion_prompt</span> <span class="o">=</span> <span class="s">"""You are a coding assistant performing 
self-correction (reflexion).

You will be given:
1. A previous implementation that failed some test cases.
2. A list of failing test cases with expected vs. actual results 
   and specific validation rules that failed.

Your job:
- Read the failure report carefully.
- Identify exactly which checks were wrong, missed, or inverted.
- Produce a corrected implementation."""</span>
</code></pre></div></div>

<p>The reflexion prompt receives the actual failing output as context — for example: <code class="language-plaintext highlighter-rouge">"Input: Password1 → expected True, got False. Failing checks: missing special"</code>. The first pass often missed edge cases. But after seeing <em>exactly</em> which tests failed and why, the second pass nailed it.</p>

<p><strong>Why it works:</strong> Reflexion mimics how humans debug: write code → run tests → read errors → fix. The model doesn’t need to get it right the first time; it just needs to get it right <em>eventually</em>, guided by concrete feedback.</p>

<p><strong>Watch out for:</strong></p>
<ul>
  <li><strong>Feedback quality is critical.</strong> “It’s wrong, try again” is useless. “Input ‘Password1’ returned True but should return False because it’s missing a special character” — that’s actionable.</li>
  <li><strong>One iteration might not be enough.</strong> Complex bugs may need multiple rounds of reflexion. But too many rounds risk the model going in circles.</li>
  <li><strong>The model can over-correct.</strong> It might fix the failing case but break a previously passing one. Always re-run all tests, not just the failing ones.</li>
</ul>

<h2 id="6-tool-calling-use-real-tools-dont-pretend">6. Tool Calling: “Use Real Tools, Don’t Pretend”</h2>

<p><strong>The idea:</strong> Instead of asking the model to compute or guess, let it call external tools (APIs, code interpreters, databases) and work with real results.</p>

<p>My assignment required the model to call a Python function that parses source files:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">system_prompt</span> <span class="o">=</span> <span class="s">"""You are a tool-calling assistant. 
Respond with ONLY a JSON object:
{"tool": "&lt;tool_name&gt;", "args": {&lt;arguments&gt;}}

Available tools:
[
  {
    "name": "output_every_func_return_type",
    "description": "Parse a Python file and return 
    function_name: return_type for each function.",
    "parameters": {
      "file_path": { "type": "string" }
    }
  }
]"""</span>
</code></pre></div></div>

<p>The model outputs a structured tool call; the code <em>actually executes</em> the tool and returns real results.</p>

<p><strong>Why it works:</strong> This is the solution to the “fake code execution” problem from my <a href="/blog/2026/05/llm-right-answer-wrong-reasoning/">second blog post</a>. Instead of the model <em>pretending</em> to run code, it <em>actually</em> runs code. Instead of <em>guessing</em> what an API returns, it <em>calls</em> the API. Real data, real results, no hallucination.</p>

<p><strong>Watch out for:</strong></p>
<ul>
  <li><strong>Prompt format must be strict.</strong> The model needs to output valid JSON that your code can parse. One extra word outside the JSON and parsing fails. Be very explicit about the output format.</li>
  <li><strong>Security matters.</strong> If the model can call arbitrary tools, it can do damage. Always validate and sandbox tool calls.</li>
  <li><strong>Not every model supports it natively.</strong> Smaller models may struggle with structured JSON output. Larger models (GPT-4, Claude) have built-in tool-calling support.</li>
</ul>

<h2 id="why-do-these-techniques-exist">Why Do These Techniques Exist?</h2>

<p>All six techniques address the same root problem: <strong>LLMs are text predictors, not reasoners.</strong> They predict the most likely next token given the context. Every prompting technique is essentially a way to <em>engineer the context</em> so that the most likely next token is also the correct one.</p>

<table>
  <thead>
    <tr>
      <th style="text-align: left">Technique</th>
      <th style="text-align: left">Core Strategy</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left">Few-Shot</td>
      <td style="text-align: left">Set up a pattern the model can continue</td>
    </tr>
    <tr>
      <td style="text-align: left">Chain-of-Thought</td>
      <td style="text-align: left">Create intermediate context that guides the answer</td>
    </tr>
    <tr>
      <td style="text-align: left">Self-Consistency</td>
      <td style="text-align: left">Reduce variance by aggregating multiple attempts</td>
    </tr>
    <tr>
      <td style="text-align: left">RAG</td>
      <td style="text-align: left">Replace guessing with grounding in real data</td>
    </tr>
    <tr>
      <td style="text-align: left">Reflexion</td>
      <td style="text-align: left">Use feedback to iteratively narrow down the correct answer</td>
    </tr>
    <tr>
      <td style="text-align: left">Tool Calling</td>
      <td style="text-align: left">Bypass generation entirely for tasks that need computation</td>
    </tr>
  </tbody>
</table>

<p>The progression tells a story: we started by hoping the model would “just get it,” and gradually moved toward giving it more structure, more data, and more tools — because hoping isn’t a strategy.</p>

<h2 id="try-it-yourself">Try It Yourself</h2>

<p>Want to practice prompt engineering? Here are two excellent resources:</p>

<p><strong><a href="https://www.promptingguide.ai/">Prompting Guide</a></strong> — A comprehensive, open-source reference covering every technique from zero-shot to advanced agent patterns. Great as a lookup reference.</p>

<p><strong><a href="https://learnprompting.org/">Learn Prompting</a></strong> — An interactive course with hands-on exercises. Free and well-structured for beginners to advanced users.</p>

<p><strong><a href="https://github.com/anthropics/prompt-eng-interactive-tutorial">Anthropic’s Interactive Tutorial</a></strong> — Jupyter notebook-based course with a built-in playground at the bottom of each lesson for live experimentation.</p>

<h2 id="key-takeaways">Key Takeaways</h2>

<ol>
  <li><strong>The prompt is the program.</strong> How you ask is often more important than which model you use.</li>
  <li><strong>Start simple, escalate as needed.</strong> Few-shot handles most tasks; reach for CoT, RAG, or tools only when simple prompts fail.</li>
  <li><strong>Every technique has a cost.</strong> More tokens, more API calls, more complexity. Match the technique to the stakes.</li>
  <li><strong>Always verify outputs.</strong> No technique eliminates hallucinations entirely — they just reduce the probability.</li>
  <li><strong>Combine techniques.</strong> The real power comes from mixing: RAG + CoT + Tool Calling is how production AI systems work.</li>
</ol>

<p style="font-size: 1.4em; font-style: italic; text-align: center; margin: 2rem 0;">Every prompting trick is just a communication skill we forgot we already had.</p>

<hr />

<h2 id="useful-resources">Useful Resources</h2>

<ul>
  <li><a href="https://www.promptingguide.ai/">Prompt Engineering Guide</a></li>
  <li><a href="https://learnprompting.org/">Learn Prompting — Free Interactive Course</a></li>
  <li><a href="https://github.com/anthropics/prompt-eng-interactive-tutorial">Anthropic Interactive Prompt Engineering Tutorial (GitHub)</a></li>
  <li><a href="https://platform.openai.com/docs/guides/prompt-engineering">OpenAI Prompt Engineering Best Practices</a></li>
  <li><a href="https://arxiv.org/abs/2203.11171">Self-Consistency Improves Chain of Thought Reasoning (arXiv)</a></li>
  <li><a href="https://arxiv.org/abs/2303.11366">Reflexion: Language Agents with Verbal Reinforcement Learning (arXiv)</a></li>
  <li><a href="https://arxiv.org/abs/2201.11903">Chain-of-Thought Prompting Elicits Reasoning in LLMs (arXiv)</a></li>
  <li><a href="https://arxiv.org/abs/2005.11401">Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks (arXiv)</a></li>
</ul>]]></content><author><name>Zhipeng Bao</name></author><category term="AI" /><category term="LLM" /><category term="prompt-engineering" /><category term="tutorial" /><category term="techniques" /><summary type="html"><![CDATA[Same model, same question, wildly different answers. I discovered that the gap between a useless AI response and a brilliant one often has nothing to do with the model — it’s all about how you ask.]]></summary></entry><entry xml:lang="zh"><title type="html">和 AI 对话的艺术：提示工程实用指南</title><link href="https://hzxbzp.github.io/zh/blog/2026/05/prompt-engineering-guide/" rel="alternate" type="text/html" title="和 AI 对话的艺术：提示工程实用指南" /><published>2026-05-18T00:00:00+00:00</published><updated>2026-05-18T00:00:00+00:00</updated><id>https://hzxbzp.github.io/zh/blog/2026/05/zh-prompt-engineering-guide</id><content type="html" xml:base="https://hzxbzp.github.io/zh/blog/2026/05/prompt-engineering-guide/"><![CDATA[<p>同一个模型，同一个问题，答案却天差地别。我发现，一个没用的 AI 回答和一个惊艳的回答之间的差距，往往和模型本身无关——关键在于你怎么问。</p>

<h2 id="故事的起点一次作业六种技巧">故事的起点：一次作业，六种技巧</h2>

<p>我的 CS146S 课程（The Modern Software Developer）布置了一组编程练习，它们有一个共同的结构：让 Llama 3.1（8B）正确完成一个任务。关键在于，每道题要求使用<em>不同的提示技巧</em>——而结果的差异令人震惊。</p>

<p>同一个模型，同一台机器，能力却完全不同，仅仅因为换了一种提问方式。</p>

<p>以下是我实现的六种技巧，按从简单到强大的顺序排列。</p>

<p><img src="/assets/images/blog/prompt-techniques-overview.svg" alt="从基础到高级的提示技巧" /></p>

<h2 id="1-少样本提示few-shot-prompting用例子来教">1. 少样本提示（Few-Shot Prompting）：”用例子来教”</h2>

<p><strong>核心思路：</strong> 不要解释规则，而是给模型展示正确的输入-输出示例，让它自己找到规律。</p>

<p>在我的作业中，我需要让 Llama 反转 “httpstatus” 这个词。与其解释什么是反转，不如直接给它看例子：</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">system_prompt</span> <span class="o">=</span> <span class="s">"""You reverse the letters of a word. 
Output ONLY the reversed word.

Word: httpstatus
Reversed: sutatsptth

Word: hello
Reversed: olleh

Word: httpstatus
Reversed: sutatsptth"""</span>
</code></pre></div></div>

<p><strong>为什么有效：</strong> 大语言模型本质上是模式补全机器。当它们看到一致的输入 → 输出模式时，就会自动推断。少样本提示正是利用了这一点，给模型一个可以遵循的”模板”。</p>

<p><strong>需要注意的坑：</strong></p>
<ul>
  <li><strong>示例的质量比数量重要得多。</strong> 一个错误的示例就能把模型带偏。三个干净、多样的示例通常比十个重复的效果好。</li>
  <li><strong>顺序会影响结果。</strong> 把简单的例子放前面，难的放后面。模型对最近的上下文更敏感。</li>
  <li><strong>它并不是真的”理解”了。</strong> 模型只是在模仿模式，并没有真正”搞懂”——这也是为什么它在边界情况（比如不常见的分词方式）下依然会失败（参见<a href="/zh/blog/2026/05/why-llms-cant-reverse-words/">我的第一篇博客</a>）。</li>
</ul>

<h2 id="2-思维链chain-of-thought一步一步想">2. 思维链（Chain-of-Thought）：”一步一步想”</h2>

<p><strong>核心思路：</strong> 要求模型在给出最终答案之前，先展示推理过程。</p>

<p>我用这个技巧来计算 3^{12345} mod 100：</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">system_prompt</span> <span class="o">=</span> <span class="s">"""You solve user's problem. Think step by step. 
Output the reasoning trace and the final answer."""</span>
</code></pre></div></div>

<p><strong>为什么有效：</strong> 当你强制模型生成中间步骤时，这些步骤会变成额外的上下文，引导最终答案的生成。就像给模型一张”草稿纸”——把推理过程写出来这个动作本身，就能帮助它保持在正确的轨道上。</p>

<p><strong>需要注意的坑：</strong></p>
<ul>
  <li><strong>推理过程可能是假的。</strong> 正如我发现并<a href="/zh/blog/2026/05/llm-right-answer-wrong-reasoning/">写过的</a>，模型可能生成看起来很合理的步骤，但这些步骤实际上并不支持它的结论。它可能先知道答案，再反过来编造推理过程。</li>
  <li><strong>更长的输出意味着更高的成本。</strong> 思维链会显著增加 token 消耗。对于简单任务来说，没必要。</li>
  <li><strong>垃圾进，垃圾出。</strong> 如果第一步就错了，后面每一步都会把错误放大。</li>
</ul>

<h2 id="3-自洽性self-consistency问三遍听多数的">3. 自洽性（Self-Consistency）：”问三遍，听多数的”</h2>

<p><strong>核心思路：</strong> 让模型用不同的方法多次解决同一个问题，然后选择出现次数最多的答案。</p>

<p>我的实现是整组作业中最精心设计的提示：</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">system_prompt</span> <span class="o">=</span> <span class="s">"""You will solve every problem multiple times 
using different reasoning approaches.

1. Reasoning 1: Solve step by step, directly.
   Answer: &lt;number&gt;

2. Reasoning 2: Solve again from scratch, 
   using a different framing (e.g. work backwards).
   Answer: &lt;number&gt;

3. Reasoning 3: Solve by checking concrete 
   positions or values.
   Answer: &lt;number&gt;

4. Compare the three answers. Pick the majority vote.
   Answer: &lt;number&gt;"""</span>
</code></pre></div></div>

<p>代码会把这个过程跑 5 次，然后在所有运行结果中取多数票。</p>

<p><strong>为什么有效：</strong> 不同的推理路径会碰到不同的失败模式。如果三种方法中有两种得出了相同的答案，那个共同答案更可能是对的。道理就像”找三个医生看看”：一个可能误诊，但如果两个意见一致，就更值得信赖。</p>

<p><strong>需要注意的坑：</strong></p>
<ul>
  <li><strong>成本会翻倍。</strong> 每次调用消耗 3 倍的 token，而且要运行多次。要提前算好预算。</li>
  <li><strong>多样性很重要。</strong> 如果三种”不同”的方法本质上只是同一种方法的不同说法，那就没有任何好处。要明确指定每种方法<em>具体</em>应该怎么不同。</li>
  <li><strong>不是所有任务都适用。</strong> 对于创意写作或主观性任务，没有一个”正确答案”可以投票。</li>
</ul>

<h2 id="4-检索增强生成rag这是你需要知道的">4. 检索增强生成（RAG）：”这是你需要知道的”</h2>

<p><strong>核心思路：</strong> 给模型提供外部文档作为上下文，这样它就不用依赖（可能过时或错误的）训练数据。</p>

<p>我的作业要求编写一个调用文档化 API 的函数。关键是把 API 文档直接喂进提示里：</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">user_prompt</span> <span class="o">=</span> <span class="sa">f</span><span class="s">"""Context (use ONLY this information):
</span><span class="si">{</span><span class="n">api_docs</span><span class="si">}</span><span class="s">

Task: Write a Python function fetch_user_name(user_id, api_key) 
that calls the documented API.

Requirements:
- Use the documented Base URL and endpoint.
- Send the documented authentication header.
- Return only the user's name string."""</span>
</code></pre></div></div>

<p><strong>为什么有效：</strong> 大语言模型在缺乏信息时会产生幻觉（Hallucination）。RAG 通过在提示中直接提供模型需要的确切信息来解决这个问题。不用猜测，不会凭空捏造端点或参数。</p>

<p><strong>需要注意的坑：</strong></p>
<ul>
  <li><strong>上下文窗口（Context Window）有限。</strong> 你不可能把整个代码库都塞进提示里。要精心挑选最相关的文档。</li>
  <li><strong>“仅使用以下信息”这句话很重要。</strong> 没有它，模型可能会把上下文和训练数据混在一起，发明出根本不存在的字段。</li>
  <li><strong>检索质量决定一切。</strong> RAG 的效果取决于你喂给它的文档。检索质量差 → 答案就差，模型再好也没用。</li>
</ul>

<h2 id="5-反思reflexion从错误中学习">5. 反思（Reflexion）：”从错误中学习”</h2>

<p><strong>核心思路：</strong> 让模型先生成一个答案，测试它，把哪里错了告诉它，然后让它修复代码。</p>

<p>我的作业实现了一个两轮循环：生成 → 测试 → 展示失败 → 重新生成。一个关键细节：<strong>两轮使用不同的系统提示。</strong> 第一轮用简单的生成提示；反思轮用专门的纠错提示，并附带失败的上下文信息。</p>

<p><strong>第一轮——初始生成</strong>（简单，无反馈）：</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">system_prompt</span> <span class="o">=</span> <span class="s">"""You are a coding assistant. Output ONLY a single 
fenced Python code block that defines the function 
is_valid_password(password: str) -&gt; bool. No prose or comments."""</span>
</code></pre></div></div>

<p><strong>第二轮——反思</strong>（给出之前的代码 + 哪里出了问题）：</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">reflexion_prompt</span> <span class="o">=</span> <span class="s">"""You are a coding assistant performing 
self-correction (reflexion).

You will be given:
1. A previous implementation that failed some test cases.
2. A list of failing test cases with expected vs. actual results 
   and specific validation rules that failed.

Your job:
- Read the failure report carefully.
- Identify exactly which checks were wrong, missed, or inverted.
- Produce a corrected implementation."""</span>
</code></pre></div></div>

<p>反思提示会收到实际的失败输出作为上下文——比如：<code class="language-plaintext highlighter-rouge">"Input: Password1 → expected True, got False. Failing checks: missing special"</code>。第一轮往往会漏掉边界情况。但在看到<em>具体</em>哪些测试失败了以及<em>为什么</em>之后，第二轮就能搞定。</p>

<p><strong>为什么有效：</strong> 反思模仿了人类调试的方式：写代码 → 跑测试 → 看报错 → 修复。模型不需要第一次就写对，它只需要在具体反馈的引导下<em>最终</em>写对就行。</p>

<p><strong>需要注意的坑：</strong></p>
<ul>
  <li><strong>反馈质量至关重要。</strong> “错了，再试一次”毫无用处。”输入 ‘Password1’ 返回了 True，但应该返回 False，因为缺少特殊字符”——这才是可操作的反馈。</li>
  <li><strong>一轮迭代可能不够。</strong> 复杂的 bug 可能需要多轮反思。但轮数太多，模型可能会原地打转。</li>
  <li><strong>模型可能矫枉过正。</strong> 它可能修好了失败的测试，却搞坏了之前通过的。一定要重新运行所有测试，而不只是失败的那些。</li>
</ul>

<h2 id="6-工具调用tool-calling用真工具别靠猜">6. 工具调用（Tool Calling）：”用真工具，别靠猜”</h2>

<p><strong>核心思路：</strong> 与其让模型去计算或猜测，不如让它调用外部工具（API、代码解释器、数据库），用真实的结果来工作。</p>

<p>我的作业要求模型调用一个解析源文件的 Python 函数：</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">system_prompt</span> <span class="o">=</span> <span class="s">"""You are a tool-calling assistant. 
Respond with ONLY a JSON object:
{"tool": "&lt;tool_name&gt;", "args": {&lt;arguments&gt;}}

Available tools:
[
  {
    "name": "output_every_func_return_type",
    "description": "Parse a Python file and return 
    function_name: return_type for each function.",
    "parameters": {
      "file_path": { "type": "string" }
    }
  }
]"""</span>
</code></pre></div></div>

<p>模型输出一个结构化的工具调用；代码<em>真正执行</em>这个工具，并返回真实结果。</p>

<p><strong>为什么有效：</strong> 这就是我在<a href="/zh/blog/2026/05/llm-right-answer-wrong-reasoning/">第二篇博客</a>中提到的”假装执行代码”问题的解决方案。模型不再<em>假装</em>运行代码，而是<em>真正</em>运行代码。不再<em>猜测</em> API 返回什么，而是<em>实际调用</em> API。真实数据，真实结果，没有幻觉。</p>

<p><strong>需要注意的坑：</strong></p>
<ul>
  <li><strong>提示格式必须严格。</strong> 模型需要输出你的代码能解析的有效 JSON。JSON 外面多一个字就会导致解析失败。对输出格式要非常明确。</li>
  <li><strong>安全性很重要。</strong> 如果模型可以调用任意工具，它就可能造成破坏。一定要对工具调用进行验证和沙箱隔离（Sandboxing）。</li>
  <li><strong>不是所有模型都原生支持。</strong> 小模型可能很难生成结构化的 JSON 输出。大模型（GPT-4、Claude）有内置的工具调用支持。</li>
</ul>

<h2 id="这些技巧为什么会存在">这些技巧为什么会存在？</h2>

<p>所有六种技巧都在解决同一个根本问题：<strong>大语言模型是文本预测器，不是推理器。</strong> 它们根据上下文预测最可能的下一个 token。每一种提示技巧，本质上都是一种<em>工程化地构造上下文</em>的方式，让最可能的下一个 token 同时也是正确的那个。</p>

<table>
  <thead>
    <tr>
      <th style="text-align: left">技巧</th>
      <th style="text-align: left">核心策略</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left">少样本提示（Few-Shot）</td>
      <td style="text-align: left">建立一个模型可以延续的模式</td>
    </tr>
    <tr>
      <td style="text-align: left">思维链（Chain-of-Thought）</td>
      <td style="text-align: left">创建引导答案的中间上下文</td>
    </tr>
    <tr>
      <td style="text-align: left">自洽性（Self-Consistency）</td>
      <td style="text-align: left">通过聚合多次尝试来降低方差</td>
    </tr>
    <tr>
      <td style="text-align: left">检索增强生成（RAG）</td>
      <td style="text-align: left">用真实数据替代猜测</td>
    </tr>
    <tr>
      <td style="text-align: left">反思（Reflexion）</td>
      <td style="text-align: left">利用反馈逐步缩小到正确答案</td>
    </tr>
    <tr>
      <td style="text-align: left">工具调用（Tool Calling）</td>
      <td style="text-align: left">对需要计算的任务，直接跳过生成环节</td>
    </tr>
  </tbody>
</table>

<p>这个递进关系讲述了一个故事：我们一开始寄希望于模型能”直接搞定”，然后逐渐给它更多的结构、更多的数据、更多的工具——因为光靠希望不是策略。</p>

<h2 id="自己动手试试">自己动手试试</h2>

<p>想练习提示工程吗？这里有几个优秀的资源：</p>

<p><strong><a href="https://www.promptingguide.ai/">Prompting Guide</a></strong> — 一个全面的开源参考指南，涵盖从零样本到高级智能体模式的所有技巧。非常适合作为速查手册。</p>

<p><strong><a href="https://learnprompting.org/">Learn Prompting</a></strong> — 一个互动课程，有动手练习。免费且结构清晰，适合从入门到进阶的所有用户。</p>

<p><strong><a href="https://github.com/anthropics/prompt-eng-interactive-tutorial">Anthropic’s Interactive Tutorial</a></strong> — 基于 Jupyter notebook 的课程，每节课底部都有内置的实验环境，可以实时动手。</p>

<h2 id="关键收获">关键收获</h2>

<ol>
  <li><strong>提示就是程序。</strong> 你怎么问，往往比你用哪个模型更重要。</li>
  <li><strong>从简单开始，按需升级。</strong> 少样本提示能搞定大多数任务；只有当简单提示失败时，才去用思维链、RAG 或工具调用。</li>
  <li><strong>每种技巧都有代价。</strong> 更多 token、更多 API 调用、更高复杂度。要根据任务的重要程度来选择技巧。</li>
  <li><strong>永远验证输出。</strong> 没有任何技巧能完全消除幻觉——它们只是降低了概率。</li>
  <li><strong>组合使用。</strong> 真正的威力来自混合搭配：RAG + 思维链 + 工具调用，这就是生产级 AI 系统的工作方式。</li>
</ol>

<p style="font-size: 1.4em; font-style: italic; text-align: center; margin: 2rem 0;">每一个提示技巧，都不过是我们早已拥有却遗忘了的沟通能力。</p>

<hr />

<h2 id="参考资源">参考资源</h2>

<ul>
  <li><a href="https://www.promptingguide.ai/">Prompt Engineering Guide</a></li>
  <li><a href="https://learnprompting.org/">Learn Prompting — Free Interactive Course</a></li>
  <li><a href="https://github.com/anthropics/prompt-eng-interactive-tutorial">Anthropic Interactive Prompt Engineering Tutorial (GitHub)</a></li>
  <li><a href="https://platform.openai.com/docs/guides/prompt-engineering">OpenAI Prompt Engineering Best Practices</a></li>
  <li><a href="https://arxiv.org/abs/2203.11171">Self-Consistency Improves Chain of Thought Reasoning (arXiv)</a></li>
  <li><a href="https://arxiv.org/abs/2303.11366">Reflexion: Language Agents with Verbal Reinforcement Learning (arXiv)</a></li>
  <li><a href="https://arxiv.org/abs/2201.11903">Chain-of-Thought Prompting Elicits Reasoning in LLMs (arXiv)</a></li>
  <li><a href="https://arxiv.org/abs/2005.11401">Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks (arXiv)</a></li>
</ul>]]></content><author><name>Zhipeng Bao</name></author><category term="AI" /><category term="LLM" /><category term="prompt-engineering" /><category term="tutorial" /><category term="techniques" /><summary type="html"><![CDATA[同一个模型，同一个问题，答案却天差地别。我发现，一个没用的 AI 回答和一个惊艳的回答之间的差距，往往和模型本身无关——关键在于你怎么问。]]></summary></entry><entry xml:lang="en"><title type="html">Right Answer, Wrong Reasoning: Can LLMs Actually Think?</title><link href="https://hzxbzp.github.io/blog/2026/05/llm-right-answer-wrong-reasoning/" rel="alternate" type="text/html" title="Right Answer, Wrong Reasoning: Can LLMs Actually Think?" /><published>2026-05-17T00:00:00+00:00</published><updated>2026-05-17T00:00:00+00:00</updated><id>https://hzxbzp.github.io/blog/2026/05/llm-right-answer-wrong-reasoning</id><content type="html" xml:base="https://hzxbzp.github.io/blog/2026/05/llm-right-answer-wrong-reasoning/"><![CDATA[<p>I asked an AI to solve a math problem. It wrote Python code, “ran” it, showed intermediate results, and arrived at the correct answer. Impressive — until I looked closer and realized the reasoning was a performance, not a proof.</p>

<h2 id="the-story-a-math-problem-that-fooled-me">The Story: A Math Problem That Fooled Me</h2>

<p>For another CS146S assignment, I needed an LLM to solve this using chain-of-thought prompting:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>What is 3^{12345} (mod 100)?
</code></pre></div></div>

<p>In plain English: what are the last two digits of 3 raised to the power of 12345? The answer is <strong>43</strong>.</p>

<p>Here’s the setup:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">ollama</span> <span class="kn">import</span> <span class="n">chat</span>

<span class="n">system_prompt</span> <span class="o">=</span> <span class="s">"""You solve user's problem. Think step by step. 
Output the reasoning trace and the final answer."""</span>

<span class="n">user_prompt</span> <span class="o">=</span> <span class="s">"""
Solve this problem, then give the final answer on the last line 
as "Answer: &lt;number&gt;".

what is 3^{12345} (mod 100)?
"""</span>

<span class="n">response</span> <span class="o">=</span> <span class="n">chat</span><span class="p">(</span>
    <span class="n">model</span><span class="o">=</span><span class="s">"llama3.1:8b"</span><span class="p">,</span>
    <span class="n">messages</span><span class="o">=</span><span class="p">[</span>
        <span class="p">{</span><span class="s">"role"</span><span class="p">:</span> <span class="s">"system"</span><span class="p">,</span> <span class="s">"content"</span><span class="p">:</span> <span class="n">system_prompt</span><span class="p">},</span>
        <span class="p">{</span><span class="s">"role"</span><span class="p">:</span> <span class="s">"user"</span><span class="p">,</span> <span class="s">"content"</span><span class="p">:</span> <span class="n">user_prompt</span><span class="p">},</span>
    <span class="p">],</span>
    <span class="n">options</span><span class="o">=</span><span class="p">{</span><span class="s">"temperature"</span><span class="p">:</span> <span class="mf">0.3</span><span class="p">},</span>
<span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">response</span><span class="p">.</span><span class="n">message</span><span class="p">.</span><span class="n">content</span><span class="p">)</span>
</code></pre></div></div>

<p>Llama 3.1 responded with a beautifully structured answer: it wrote Python code, displayed “outputs,” identified a pattern, and arrived at 43. On the surface, it looked like rigorous step-by-step problem-solving.</p>

<p>But something was off.</p>

<h2 id="what-llama-showed-me">What Llama Showed Me</h2>

<p>The model’s response looked roughly like this:</p>

<p><strong>Step 1:</strong> Compute the first few powers of 3 mod 100 to find a pattern.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">powers</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">10</span><span class="p">):</span>
    <span class="n">power</span> <span class="o">=</span> <span class="nb">pow</span><span class="p">(</span><span class="n">base</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">modulus</span><span class="p">)</span>
    <span class="n">powers</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">power</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">powers</span><span class="p">)</span>  <span class="c1"># Output: [3, 9, 27, 81, 43, 29, 87, 61, 83, 49]
</span></code></pre></div></div>

<p><strong>Step 2:</strong> “From the output, we can see the pattern repeats every 20 powers.”</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">simplified_exponent</span> <span class="o">=</span> <span class="mi">12345</span> <span class="o">%</span> <span class="mi">20</span>  <span class="c1"># Output: 5
</span></code></pre></div></div>

<p><strong>Step 3:</strong> Calculate the final result.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">result</span> <span class="o">=</span> <span class="nb">pow</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">100</span><span class="p">)</span>  <span class="c1"># Output: 43
</span></code></pre></div></div>

<p><strong>Answer: 43</strong> — Correct!</p>

<p>Looks solid, right? Code, outputs, pattern recognition, final answer. But here’s the thing…</p>

<h2 id="three-things-that-were-wrong">Three Things That Were Wrong</h2>

<p><img src="/assets/images/blog/llm-reasoning-vs-real.svg" alt="What Llama showed vs what actually happened" /></p>

<h3 id="1-it-never-ran-the-code">1. It never ran the code</h3>

<p>Llama 3.1 is a text-generation model. It doesn’t have a Python interpreter. Those “outputs” after each <code class="language-plaintext highlighter-rouge">print()</code> statement? The model <em>generated</em> them as text — it predicted what the output <em>should</em> look like based on patterns in its training data.</p>

<p>For simple calculations, these predictions happen to be correct. But the model wasn’t computing — it was <em>performing</em> computation.</p>

<h3 id="2-the-logic-has-a-gap">2. The logic has a gap</h3>

<p>It showed 10 values, then claimed the pattern repeats every <strong>20</strong>. But you can’t deduce a period of 20 from only 10 data points. To actually prove this, you’d need to verify that 3^20 mod 100 = 1. Llama skipped that entirely.</p>

<h3 id="3-it-probably-knew-the-answer-first">3. It probably knew the answer first</h3>

<p>The most likely explanation: Llama had seen similar modular arithmetic problems in its training data. It already “knew” the period is 20 (related to Euler’s totient function). So it constructed a plausible-looking derivation <em>around</em> an answer it had already retrieved — not <em>toward</em> an answer it was discovering.</p>

<p>This is <strong>post-hoc rationalization</strong>: starting from the conclusion and building a story backwards.</p>

<h2 id="the-real-question-do-llms-actually-reason">The Real Question: Do LLMs Actually Reason?</h2>

<p>This experience points to a deeper issue that researchers are actively studying: <strong>when an LLM shows you its “thinking,” is it showing you the actual process that led to the answer, or a fabricated narrative?</strong></p>

<p>Recent research calls this the problem of <strong>unfaithful chain-of-thought</strong>. A 2025 study titled “Chain-of-Thought Reasoning In The Wild Is Not Always Faithful” found that even frontier models produce post-hoc rationalizations — GPT-4o-mini does it about 13% of the time, and even the best models aren’t fully immune.</p>

<p>The core tension is this: LLMs are trained to predict the next token, not to reason logically. When we prompt them to “think step by step,” they generate text that <em>looks like</em> reasoning. Sometimes it <em>is</em> genuine reasoning. Sometimes it’s pattern-matching dressed up in the format of logic.</p>

<p>And here’s what makes it dangerous: <strong>you can’t always tell the difference by reading the output.</strong> The fabricated reasoning looks just as convincing as the real thing.</p>

<h2 id="why-this-happens">Why This Happens</h2>

<h3 id="llms-are-text-predictors-not-logic-engines">LLMs are text predictors, not logic engines</h3>

<p>At their core, language models predict: “given everything so far, what token comes next?” They’ve seen millions of math solutions in training, so they know the <em>format</em> of a proof. But knowing the format doesn’t mean following the logic.</p>

<h3 id="training-data-creates-shortcuts">Training data creates shortcuts</h3>

<p>Llama has seen thousands of modular arithmetic problems. It learned that “modular exponentiation → find the period → reduce the exponent.” So it retrieves and applies this template. When the template fits, the answer is correct. When it doesn’t, you get confident nonsense.</p>

<h3 id="show-your-work-doesnt-guarantee-honest-work">“Show your work” doesn’t guarantee honest work</h3>

<p>Chain-of-thought prompting (“think step by step”) was designed to improve accuracy by forcing the model to lay out intermediate steps. And it does improve accuracy — but research shows the displayed steps don’t always reflect the model’s actual “decision process.” The model may have arrived at the answer through a completely different internal path, then generated a plausible explanation after the fact.</p>

<h2 id="what-can-we-do-about-it">What Can We Do About It?</h2>

<h3 id="1-give-llms-real-tools">1. Give LLMs real tools</h3>

<p>The most direct fix: let models actually execute code instead of pretending to. GPT-4 with Code Interpreter, Claude with tool use — these models can run Python for real. When Llama “runs” code in its head, it’s guessing. When a model with tool access runs code, it’s computing.</p>

<h3 id="2-verify-the-reasoning-not-just-the-answer">2. Verify the reasoning, not just the answer</h3>

<p>Don’t stop at “is the answer correct?” Ask: “does each step logically follow from the previous one?” In my Llama example, checking the 10-to-20 logical gap would have revealed the problem immediately.</p>

<h3 id="3-self-consistency-checking">3. Self-consistency checking</h3>

<p>Run the same prompt multiple times with different temperatures. If the model produces different reasoning paths but the same answer, the answer is likely correct. If the reasoning paths contradict each other, something’s wrong. Research shows this can substantially improve reliability.</p>

<h3 id="4-cross-verify-with-different-approaches">4. Cross-verify with different approaches</h3>

<p>Ask the model to solve the same problem in two different ways. If both approaches agree, confidence goes up. If they disagree, at least one reasoning chain is unfaithful.</p>

<h3 id="5-treat-llm-output-as-a-draft-not-a-proof">5. Treat LLM output as a draft, not a proof</h3>

<p>This is the most important mindset shift. LLM reasoning is a <em>starting point</em> for human verification, not a substitute for it. The model gives you a plausible approach; you verify whether it actually holds.</p>

<h2 id="key-takeaways">Key Takeaways</h2>

<ol>
  <li><strong>Correct answers don’t guarantee correct reasoning</strong> — an LLM can get the right answer for the wrong reasons</li>
  <li><strong>LLMs perform reasoning, not always practice it</strong> — the “thinking” you see may be reconstructed after the fact</li>
  <li><strong>Fake code execution is real</strong> — without tool access, models generate plausible-looking but unverified outputs</li>
  <li><strong>Chain-of-thought is powerful but imperfect</strong> — it improves accuracy while creating a false sense of transparency</li>
  <li><strong>Always verify the process, not just the result</strong> — especially for math, logic, and any high-stakes reasoning</li>
</ol>

<p style="font-size: 1.4em; font-style: italic; text-align: center; margin: 2rem 0;">The best liars don't get the facts wrong — they get the reasoning wrong.</p>

<hr />

<h2 id="useful-resources">Useful Resources</h2>

<ul>
  <li><a href="https://arxiv.org/abs/2503.08679">Chain-of-Thought Reasoning In The Wild Is Not Always Faithful (arXiv, 2025)</a></li>
  <li><a href="https://arxiv.org/abs/2305.04388">Language Models Don’t Always Say What They Think (arXiv, 2023)</a></li>
  <li><a href="https://arxiv.org/abs/2203.11171">Self-Consistency Improves Chain of Thought Reasoning (arXiv)</a></li>
  <li><a href="https://explore.n1n.ai/blog/llm-cot-faithfulness-research-2026-03-30">Chain of Thought Faithfulness: Why LLM Reasoning Is Often a Narrative (n1n.ai)</a></li>
  <li><a href="https://en.wikipedia.org/wiki/Stochastic_parrot">Stochastic Parrot — Wikipedia</a></li>
  <li><a href="https://simonwillison.net/2025/Mar/2/hallucinations-in-code/">Hallucinations in Code Are the Least Dangerous Form of LLM Mistakes (Simon Willison)</a></li>
</ul>]]></content><author><name>Zhipeng Bao</name></author><category term="AI" /><category term="LLM" /><category term="reasoning" /><category term="chain-of-thought" /><category term="tutorial" /><summary type="html"><![CDATA[I asked an AI to solve a math problem. It wrote Python code, “ran” it, showed intermediate results, and arrived at the correct answer. Impressive — until I looked closer and realized the reasoning was a performance, not a proof.]]></summary></entry><entry xml:lang="zh"><title type="html">答案对了，推理错了：LLM 真的会思考吗？</title><link href="https://hzxbzp.github.io/zh/blog/2026/05/llm-right-answer-wrong-reasoning/" rel="alternate" type="text/html" title="答案对了，推理错了：LLM 真的会思考吗？" /><published>2026-05-17T00:00:00+00:00</published><updated>2026-05-17T00:00:00+00:00</updated><id>https://hzxbzp.github.io/zh/blog/2026/05/zh-llm-right-answer-wrong-reasoning</id><content type="html" xml:base="https://hzxbzp.github.io/zh/blog/2026/05/llm-right-answer-wrong-reasoning/"><![CDATA[<p>我让一个 AI 解一道数学题。它写了 Python 代码，”运行”了一下，展示了中间结果，最后得出了正确答案。看起来很厉害——直到我仔细一看，发现那个推理过程是在”演戏”，而不是在”证明”。</p>

<h2 id="故事的起因一道把我骗了的数学题">故事的起因：一道把我骗了的数学题</h2>

<p>在另一次 CS146S 的作业中，我需要用 <strong>思维链（Chain-of-Thought）</strong> 提示法让 LLM 解这道题：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>What is 3^{12345} (mod 100)?
</code></pre></div></div>

<p>翻译成人话就是：3 的 12345 次方，最后两位数字是什么？答案是 <strong>43</strong>。</p>

<p>下面是代码设置：</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">ollama</span> <span class="kn">import</span> <span class="n">chat</span>

<span class="n">system_prompt</span> <span class="o">=</span> <span class="s">"""You solve user's problem. Think step by step. 
Output the reasoning trace and the final answer."""</span>

<span class="n">user_prompt</span> <span class="o">=</span> <span class="s">"""
Solve this problem, then give the final answer on the last line 
as "Answer: &lt;number&gt;".

what is 3^{12345} (mod 100)?
"""</span>

<span class="n">response</span> <span class="o">=</span> <span class="n">chat</span><span class="p">(</span>
    <span class="n">model</span><span class="o">=</span><span class="s">"llama3.1:8b"</span><span class="p">,</span>
    <span class="n">messages</span><span class="o">=</span><span class="p">[</span>
        <span class="p">{</span><span class="s">"role"</span><span class="p">:</span> <span class="s">"system"</span><span class="p">,</span> <span class="s">"content"</span><span class="p">:</span> <span class="n">system_prompt</span><span class="p">},</span>
        <span class="p">{</span><span class="s">"role"</span><span class="p">:</span> <span class="s">"user"</span><span class="p">,</span> <span class="s">"content"</span><span class="p">:</span> <span class="n">user_prompt</span><span class="p">},</span>
    <span class="p">],</span>
    <span class="n">options</span><span class="o">=</span><span class="p">{</span><span class="s">"temperature"</span><span class="p">:</span> <span class="mf">0.3</span><span class="p">},</span>
<span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">response</span><span class="p">.</span><span class="n">message</span><span class="p">.</span><span class="n">content</span><span class="p">)</span>
</code></pre></div></div>

<p>Llama 3.1 给出了一个结构漂亮的回答：它写了 Python 代码，展示了”输出结果”，识别出了一个规律，最终得出了 43。从表面上看，这是一个严谨的、逐步推导的解题过程。</p>

<p>但有些地方不太对劲。</p>

<h2 id="llama-给我看了什么">Llama 给我看了什么</h2>

<p>模型的回答大概是这样的：</p>

<p><strong>第 1 步：</strong> 计算前几个 3 的幂对 100 取模的结果，找规律。</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">powers</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">10</span><span class="p">):</span>
    <span class="n">power</span> <span class="o">=</span> <span class="nb">pow</span><span class="p">(</span><span class="n">base</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">modulus</span><span class="p">)</span>
    <span class="n">powers</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">power</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">powers</span><span class="p">)</span>  <span class="c1"># Output: [3, 9, 27, 81, 43, 29, 87, 61, 83, 49]
</span></code></pre></div></div>

<p><strong>第 2 步：</strong> “从输出结果可以看出，这个模式每 20 个幂次重复一次。”</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">simplified_exponent</span> <span class="o">=</span> <span class="mi">12345</span> <span class="o">%</span> <span class="mi">20</span>  <span class="c1"># Output: 5
</span></code></pre></div></div>

<p><strong>第 3 步：</strong> 计算最终结果。</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">result</span> <span class="o">=</span> <span class="nb">pow</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">100</span><span class="p">)</span>  <span class="c1"># Output: 43
</span></code></pre></div></div>

<p><strong>Answer: 43</strong> ——正确！</p>

<p>看起来很靠谱对吧？代码、输出、模式识别、最终答案，一套流程下来很完整。但问题是……</p>

<h2 id="三个错误">三个错误</h2>

<p><img src="/assets/images/blog/llm-reasoning-vs-real.svg" alt="What Llama showed vs what actually happened" /></p>

<h3 id="1-它根本没运行代码">1. 它根本没运行代码</h3>

<p>Llama 3.1 是一个文本生成模型，它没有 Python 解释器。那些 <code class="language-plaintext highlighter-rouge">print()</code> 语句后面的”输出结果”？其实是模型根据训练数据中的模式，<em>预测</em>出来的文本——它猜的是输出<em>应该</em>长什么样。</p>

<p>对于简单的计算，这些预测恰好是对的。但模型并不是在<strong>计算（computing）</strong>——它是在<strong>表演（performing）</strong>计算。</p>

<h3 id="2-逻辑有漏洞">2. 逻辑有漏洞</h3>

<p>它展示了 10 个值，然后声称模式每 <strong>20</strong> 个一循环。但你不可能从 10 个数据点推导出周期是 20。要真正证明这一点，你需要验证 3^20 mod 100 = 1。Llama 完全跳过了这一步。</p>

<h3 id="3-它很可能一开始就知道答案">3. 它很可能一开始就知道答案</h3>

<p>最可能的解释是：Llama 在训练数据中见过类似的模运算题。它已经”知道”周期是 20（这和<strong>欧拉函数（Euler’s totient function）</strong>有关）。所以它是围绕一个已经检索到的答案，<em>反向构造</em>了一个看起来合理的推导过程——而不是<em>正向推导</em>出一个新发现的答案。</p>

<p>这就是<strong>事后合理化（post-hoc rationalization）</strong>：从结论出发，反向编一个故事。</p>

<h2 id="真正的问题llm-到底会不会推理">真正的问题：LLM 到底会不会推理？</h2>

<p>这个经历指向了一个研究人员正在积极研究的更深层问题：<strong>当一个 LLM 向你展示它的”思考过程”时，它展示的是真正导致答案产生的过程，还是一个编造出来的叙事？</strong></p>

<p>最近的研究把这称为<strong>不忠实的思维链（unfaithful chain-of-thought）</strong>问题。2025 年一项题为”Chain-of-Thought Reasoning In The Wild Is Not Always Faithful”的研究发现，即使是最前沿的模型也会产生事后合理化——GPT-4o-mini 大约有 13% 的概率这样做，就连最好的模型也不能完全幸免。</p>

<p>核心矛盾在于：LLM 被训练来预测下一个 <strong>token</strong>，而不是进行逻辑推理。当我们提示它”逐步思考”时，它生成的是<em>看起来像</em>推理的文本。有时候这<em>确实是</em>真正的推理。有时候只是伪装成逻辑格式的模式匹配。</p>

<p>而真正危险的地方在于：<strong>你不能总是通过阅读输出来分辨真假。</strong> 编造出来的推理看起来和真正的推理一样令人信服。</p>

<h2 id="为什么会这样">为什么会这样</h2>

<h3 id="llm-是文本预测器不是逻辑引擎">LLM 是文本预测器，不是逻辑引擎</h3>

<p>归根结底，语言模型做的事情就是预测：”根据到目前为止的所有内容，下一个 token 是什么？”它们在训练中见过几百万个数学解题过程，所以它们知道证明的<em>格式</em>。但知道格式不等于遵循逻辑。</p>

<h3 id="训练数据制造了捷径">训练数据制造了捷径</h3>

<p>Llama 见过成千上万的模运算问题。它学到了”模幂运算 → 找周期 → 简化指数”这个模板。所以它检索并套用了这个模板。当模板恰好适用时，答案就是对的。当不适用时，你得到的就是一本正经的胡说八道。</p>

<h3 id="写出你的解题步骤不等于诚实地展示解题步骤">“写出你的解题步骤”不等于”诚实地展示解题步骤”</h3>

<p><strong>思维链提示法（Chain-of-thought prompting）</strong>（”逐步思考”）的设计初衷是通过迫使模型展示中间步骤来提高准确率。它确实提高了准确率——但研究表明，展示出来的步骤并不总是反映模型实际的”决策过程”。模型可能是通过一条完全不同的内部路径得出了答案，然后在事后生成了一个看起来合理的解释。</p>

<h2 id="我们能做什么">我们能做什么？</h2>

<h3 id="1-给-llm-真正的工具">1. 给 LLM 真正的工具</h3>

<p>最直接的解决办法：让模型真正执行代码，而不是假装执行。GPT-4 带 <strong>Code Interpreter</strong>、Claude 带 <strong>tool use</strong>——这些模型可以真正运行 Python。当 Llama 在”脑子里”运行代码时，它是在猜。当有工具访问权限的模型运行代码时，它是在计算。</p>

<h3 id="2-验证推理过程而不只是答案">2. 验证推理过程，而不只是答案</h3>

<p>不要停留在”答案对不对？”这个问题上。要问：”每一步是否从上一步逻辑推导而来？”在我的 Llama 例子中，检查”从 10 个值跳到周期 20”这个逻辑漏洞就能立刻发现问题。</p>

<h3 id="3-自洽性检查self-consistency-checking">3. 自洽性检查（Self-consistency checking）</h3>

<p>用不同的 temperature 多次运行同一个 prompt。如果模型产生了不同的推理路径但得出相同的答案，那答案很可能是对的。如果推理路径互相矛盾，那就有问题了。研究表明这种方法可以显著提高可靠性。</p>

<h3 id="4-用不同方法交叉验证">4. 用不同方法交叉验证</h3>

<p>让模型用两种不同的方法解同一道题。如果两种方法得出一致的结论，信心就提高了。如果不一致，至少有一条推理链是不忠实的。</p>

<h3 id="5-把-llm-的输出当草稿而不是证明">5. 把 LLM 的输出当草稿，而不是证明</h3>

<p>这是最重要的思维转变。LLM 的推理是人类验证的<em>起点</em>，而不是替代品。模型给你一个看起来合理的方法；你来验证它是否真的成立。</p>

<h2 id="关键要点">关键要点</h2>

<ol>
  <li><strong>正确的答案不等于正确的推理</strong> ——LLM 可以因为错误的理由得出正确的答案</li>
  <li><strong>LLM 在表演推理，而不总是在实践推理</strong> ——你看到的”思考过程”可能是事后重构的</li>
  <li><strong>假装执行代码是真实存在的问题</strong> ——没有工具访问权限时，模型会生成看起来合理但未经验证的输出</li>
  <li><strong>思维链强大但不完美</strong> ——它提高了准确率，同时也制造了虚假的透明感</li>
  <li><strong>永远要验证过程，而不只是结果</strong> ——尤其是在数学、逻辑和任何高风险推理场景中</li>
</ol>

<p style="font-size: 1.4em; font-style: italic; text-align: center; margin: 2rem 0;">最高明的骗子不会弄错事实——他们只是编造了推理过程。</p>

<hr />

<h2 id="参考资源">参考资源</h2>

<ul>
  <li><a href="https://arxiv.org/abs/2503.08679">Chain-of-Thought Reasoning In The Wild Is Not Always Faithful (arXiv, 2025)</a></li>
  <li><a href="https://arxiv.org/abs/2305.04388">Language Models Don’t Always Say What They Think (arXiv, 2023)</a></li>
  <li><a href="https://arxiv.org/abs/2203.11171">Self-Consistency Improves Chain of Thought Reasoning (arXiv)</a></li>
  <li><a href="https://explore.n1n.ai/blog/llm-cot-faithfulness-research-2026-03-30">Chain of Thought Faithfulness: Why LLM Reasoning Is Often a Narrative (n1n.ai)</a></li>
  <li><a href="https://en.wikipedia.org/wiki/Stochastic_parrot">Stochastic Parrot — Wikipedia</a></li>
  <li><a href="https://simonwillison.net/2025/Mar/2/hallucinations-in-code/">Hallucinations in Code Are the Least Dangerous Form of LLM Mistakes (Simon Willison)</a></li>
</ul>]]></content><author><name>Zhipeng Bao</name></author><category term="AI" /><category term="LLM" /><category term="reasoning" /><category term="chain-of-thought" /><category term="tutorial" /><summary type="html"><![CDATA[我让一个 AI 解一道数学题。它写了 Python 代码，”运行”了一下，展示了中间结果，最后得出了正确答案。看起来很厉害——直到我仔细一看，发现那个推理过程是在”演戏”，而不是在”证明”。]]></summary></entry><entry xml:lang="en"><title type="html">Why Can’t AI Spell Backwards? The Secret of Tokenization</title><link href="https://hzxbzp.github.io/blog/2026/05/why-llms-cant-reverse-words/" rel="alternate" type="text/html" title="Why Can’t AI Spell Backwards? The Secret of Tokenization" /><published>2026-05-16T00:00:00+00:00</published><updated>2026-05-16T00:00:00+00:00</updated><id>https://hzxbzp.github.io/blog/2026/05/why-llms-cant-reverse-words</id><content type="html" xml:base="https://hzxbzp.github.io/blog/2026/05/why-llms-cant-reverse-words/"><![CDATA[<p>Have you ever asked ChatGPT to reverse a word and gotten a wrong answer? I did — and it led me down a fascinating rabbit hole about how AI actually “reads” text.</p>

<h2 id="the-story-a-homework-assignment-gone-wrong">The Story: A Homework Assignment Gone Wrong</h2>

<p>I was working on an assignment for my CS146S course (The Modern Software Developer) where the task was straightforward: <strong>get an LLM to reverse the letters of a word</strong>. Sounds simple, right?</p>

<p>Here’s the code I wrote, using k-shot prompting with Llama 3.1:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">ollama</span> <span class="kn">import</span> <span class="n">chat</span>

<span class="n">YOUR_SYSTEM_PROMPT</span> <span class="o">=</span> <span class="s">"""You reverse the letters of a word. 
Output ONLY the reversed word, with no explanation, no punctuation, 
and no other text.

Word: httpstatus
Reversed: sutatsptth

Word: hello
Reversed: olleh

Word: httpstatus
Reversed: sutatsptth"""</span>

<span class="n">USER_PROMPT</span> <span class="o">=</span> <span class="s">"""
Reverse the order of letters in the following word. 
Only output the reversed word, no other text:

httpstatus
"""</span>

<span class="n">EXPECTED_OUTPUT</span> <span class="o">=</span> <span class="s">"sutatsptth"</span>

<span class="n">response</span> <span class="o">=</span> <span class="n">chat</span><span class="p">(</span>
    <span class="n">model</span><span class="o">=</span><span class="s">"llama3.1:8b"</span><span class="p">,</span>
    <span class="n">messages</span><span class="o">=</span><span class="p">[</span>
        <span class="p">{</span><span class="s">"role"</span><span class="p">:</span> <span class="s">"system"</span><span class="p">,</span> <span class="s">"content"</span><span class="p">:</span> <span class="n">YOUR_SYSTEM_PROMPT</span><span class="p">},</span>
        <span class="p">{</span><span class="s">"role"</span><span class="p">:</span> <span class="s">"user"</span><span class="p">,</span> <span class="s">"content"</span><span class="p">:</span> <span class="n">USER_PROMPT</span><span class="p">},</span>
    <span class="p">],</span>
    <span class="n">options</span><span class="o">=</span><span class="p">{</span><span class="s">"temperature"</span><span class="p">:</span> <span class="mf">0.5</span><span class="p">},</span>
<span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">response</span><span class="p">.</span><span class="n">message</span><span class="p">.</span><span class="n">content</span><span class="p">.</span><span class="n">strip</span><span class="p">())</span>
</code></pre></div></div>

<p>Even with <strong>5 examples</strong> showing the correct reversal, the model kept getting it wrong! It would output things like “sutattsptth” or “statustpth” — close, but not right.</p>

<p>This isn’t just a Llama problem. Try asking GPT-4 or Claude to reverse “httpstatus” — they’ll often struggle too. But <strong>why</strong>?</p>

<h2 id="the-answer-llms-dont-see-letters">The Answer: LLMs Don’t See Letters</h2>

<p>Here’s the key insight: <strong>LLMs don’t read text letter by letter like humans do.</strong> They read in chunks called <strong>tokens</strong>.</p>

<p>When you type “httpstatus”, the AI doesn’t see:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>h - t - t - p - s - t - a - t - u - s
</code></pre></div></div>

<p>Instead, it sees something like:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[http] [status]
</code></pre></div></div>

<p>That’s it. Two chunks. The individual letters are invisible to the model.</p>

<p><img src="/assets/images/blog/tokenization-example.svg" alt="How tokenization splits &quot;httpstatus&quot; into tokens" /></p>

<h2 id="what-are-tokens">What Are Tokens?</h2>

<p>A <strong>token</strong> is the basic unit of text that an LLM processes. Think of it as the “atom” of language for AI. Tokens can be:</p>

<ul>
  <li>A whole word: <code class="language-plaintext highlighter-rouge">hello</code> → 1 token</li>
  <li>Part of a word: <code class="language-plaintext highlighter-rouge">running</code> → <code class="language-plaintext highlighter-rouge">run</code> + <code class="language-plaintext highlighter-rouge">ning</code> (2 tokens)</li>
  <li>A single character: rare characters might be individual tokens</li>
  <li>Punctuation: <code class="language-plaintext highlighter-rouge">.</code> <code class="language-plaintext highlighter-rouge">!</code> <code class="language-plaintext highlighter-rouge">?</code> are usually their own tokens</li>
  <li>Even spaces: in some tokenizers, spaces are part of the token</li>
</ul>

<p>For example, the sentence “I love AI” might become 3 tokens: <code class="language-plaintext highlighter-rouge">[I]</code> <code class="language-plaintext highlighter-rouge">[love]</code> <code class="language-plaintext highlighter-rouge">[AI]</code>. But “tokenization” might become <code class="language-plaintext highlighter-rouge">[token]</code> <code class="language-plaintext highlighter-rouge">[ization]</code> — two tokens.</p>

<p><strong>Why not just use individual letters?</strong> Because that would be incredibly expensive. The sentence “Hello, how are you?” has 20 characters but only about 6 tokens. Fewer tokens = less computation = faster and cheaper responses.</p>

<h2 id="why-do-llms-need-tokenizers">Why Do LLMs Need Tokenizers?</h2>

<p>Neural networks only understand numbers, not text. So before any text reaches the AI’s “brain,” it must be converted to numbers. The process works like this:</p>

<ol>
  <li><strong>Text</strong> → split into tokens (by the tokenizer)</li>
  <li><strong>Tokens</strong> → mapped to numeric IDs (from a vocabulary)</li>
  <li><strong>Numeric IDs</strong> → processed by the neural network</li>
  <li><strong>Output IDs</strong> → converted back to tokens → text</li>
</ol>

<p>The tokenizer is essentially the AI’s “eyes” — it determines what the model can and cannot see. And just like human eyes have blind spots, <strong>tokenizers have blind spots too</strong>. Letter-level operations fall right into that blind spot.</p>

<h2 id="how-does-tokenization-work-the-bpe-algorithm">How Does Tokenization Work? The BPE Algorithm</h2>

<p>The most popular tokenization method is called <strong>Byte Pair Encoding (BPE)</strong>. It’s surprisingly elegant:</p>

<ol>
  <li>Start with all individual characters as your vocabulary</li>
  <li>Count which pair of adjacent characters appears most frequently in your training data</li>
  <li>Merge that pair into a new token</li>
  <li>Repeat steps 2-3 until you reach your desired vocabulary size</li>
</ol>

<p><img src="/assets/images/blog/bpe-algorithm.svg" alt="BPE algorithm step by step" /></p>

<p>For example, if your training data has lots of English text, “th” appears very frequently, so it gets merged early. Then “the” becomes common, so that gets merged too. Eventually, common words like “the”, “and”, “is” become single tokens, while rare words get split into pieces.</p>

<h3 id="a-concrete-example">A Concrete Example</h3>

<p>Let’s say we’re building a tiny BPE vocabulary from the text “low lower lowest”:</p>

<table>
  <thead>
    <tr>
      <th>Step</th>
      <th>Action</th>
      <th>Vocabulary Change</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>0</td>
      <td>Start with characters</td>
      <td><code class="language-plaintext highlighter-rouge">l, o, w, e, r, s, t</code></td>
    </tr>
    <tr>
      <td>1</td>
      <td>Most frequent pair: <code class="language-plaintext highlighter-rouge">l</code> + <code class="language-plaintext highlighter-rouge">o</code> → merge</td>
      <td>Add <code class="language-plaintext highlighter-rouge">lo</code></td>
    </tr>
    <tr>
      <td>2</td>
      <td>Most frequent pair: <code class="language-plaintext highlighter-rouge">lo</code> + <code class="language-plaintext highlighter-rouge">w</code> → merge</td>
      <td>Add <code class="language-plaintext highlighter-rouge">low</code></td>
    </tr>
    <tr>
      <td>3</td>
      <td>Most frequent pair: <code class="language-plaintext highlighter-rouge">e</code> + <code class="language-plaintext highlighter-rouge">r</code> → merge</td>
      <td>Add <code class="language-plaintext highlighter-rouge">er</code></td>
    </tr>
    <tr>
      <td>4</td>
      <td>Most frequent pair: <code class="language-plaintext highlighter-rouge">e</code> + <code class="language-plaintext highlighter-rouge">s</code> → merge</td>
      <td>Add <code class="language-plaintext highlighter-rouge">es</code></td>
    </tr>
  </tbody>
</table>

<p>After training, “lower” tokenizes as <code class="language-plaintext highlighter-rouge">[low][er]</code> instead of 5 separate characters. Efficient!</p>

<h2 id="different-tokenizers-for-different-models">Different Tokenizers for Different Models</h2>

<p>Not all LLMs use the same tokenizer. Here’s a quick overview:</p>

<p><img src="/assets/images/blog/tokenizer-comparison.svg" alt="Tokenizer comparison table" /></p>

<h3 id="bpe-byte-pair-encoding">BPE (Byte Pair Encoding)</h3>
<ul>
  <li><strong>Used by:</strong> GPT-2, GPT-3, GPT-4, LLaMA, Mistral, Claude</li>
  <li><strong>How it works:</strong> Merges frequent character pairs iteratively</li>
  <li><strong>Variant:</strong> Byte-level BPE starts with 256 byte values instead of characters, handling any language/encoding</li>
</ul>

<h3 id="wordpiece">WordPiece</h3>
<ul>
  <li><strong>Used by:</strong> BERT, DistilBERT, Electra</li>
  <li><strong>How it works:</strong> Similar to BPE, but selects merges based on likelihood (which merge increases the training data probability most)</li>
  <li><strong>Key difference:</strong> Uses <code class="language-plaintext highlighter-rouge">##</code> prefix for sub-word continuations (e.g., “playing” → <code class="language-plaintext highlighter-rouge">play</code> + <code class="language-plaintext highlighter-rouge">##ing</code>)</li>
</ul>

<h3 id="sentencepiece-unigram">SentencePiece (Unigram)</h3>
<ul>
  <li><strong>Used by:</strong> T5, ALBERT, XLNet, Gemma</li>
  <li><strong>How it works:</strong> Starts with a large vocabulary and removes tokens that least affect the overall likelihood</li>
  <li><strong>Key difference:</strong> Treats text as a raw stream (no pre-tokenization by spaces), making it great for multilingual models</li>
</ul>

<h3 id="tiktoken-openais-implementation">Tiktoken (OpenAI’s Implementation)</h3>
<ul>
  <li><strong>GPT-4:</strong> Uses <code class="language-plaintext highlighter-rouge">cl100k_base</code> with ~100K tokens</li>
  <li><strong>GPT-4o:</strong> Uses <code class="language-plaintext highlighter-rouge">o200k_base</code> with ~200K tokens (double the vocabulary!)</li>
  <li>Larger vocabulary = more words as single tokens = faster inference</li>
</ul>

<h2 id="what-about-chinese-tokenization-across-languages">What About Chinese? Tokenization Across Languages</h2>

<p>English has spaces between words. Chinese, Japanese, and Thai don’t. So where do you split “我喜欢人工智能” (I love AI)?</p>

<ul>
  <li><strong>Character-level:</strong> <code class="language-plaintext highlighter-rouge">[我][喜][欢][人][工][智][能]</code> — 7 tokens. Safe but wasteful.</li>
  <li><strong>Word-level:</strong> <code class="language-plaintext highlighter-rouge">[我][喜欢][人工智能]</code> — 3 tokens. Efficient but needs a word segmentation tool first.</li>
  <li><strong>Subword (BPE):</strong> A middle ground — common words like <code class="language-plaintext highlighter-rouge">人工智能</code> become single tokens, rare ones get split.</li>
</ul>

<p>The key breakthrough was <strong>SentencePiece</strong>, which treats input as a raw byte stream instead of assuming spaces between words. This makes it work naturally for any language. That’s why it’s the go-to for multilingual models like T5 and Gemma.</p>

<p>Vocabulary size matters here too. GPT-4o’s tokenizer (o200k_base, 200K tokens) is twice the size of GPT-4’s (cl100k_base, 100K tokens), and a big chunk of those extra tokens went to non-English languages. Try pasting Chinese text into <a href="https://tiktokenizer.vercel.app/">Tiktokenizer</a> — GPT-4o consistently produces fewer tokens for the same input.</p>

<h2 id="try-it-yourself">Try It Yourself!</h2>

<p>Want to see how different models tokenize text? Check out this awesome online tool:</p>

<p><strong><a href="https://tiktokenizer.vercel.app/">Tiktokenizer</a></strong> — paste any text and see exactly how GPT-4, GPT-3.5, and other models break it into tokens.</p>

<p>Try typing “httpstatus” and see how it splits! Then try “h t t p s t a t u s” (with spaces) and notice the difference.</p>

<h2 id="so-how-do-we-get-llms-to-reverse-letters">So How DO We Get LLMs to Reverse Letters?</h2>

<p>Now that we understand the problem, here are effective solutions:</p>

<h3 id="method-1-separate-the-characters-first">Method 1: Separate the Characters First</h3>

<p>The simplest fix — give the model characters it can actually “see”:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Instead of: "Reverse: httpstatus"
# Do this:
</span><span class="n">prompt</span> <span class="o">=</span> <span class="s">"""The letters are: h, t, t, p, s, t, a, t, u, s
Now write them in reverse order, separated by commas:"""</span>
<span class="c1"># Output: s, u, t, a, t, s, p, t, t, h
# Then join: "sutatsptth" ✓
</span></code></pre></div></div>

<h3 id="method-2-chain-of-thought-step-by-step">Method 2: Chain-of-Thought (Step by Step)</h3>

<p>Ask the model to first list the letters, then reverse:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">prompt</span> <span class="o">=</span> <span class="s">"""Reverse the letters in "httpstatus".

Step 1: List each letter with its position:
Position 1: h
Position 2: t
Position 3: t
Position 4: p
Position 5: s
Position 6: t
Position 7: a
Position 8: t
Position 9: u
Position 10: s

Step 2: Now list them from last position to first:"""</span>
</code></pre></div></div>

<h3 id="method-3-use-code-execution">Method 3: Use Code Execution</h3>

<p>The most reliable approach — let the model write and run code:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">prompt</span> <span class="o">=</span> <span class="s">"""Write Python code to reverse the string "httpstatus" 
and output only the result."""</span>

<span class="c1"># Model outputs: print("httpstatus"[::-1])
# Result: sutatsptth ✓
</span></code></pre></div></div>

<h3 id="method-4-fine-tuning-with-character-level-tasks">Method 4: Fine-tuning with Character-Level Tasks</h3>

<p>For production systems, models can be fine-tuned with <strong>Token Internal Position Awareness (TIPA)</strong> — training them on tasks that require knowing character positions within tokens. This is an active research area.</p>

<h2 id="key-takeaways">Key Takeaways</h2>

<ol>
  <li><strong>LLMs don’t see individual letters</strong> — they see tokens (chunks of text)</li>
  <li><strong>Tokenization is a trade-off</strong>: efficiency vs. character-level awareness</li>
  <li><strong>“Simple” text tasks can be hard for AI</strong> when they require letter-level manipulation</li>
  <li><strong>Workarounds exist</strong>: character separation, chain-of-thought, and code execution all help</li>
  <li><strong>The tokenizer is the AI’s “eyes”</strong> — its capabilities and limitations shape what the model can do</li>
</ol>

<p style="font-size: 1.4em; font-style: italic; text-align: center; margin: 2rem 0;">AI doesn't misunderstand language — it never saw it the way we do.</p>

<hr />

<h2 id="useful-resources">Useful Resources</h2>

<ul>
  <li><a href="https://tiktokenizer.vercel.app/">Tiktokenizer — Online Tokenizer Visualization Tool</a></li>
  <li><a href="https://www.youtube.com/watch?v=7xTGNNLPyMI">Let’s Build the GPT Tokenizer — Andrej Karpathy (YouTube)</a></li>
  <li><a href="https://huggingface.co/docs/transformers/en/tokenizer_summary">Hugging Face — Tokenization Algorithms Summary</a></li>
  <li><a href="https://huggingface.co/learn/llm-course/en/chapter6/5">Hugging Face — BPE Tokenization Explained</a></li>
  <li><a href="https://github.com/openai/tiktoken">OpenAI Tiktoken Library (GitHub)</a></li>
  <li><a href="https://nebius.com/blog/posts/how-tokenizers-work-in-ai-models">How Tokenizers Work in AI Models (Nebius)</a></li>
  <li><a href="https://sebastianraschka.com/blog/2025/bpe-from-scratch.html">Sebastian Raschka — Implementing BPE from Scratch</a></li>
  <li><a href="https://arxiv.org/html/2412.18626v1">Why LLMs Struggle to Count Letters (arXiv)</a></li>
</ul>]]></content><author><name>Zhipeng Bao</name></author><category term="AI" /><category term="LLM" /><category term="tokenization" /><category term="NLP" /><category term="tutorial" /><summary type="html"><![CDATA[Have you ever asked ChatGPT to reverse a word and gotten a wrong answer? I did — and it led me down a fascinating rabbit hole about how AI actually “reads” text.]]></summary></entry><entry xml:lang="zh"><title type="html">为什么AI不会倒着拼写？分词的秘密</title><link href="https://hzxbzp.github.io/zh/blog/2026/05/why-llms-cant-reverse-words/" rel="alternate" type="text/html" title="为什么AI不会倒着拼写？分词的秘密" /><published>2026-05-16T00:00:00+00:00</published><updated>2026-05-16T00:00:00+00:00</updated><id>https://hzxbzp.github.io/zh/blog/2026/05/zh-why-llms-cant-reverse-words</id><content type="html" xml:base="https://hzxbzp.github.io/zh/blog/2026/05/why-llms-cant-reverse-words/"><![CDATA[<p>你有没有让ChatGPT把一个单词倒过来拼，结果它给了你一个错误答案？我就遇到过——然后我就掉进了一个关于AI到底是怎么”阅读”文字的兔子洞。</p>

<h2 id="故事的起因一次翻车的作业">故事的起因：一次翻车的作业</h2>

<p>我当时在做CS146S课程（The Modern Software Developer）的作业，任务很简单：<strong>让一个LLM把一个单词的字母倒序排列</strong>。听起来很容易对吧？</p>

<p>下面是我写的代码，用的是k-shot提示和Llama 3.1：</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">ollama</span> <span class="kn">import</span> <span class="n">chat</span>

<span class="n">YOUR_SYSTEM_PROMPT</span> <span class="o">=</span> <span class="s">"""You reverse the letters of a word. 
Output ONLY the reversed word, with no explanation, no punctuation, 
and no other text.

Word: httpstatus
Reversed: sutatsptth

Word: hello
Reversed: olleh

Word: httpstatus
Reversed: sutatsptth"""</span>

<span class="n">USER_PROMPT</span> <span class="o">=</span> <span class="s">"""
Reverse the order of letters in the following word. 
Only output the reversed word, no other text:

httpstatus
"""</span>

<span class="n">EXPECTED_OUTPUT</span> <span class="o">=</span> <span class="s">"sutatsptth"</span>

<span class="n">response</span> <span class="o">=</span> <span class="n">chat</span><span class="p">(</span>
    <span class="n">model</span><span class="o">=</span><span class="s">"llama3.1:8b"</span><span class="p">,</span>
    <span class="n">messages</span><span class="o">=</span><span class="p">[</span>
        <span class="p">{</span><span class="s">"role"</span><span class="p">:</span> <span class="s">"system"</span><span class="p">,</span> <span class="s">"content"</span><span class="p">:</span> <span class="n">YOUR_SYSTEM_PROMPT</span><span class="p">},</span>
        <span class="p">{</span><span class="s">"role"</span><span class="p">:</span> <span class="s">"user"</span><span class="p">,</span> <span class="s">"content"</span><span class="p">:</span> <span class="n">USER_PROMPT</span><span class="p">},</span>
    <span class="p">],</span>
    <span class="n">options</span><span class="o">=</span><span class="p">{</span><span class="s">"temperature"</span><span class="p">:</span> <span class="mf">0.5</span><span class="p">},</span>
<span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">response</span><span class="p">.</span><span class="n">message</span><span class="p">.</span><span class="n">content</span><span class="p">.</span><span class="n">strip</span><span class="p">())</span>
</code></pre></div></div>

<p>即使给了<strong>5个正确示例</strong>，模型还是一直搞错！它会输出类似”sutattsptth”或”statustpth”的东西——接近了，但就是不对。</p>

<p>这不只是Llama的问题。你试试让GPT-4或Claude去反转”httpstatus”——它们也经常会翻车。但<strong>为什么呢</strong>？</p>

<h2 id="答案llm看不到字母">答案：LLM看不到字母</h2>

<p>关键的洞察是：<strong>LLM并不像人类那样逐个字母地阅读文本。</strong> 它们是按”块”来读的，这些块叫做<strong>词元（Token）</strong>。</p>

<p>当你输入”httpstatus”时，AI看到的并不是：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>h - t - t - p - s - t - a - t - u - s
</code></pre></div></div>

<p>它看到的实际上是这样的：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[http] [status]
</code></pre></div></div>

<p>就这样。两个块。模型根本看不到单个字母。</p>

<p><img src="/assets/images/blog/tokenization-example.svg" alt="分词如何将&quot;httpstatus&quot;拆分为词元" /></p>

<h2 id="什么是词元token">什么是词元（Token）？</h2>

<p><strong>词元（Token）</strong> 是LLM处理的基本文本单位。你可以把它想象成AI语言世界里的”原子”。词元可以是：</p>

<ul>
  <li>一个完整的单词：<code class="language-plaintext highlighter-rouge">hello</code> → 1个词元</li>
  <li>单词的一部分：<code class="language-plaintext highlighter-rouge">running</code> → <code class="language-plaintext highlighter-rouge">run</code> + <code class="language-plaintext highlighter-rouge">ning</code>（2个词元）</li>
  <li>单个字符：罕见字符可能是单独的词元</li>
  <li>标点符号：<code class="language-plaintext highlighter-rouge">.</code> <code class="language-plaintext highlighter-rouge">!</code> <code class="language-plaintext highlighter-rouge">?</code> 通常各自是一个词元</li>
  <li>甚至空格：在某些分词器中，空格也是词元的一部分</li>
</ul>

<p>举个例子，句子”I love AI”可能变成3个词元：<code class="language-plaintext highlighter-rouge">[I]</code> <code class="language-plaintext highlighter-rouge">[love]</code> <code class="language-plaintext highlighter-rouge">[AI]</code>。但”tokenization”可能变成 <code class="language-plaintext highlighter-rouge">[token]</code> <code class="language-plaintext highlighter-rouge">[ization]</code>——两个词元。</p>

<p><strong>为什么不直接用单个字母呢？</strong> 因为那样的计算成本太高了。句子”Hello, how are you?”有20个字符，但只有大约6个词元。更少的词元 = 更少的计算 = 更快更便宜的响应。</p>

<h2 id="为什么llm需要分词器tokenizer">为什么LLM需要分词器（Tokenizer）？</h2>

<p>神经网络只认识数字，不认识文字。所以在任何文本到达AI的”大脑”之前，它必须先被转换成数字。整个过程是这样的：</p>

<ol>
  <li><strong>文本</strong> → 被拆分成词元（由分词器完成）</li>
  <li><strong>词元</strong> → 映射为数字ID（来自词汇表）</li>
  <li><strong>数字ID</strong> → 由神经网络处理</li>
  <li><strong>输出ID</strong> → 转换回词元 → 文本</li>
</ol>

<p>分词器本质上就是AI的”眼睛”——它决定了模型能看到什么、看不到什么。就像人的眼睛有盲区一样，<strong>分词器也有盲区</strong>。字母级别的操作恰恰就落在了这个盲区里。</p>

<h2 id="分词是怎么工作的bpe算法">分词是怎么工作的？BPE算法</h2>

<p>最流行的分词方法叫做<strong>字节对编码（Byte Pair Encoding, BPE）</strong>。它的原理出奇地优雅：</p>

<ol>
  <li>从所有单个字符作为你的词汇表开始</li>
  <li>统计训练数据中哪对相邻字符出现频率最高</li>
  <li>将这对字符合并为一个新的词元</li>
  <li>重复第2-3步，直到达到你想要的词汇表大小</li>
</ol>

<p><img src="/assets/images/blog/bpe-algorithm.svg" alt="BPE算法分步演示" /></p>

<p>比如说，如果你的训练数据里有大量英文文本，”th”出现得非常频繁，所以它很早就会被合并。然后”the”变得常见了，于是也被合并。最终，像”the”、”and”、”is”这样的常见词都会变成单个词元，而罕见词则会被拆分成几部分。</p>

<h3 id="一个具体的例子">一个具体的例子</h3>

<p>假设我们要从文本”low lower lowest”构建一个小型BPE词汇表：</p>

<table>
  <thead>
    <tr>
      <th>步骤</th>
      <th>操作</th>
      <th>词汇表变化</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>0</td>
      <td>从单个字符开始</td>
      <td><code class="language-plaintext highlighter-rouge">l, o, w, e, r, s, t</code></td>
    </tr>
    <tr>
      <td>1</td>
      <td>最高频字符对：<code class="language-plaintext highlighter-rouge">l</code> + <code class="language-plaintext highlighter-rouge">o</code> → 合并</td>
      <td>添加 <code class="language-plaintext highlighter-rouge">lo</code></td>
    </tr>
    <tr>
      <td>2</td>
      <td>最高频字符对：<code class="language-plaintext highlighter-rouge">lo</code> + <code class="language-plaintext highlighter-rouge">w</code> → 合并</td>
      <td>添加 <code class="language-plaintext highlighter-rouge">low</code></td>
    </tr>
    <tr>
      <td>3</td>
      <td>最高频字符对：<code class="language-plaintext highlighter-rouge">e</code> + <code class="language-plaintext highlighter-rouge">r</code> → 合并</td>
      <td>添加 <code class="language-plaintext highlighter-rouge">er</code></td>
    </tr>
    <tr>
      <td>4</td>
      <td>最高频字符对：<code class="language-plaintext highlighter-rouge">e</code> + <code class="language-plaintext highlighter-rouge">s</code> → 合并</td>
      <td>添加 <code class="language-plaintext highlighter-rouge">es</code></td>
    </tr>
  </tbody>
</table>

<p>训练完成后，”lower”被分词为 <code class="language-plaintext highlighter-rouge">[low][er]</code>，而不是5个单独的字符。高效！</p>

<h2 id="不同模型的不同分词器">不同模型的不同分词器</h2>

<p>并非所有LLM都使用相同的分词器。下面是一个快速概览：</p>

<p><img src="/assets/images/blog/tokenizer-comparison.svg" alt="分词器对比表" /></p>

<h3 id="bpe字节对编码byte-pair-encoding">BPE（字节对编码，Byte Pair Encoding）</h3>
<ul>
  <li><strong>使用者：</strong> GPT-2、GPT-3、GPT-4、LLaMA、Mistral、Claude</li>
  <li><strong>工作原理：</strong> 迭代地合并高频字符对</li>
  <li><strong>变体：</strong> Byte-level BPE 从256个字节值开始而非字符，可以处理任何语言和编码</li>
</ul>

<h3 id="wordpiece">WordPiece</h3>
<ul>
  <li><strong>使用者：</strong> BERT、DistilBERT、Electra</li>
  <li><strong>工作原理：</strong> 类似BPE，但根据似然度选择合并（哪个合并最能提高训练数据的概率）</li>
  <li><strong>关键区别：</strong> 使用 <code class="language-plaintext highlighter-rouge">##</code> 前缀表示子词的延续部分（如 “playing” → <code class="language-plaintext highlighter-rouge">play</code> + <code class="language-plaintext highlighter-rouge">##ing</code>）</li>
</ul>

<h3 id="sentencepieceunigram">SentencePiece（Unigram）</h3>
<ul>
  <li><strong>使用者：</strong> T5、ALBERT、XLNet、Gemma</li>
  <li><strong>工作原理：</strong> 从一个大词汇表开始，逐步移除对整体似然度影响最小的词元</li>
  <li><strong>关键区别：</strong> 将文本视为原始字节流（不需要先按空格预分词），因此非常适合多语言模型</li>
</ul>

<h3 id="tiktokenopenai的实现">Tiktoken（OpenAI的实现）</h3>
<ul>
  <li><strong>GPT-4：</strong> 使用 <code class="language-plaintext highlighter-rouge">cl100k_base</code>，约10万个词元</li>
  <li><strong>GPT-4o：</strong> 使用 <code class="language-plaintext highlighter-rouge">o200k_base</code>，约20万个词元（词汇量翻倍！）</li>
  <li>更大的词汇表 = 更多单词成为单个词元 = 更快的推理速度</li>
</ul>

<h2 id="中文怎么办跨语言的分词挑战">中文怎么办？跨语言的分词挑战</h2>

<p>英文单词之间有空格。中文、日文和泰文没有。那”我喜欢人工智能”应该从哪里切分呢？</p>

<ul>
  <li><strong>字符级别：</strong> <code class="language-plaintext highlighter-rouge">[我][喜][欢][人][工][智][能]</code> — 7个词元。安全但浪费。</li>
  <li><strong>词级别：</strong> <code class="language-plaintext highlighter-rouge">[我][喜欢][人工智能]</code> — 3个词元。高效但需要先用分词工具。</li>
  <li><strong>子词（BPE）：</strong> 一种折中方案——常见词如 <code class="language-plaintext highlighter-rouge">人工智能</code> 变成单个词元，罕见词则被拆分。</li>
</ul>

<p>关键性的突破是 <strong>SentencePiece</strong>，它把输入当作原始字节流处理，而不是假设单词之间有空格。这使得它可以自然地适用于任何语言。这就是为什么它是T5和Gemma等多语言模型的首选方案。</p>

<p>词汇表大小在这里也很重要。GPT-4o的分词器（o200k_base，20万词元）是GPT-4（cl100k_base，10万词元）的两倍大，其中很大一部分新增词元都给了非英语语言。试着把中文文本粘贴到 <a href="https://tiktokenizer.vercel.app/">Tiktokenizer</a> 里看看——GPT-4o对于同样的输入一致地产生更少的词元。</p>

<h2 id="自己动手试试">自己动手试试！</h2>

<p>想看看不同的模型是怎么分词的？试试这个很棒的在线工具：</p>

<p><strong><a href="https://tiktokenizer.vercel.app/">Tiktokenizer</a></strong> — 粘贴任意文本，就能看到GPT-4、GPT-3.5和其他模型是怎么把它拆成词元的。</p>

<p>试着输入”httpstatus”看看它怎么切分！然后再试试”h t t p s t a t u s”（带空格），注意它们的区别。</p>

<h2 id="那到底怎么才能让llm正确地反转字母">那到底怎么才能让LLM正确地反转字母？</h2>

<p>既然我们已经理解了问题所在，以下是一些有效的解决方案：</p>

<h3 id="方法一先把字符分开">方法一：先把字符分开</h3>

<p>最简单的办法——给模型它真正能”看到”的字符：</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Instead of: "Reverse: httpstatus"
# Do this:
</span><span class="n">prompt</span> <span class="o">=</span> <span class="s">"""The letters are: h, t, t, p, s, t, a, t, u, s
Now write them in reverse order, separated by commas:"""</span>
<span class="c1"># Output: s, u, t, a, t, s, p, t, t, h
# Then join: "sutatsptth" ✓
</span></code></pre></div></div>

<h3 id="方法二思维链chain-of-thought逐步推理">方法二：思维链（Chain-of-Thought，逐步推理）</h3>

<p>让模型先列出所有字母，然后再反转：</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">prompt</span> <span class="o">=</span> <span class="s">"""Reverse the letters in "httpstatus".

Step 1: List each letter with its position:
Position 1: h
Position 2: t
Position 3: t
Position 4: p
Position 5: s
Position 6: t
Position 7: a
Position 8: t
Position 9: u
Position 10: s

Step 2: Now list them from last position to first:"""</span>
</code></pre></div></div>

<h3 id="方法三使用代码执行">方法三：使用代码执行</h3>

<p>最可靠的方法——让模型写代码然后运行：</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">prompt</span> <span class="o">=</span> <span class="s">"""Write Python code to reverse the string "httpstatus" 
and output only the result."""</span>

<span class="c1"># Model outputs: print("httpstatus"[::-1])
# Result: sutatsptth ✓
</span></code></pre></div></div>

<h3 id="方法四针对字符级任务的微调fine-tuning">方法四：针对字符级任务的微调（Fine-tuning）</h3>

<p>对于生产系统，可以使用<strong>词元内部位置感知（Token Internal Position Awareness, TIPA）</strong> 来微调模型——训练它们完成需要知道词元内字符位置的任务。这是一个活跃的研究方向。</p>

<h2 id="核心要点">核心要点</h2>

<ol>
  <li><strong>LLM看不到单个字母</strong> — 它们看到的是词元（文本块）</li>
  <li><strong>分词（Tokenization）是一种权衡</strong>：效率 vs. 字符级感知能力</li>
  <li><strong>对AI来说，”简单”的文本任务可能很难</strong> — 当这些任务需要字母级别的操作时</li>
  <li><strong>变通方法是有的</strong>：字符分离、思维链和代码执行都能帮上忙</li>
  <li><strong>分词器就是AI的”眼睛”</strong> — 它的能力和局限性决定了模型能做什么</li>
</ol>

<p style="font-size: 1.4em; font-style: italic; text-align: center; margin: 2rem 0;">AI并非误解了语言——它从未以我们的方式看过语言。</p>

<hr />

<h2 id="参考资源">参考资源</h2>

<ul>
  <li><a href="https://tiktokenizer.vercel.app/">Tiktokenizer — Online Tokenizer Visualization Tool</a></li>
  <li><a href="https://www.youtube.com/watch?v=7xTGNNLPyMI">Let’s Build the GPT Tokenizer — Andrej Karpathy (YouTube)</a></li>
  <li><a href="https://huggingface.co/docs/transformers/en/tokenizer_summary">Hugging Face — Tokenization Algorithms Summary</a></li>
  <li><a href="https://huggingface.co/learn/llm-course/en/chapter6/5">Hugging Face — BPE Tokenization Explained</a></li>
  <li><a href="https://github.com/openai/tiktoken">OpenAI Tiktoken Library (GitHub)</a></li>
  <li><a href="https://nebius.com/blog/posts/how-tokenizers-work-in-ai-models">How Tokenizers Work in AI Models (Nebius)</a></li>
  <li><a href="https://sebastianraschka.com/blog/2025/bpe-from-scratch.html">Sebastian Raschka — Implementing BPE from Scratch</a></li>
  <li><a href="https://arxiv.org/html/2412.18626v1">Why LLMs Struggle to Count Letters (arXiv)</a></li>
</ul>]]></content><author><name>Zhipeng Bao</name></author><category term="AI" /><category term="LLM" /><category term="tokenization" /><category term="NLP" /><category term="tutorial" /><summary type="html"><![CDATA[你有没有让ChatGPT把一个单词倒过来拼，结果它给了你一个错误答案？我就遇到过——然后我就掉进了一个关于AI到底是怎么”阅读”文字的兔子洞。]]></summary></entry></feed>