<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Posts on Renxin's Blog</title><link>https://renxinblog.cn/post/</link><description>Recent content in Posts on Renxin's Blog</description><generator>Hugo -- gohugo.io</generator><language>zh</language><lastBuildDate>Fri, 17 Jul 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://renxinblog.cn/post/index.xml" rel="self" type="application/rss+xml"/><item><title>高善文说的「阴谋论与类比」：中国人的思维方式到底怎么了</title><link>https://renxinblog.cn/post/gaoshanwen-thinking/</link><pubDate>Fri, 17 Jul 2026 00:00:00 +0000</pubDate><guid>https://renxinblog.cn/post/gaoshanwen-thinking/</guid><description>&lt;p&gt;2026 年 7 月 7 日，高善文走了。55 岁，T 细胞淋巴瘤。&lt;/p&gt;
&lt;p&gt;这个名字对不关注宏观经济的人可能陌生。他是安信证券的首席经济学家，业内公认的中国宏观分析第一人。他以数据驱动、逻辑严密著称，多次准确预判经济拐点。但在生命的最后几年，他因为一场演讲被禁言，社交账号被封，淡出公众视野。&lt;/p&gt;
&lt;p&gt;那场演讲是 2018 年的，山西证券 30 周年活动上。&lt;/p&gt;
&lt;p&gt;演讲里他搞了一个多小时的经济分析，但流传最广、争议最大、也最让人无法回避的，是其中一小段——关于中国人理解世界的方式。他说：&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;中国人理解世界的方式，不是观察和逻辑推导，而是阴谋论和类比。翻开二十四史，每一页都写满了阴谋。讲复杂道理听不懂，打个比方他马上就明白了。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;这话很刺耳。但如果你愿意放下防御心，仔细想一想，会发现它指向了一个比任何经济问题都更根本的问题——&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;你用什么方式理解这个世界？&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="高善文到底说了什么"&gt;高善文到底说了什么
&lt;/h2&gt;&lt;p&gt;先还原他说这话的上下文，免得断章取义。&lt;/p&gt;
&lt;p&gt;高善文不是在做文化批评，他是在解释一个困惑：为什么中国 180 年的现代化道路如此艰难。他的诊断是：不是不够努力，不是不够聪明，而是在重大历史关头的&lt;strong&gt;认知方式&lt;/strong&gt;出了问题。&lt;/p&gt;
&lt;p&gt;他对比了两种认知工具：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;&lt;/th&gt;
					&lt;th&gt;西方思维&lt;/th&gt;
					&lt;th&gt;中国思维&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;核心工具&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;客观观察 + 逻辑推导&lt;/td&gt;
					&lt;td&gt;阴谋论 + 类比&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;典型表现&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;测量、实验、因果推理&lt;/td&gt;
					&lt;td&gt;「背后一定有人搞鬼」「打个比方说」&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;历史根源&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;古希腊理性传统 + 启蒙运动&lt;/td&gt;
					&lt;td&gt;二十四史权谋叙事 + 象形文字&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;他不是说中国没有逻辑——中国有文言文、有考据学、有辩证逻辑。他说的是&lt;strong&gt;在重大选择面前，我们下意识依赖的工具&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;证据？他举了 180 年的历史：&lt;/p&gt;
&lt;p&gt;1840 年鸦片战争，面对工业文明的冲击，选择「师夷长技以制夷」——用类比理解西方：不过是船坚炮利，我们的道德文化更高。1895 年甲午战败，洋务运动的赌注全输。1949 年后的三十年，再次用阶级斗争的叙事解释经济问题。直到 1978 年改革开放，邓小平「蒙对」了——没有用任何宏大叙事，只是观察、尝试、调整。&lt;/p&gt;
&lt;p&gt;180 年里，多数时候站在了错误的方向。&lt;/p&gt;
&lt;p&gt;这个判断有多大的覆盖面不好说，但有一个现象他指出来了：当中国人和美国人坐在一起谈判时，「永远是两条平行线」。中国人说「太平洋足够大，可以容纳两个超级大国」——这是一个类比。美国人听完一脸困惑：你到底想表达什么？&lt;/p&gt;
&lt;h2 id="象形文字塑造的思维"&gt;象形文字塑造的思维
&lt;/h2&gt;&lt;p&gt;高善文没有深入讨论的一个维度，是语言本身。&lt;/p&gt;
&lt;p&gt;有一个经典的假说叫萨丕尔-沃尔夫假说（Sapir-Whorf hypothesis），核心观点就一句话：&lt;strong&gt;语言影响思维&lt;/strong&gt;。你用什么语言表达世界，会影响你怎么理解世界。&lt;/p&gt;
&lt;p&gt;汉字是表意文字（象形），拼音文字是表音文字。这个差异远不止写起来不一样——它对应的是完全不同的认知路径。&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;%%{init: {'theme':'neutral', 'fontFamily':'monospace'}}%%
flowchart LR
 subgraph 汉字["🀄 汉字：表意文字"]
 A1["看到字形"] --&gt; A2["联想意象"]
 A2 --&gt; A3["理解含义"]
 end
 subgraph 拼音["🔤 拼音文字"]
 B1["看到字母"] --&gt; B2["拼读音节"]
 B2 --&gt; B3["理解含义"]
 end
 style 汉字 fill:#fef3c7,stroke:#d97706,color:#78350f
 style 拼音 fill:#dbeafe,stroke:#2563eb,color:#1e3a5f&lt;/pre&gt;&lt;p&gt;读汉字时，大脑右半球（空间、整体、意象处理）会更多地参与进来。读拼音文字时，大脑左半球（语言、序列、逻辑处理）是主导。这不是猜测——脑功能成像研究已经反复验证了这个差异。&lt;/p&gt;
&lt;p&gt;这不是说一种比另一种高级。任何一种语言都能表达复杂的思想。问题是：&lt;strong&gt;当你习惯了通过意象联想来理解世界，你可能会不自觉地回避逻辑链条的展开。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;打个比方（你看，这就是类比思维）——如果你习惯了看一幅画来理解一个故事，你就不太容易养成逐句推理的习惯。不是不能推，是不习惯。而不习惯的后果是，当有人抛出一个精心构造的比喻时，你很难在第一时间发现那个比喻里的逻辑漏洞。&lt;/p&gt;
&lt;h2 id="类比思维的双刃剑"&gt;类比思维的双刃剑
&lt;/h2&gt;&lt;p&gt;到这里需要做一个重要的纠偏：&lt;strong&gt;不是说类比不好，也不是说中国人不会逻辑。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;跨文化心理学在这方面的研究更公允。Nisbett 的经典著作 &lt;em&gt;The Geography of Thought&lt;/em&gt;（《思维的地域性》）系统比较了东亚人和西方人的认知风格差异：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;维度&lt;/th&gt;
					&lt;th&gt;东亚认知风格&lt;/th&gt;
					&lt;th&gt;西方认知风格&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;注意力&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;整体性——关注背景和关系&lt;/td&gt;
					&lt;td&gt;分析性——关注对象和类别&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;归因&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;情境归因——行为由环境决定&lt;/td&gt;
					&lt;td&gt;特质归因——行为由内在特质决定&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;推理&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;辩证——接受矛盾共存&lt;/td&gt;
					&lt;td&gt;逻辑——排中律，非此即彼&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;解释方式&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;关联性思维——「事物是相互联系的」&lt;/td&gt;
					&lt;td&gt;因果性思维——「A 导致 B」&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;2019 年发表在 &lt;em&gt;Taylor &amp;amp; Francis&lt;/em&gt; 上的一篇综述进一步深化了这个框架：研究者区分了「朴素辩证思维」（naïve dialectical thinking）和「线性思维」（linear thinking），认为两者的差异源于——&lt;strong&gt;个体主义 vs 集体主义的社会结构、分析性 vs 整体性的认知习惯、以及不同的哲学传统&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;所以高善文的判断在学术框架里是有支撑的。中国人确实更倾向于用类比、关联、辩证的方式来理解世界。这不是缺陷，是特征。但当这个特征&lt;strong&gt;独占了你的认知工具箱&lt;/strong&gt;，问题就来了。&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;%%{init: {'theme':'neutral', 'fontFamily':'monospace'}}%%
flowchart LR
 认知工具["认知工具箱"] --&gt; 类比["类比思维&lt;br/&gt;整体·关联·辩证"]
 认知工具 --&gt; 逻辑["逻辑思维&lt;br/&gt;分析·因果·验证"]
 类比 --&gt; 优势["优势：快速理解&lt;br/&gt;复杂概念"]
 类比 --&gt; 盲区["盲区：容易忽略&lt;br/&gt;逻辑漏洞"]
 逻辑 --&gt; 优势2["优势：可验证&lt;br/&gt;可推翻"]
 逻辑 --&gt; 盲区2["盲区：抽象难懂&lt;br/&gt;缺乏画面感"]
 style 认知工具 fill:#fef3c7,stroke:#d97706,color:#78350f
 style 类比 fill:#dbeafe,stroke:#2563eb,color:#1e3a5f
 style 逻辑 fill:#d1fae5,stroke:#059669,color:#064e3b&lt;/pre&gt;&lt;p&gt;类比是强大的认知工具。物理学家费曼用「台球碰撞」解释量子力学，爱因斯坦用「坐光速行驶的火车」解释相对论——这些都是类比。但费曼和爱因斯坦在做完类比后，会用数学公式和实验数据去验证那个类比是否站得住脚。&lt;/p&gt;
&lt;p&gt;高善文说的「阴谋论+类比」的真正问题不是用了类比，而是&lt;strong&gt;只用类比&lt;/strong&gt;。当你说「经济下行就像一个人生病了」，然后用这个类比推导出「所以应该这样治」——你在做的是把两个可能毫不相干的事物用相似性连接起来，而不是在建立因果关系。&lt;/p&gt;
&lt;p&gt;一个典型的例子：有人说「中国经济就像 90 年代的日本，所以会失去三十年」。这是一个类比。但中国和日本的人口结构、城镇化率、国际环境、产业升级路径完全不同。用类比推导出的结论，可能离真相很远。但你很难用「这是个类比，所以不一定成立」去说服一个人——因为在他的认知框架里，类比就是论证。&lt;/p&gt;
&lt;h2 id="认知上的窗口期"&gt;认知上的窗口期
&lt;/h2&gt;&lt;p&gt;高善文在演讲的最后说了这样一段话：&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;对 30 岁以下的年轻人来讲，如果这次没搞对，大家就回去吃屎吧。我们这个年纪的人已经无所谓了，但是对年轻人来讲，我们确实站在一个非常重要的选择关头。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;这话说得非常重。但联系上下文看，他说的不仅是经济政策的对错，更是认知方式上的选择。&lt;/p&gt;
&lt;p&gt;你用什么方式理解世界，决定了你在关键时刻能做出什么样的判断。&lt;/p&gt;
&lt;p&gt;用类比理解的半懂不懂，以为自己懂了；用逻辑推导可能到不了 100% 的确定性，但你知道自己推导到了哪一步、哪里还不确定。后一种方式不保证结论正确，但它保证你能发现自己哪里错了——而这恰恰是前一种方式做不到的。&lt;/p&gt;
&lt;p&gt;意识到自己用的是哪种思维方式，本身就是一种认知升级。不是要你放弃类比——它是人类认知的基础能力。而是至少做到：&lt;strong&gt;当你用了一个类比的时候，知道自己在用类比，而不是把它当成了论证。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;高善文走了。一个敢用数据说话、敢于指出房间里那头大象的经济学家，在 55 岁离开了。但他提出的那个问题还在——你用什么方式理解这个世界？&lt;/p&gt;
&lt;p&gt;如果你觉得这话有道理，那不妨从一件小事开始：下次读到一篇用「打个比方说」开头的分析文章时，停一下，问自己一个问题——这个比方真的成立吗？&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;参考资料&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;高善文，&lt;em&gt;山西证券30周年演讲&lt;/em&gt;，2018-07-28。高博因该演讲被禁言，2026年7月7日病逝。&lt;/li&gt;
&lt;li&gt;Sapir, E. (1929). &lt;em&gt;The Status of Linguistics as a Science&lt;/em&gt;. Linguistic relativity 经典论述。&lt;/li&gt;
&lt;li&gt;Nisbett, R. E. (2003). &lt;em&gt;The Geography of Thought: How Asians and Westerners Think Differently…and Why&lt;/em&gt;. Free Press.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Explanations for cultural differences in thinking: Easterners&amp;rsquo; dialectical thinking and Westerners&amp;rsquo; linear thinking&lt;/em&gt;. Taylor &amp;amp; Francis, 2019.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Brain activation in the processing of Chinese characters and words: A functional MRI study&lt;/em&gt;. PMC, 2021.&lt;/li&gt;
&lt;li&gt;Guan, T. (2024). &lt;em&gt;Conspiracy Theories in Contemporary China: A Review&lt;/em&gt;. ResearchGate.&lt;/li&gt;
&lt;li&gt;经济观察网，&lt;em&gt;纪念高善文：那个敢说真话、爱自嘲的知名经济学家走了&lt;/em&gt;，2026-07-07.&lt;/li&gt;
&lt;li&gt;RFI，&lt;em&gt;《华尔街日报》回顾高善文生命最后一年&lt;/em&gt;，2026-07-15.&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>你其实不需要更强的模型</title><link>https://renxinblog.cn/post/you-dont-need-stronger-models/</link><pubDate>Fri, 17 Jul 2026 00:00:00 +0000</pubDate><guid>https://renxinblog.cn/post/you-dont-need-stronger-models/</guid><description>&lt;p&gt;你有没有这样一种感觉——&lt;/p&gt;
&lt;p&gt;2023 年用上 GPT-4 的时候，那种震撼是真实的：它居然能写代码、能推理、能理解上下文。每发布一个新版本，你会迫不及待去试。但现在呢？GPT-5.6 发布了、Claude Fable 5 来了、Kimi K3 也出来了——你的第一反应是不是变成了：「哦，又强了一点。」&lt;/p&gt;
&lt;p&gt;不是它们不够强。GPT-5.6 Sol 在复杂推理上确实甩开了上一代一大截。问题在于：&lt;strong&gt;你 90% 的日常任务，两三年前的模型就已经够用了。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这不是观点，是正在发生的现实。这篇不聊模型有多强，聊一个更实际的问题——为什么大部分 AI 项目依然在失败，以及真正该花精力在什么地方。&lt;/p&gt;
&lt;h2 id="2026-年的模型版图"&gt;2026 年的模型版图
&lt;/h2&gt;&lt;p&gt;先看看我们现在有什么。&lt;/p&gt;
&lt;p&gt;把今天的主流模型放在一张图里，按能力和价格两个维度看：&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;%%{init: {'theme':'neutral', 'fontFamily':'monospace'}}%%
flowchart LR
 经济层["💰 经济层&lt;br/&gt;$0.10-0.50/1M 输入"] --&gt;|"80% 日常任务"| 日常["分类/提取/摘要&lt;br/&gt;客服/简单推理"]
 主力层["🔋 主力层&lt;br/&gt;$2-3/1M 输入"] --&gt;|"15% 复杂任务"| 复杂["多步推理&lt;br/&gt;长文档分析"]
 旗舰层["🚀 旗舰层&lt;br/&gt;$5-10/1M 输入"] --&gt;|"5% 特殊场景"| 特殊["高难度代码&lt;br/&gt;研究级分析"]
 style 经济层 fill:#d1fae5,stroke:#059669,color:#064e3b
 style 主力层 fill:#dbeafe,stroke:#2563eb,color:#1e3a5f
 style 旗舰层 fill:#fef3c7,stroke:#d97706,color:#78350f
 style 日常 fill:#d1fae5,stroke:#059669,color:#064e3b
 style 复杂 fill:#dbeafe,stroke:#2563eb,color:#1e3a5f
 style 特殊 fill:#fef3c7,stroke:#d97706,color:#78350f&lt;/pre&gt;&lt;p&gt;数据来源：OpenRouter API（2026-07 实时定价），涵盖 344 个模型。&lt;a class="link" href="https://openai.com/index/gpt-5-6/" target="_blank" rel="noopener"
 &gt;OpenAI GPT-5.6&lt;/a&gt; 于 2026 年 7 月 9 日发布，&lt;a class="link" href="https://www.anthropic.com/news/claude-fable-5-mythos-5" target="_blank" rel="noopener"
 &gt;Claude Fable 5&lt;/a&gt; 于 6 月 9 日发布。&lt;a class="link" href="https://api-docs.deepseek.com/news/news260424/" target="_blank" rel="noopener"
 &gt;DeepSeek V4 Pro&lt;/a&gt; 于 4 月开源，1.6T 参数/49B 活跃参数，1M 上下文。&lt;a class="link" href="https://apnews.com/article/kimi-k3-china-ai-0d8a5e268deb11a673f4d444fc597cc5" target="_blank" rel="noopener"
 &gt;Kimi K3&lt;/a&gt; 据称可媲美 OpenAI 和 Anthropic 的旗舰模型。&lt;/p&gt;
&lt;p&gt;这张图的信息量比看起来大。注意定价跨度——旗舰层和主力层之间是 5-10 倍的价格差，和 DeepSeek V4 Flash 比更是 100 倍的差距。更深层的信号是：&lt;strong&gt;经济层的模型能力线已经远远到了日常任务「够用」的基准线之上。&lt;/strong&gt; 日常任务不需要旗舰模型的原因不是「没钱」，是「没必要」。&lt;/p&gt;
&lt;h2 id="80155-的分层现实"&gt;80/15/5 的分层现实
&lt;/h2&gt;&lt;p&gt;那实际在用的时候是怎么选的？&lt;/p&gt;
&lt;p&gt;以我托管的 hermes-home 多 Agent 系统为例——它跑着 7 个 Agent，每天处理调研、写作、决策分析、知识管理等任务。实际用量比例：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;层级&lt;/th&gt;
					&lt;th&gt;模型&lt;/th&gt;
					&lt;th style="text-align: center"&gt;用量&lt;/th&gt;
					&lt;th&gt;场景&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;经济层&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;DeepSeek V4 Pro（$0.44）&lt;/td&gt;
					&lt;td style="text-align: center"&gt;&lt;strong&gt;~80%&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;日常推理、内容生成、知识检索、决策辅助&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;主力层&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;GPT-5.6 Luna（$1.00）&lt;/td&gt;
					&lt;td style="text-align: center"&gt;&lt;strong&gt;~15%&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;需要更强推理能力的复杂任务&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;旗舰层&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;GPT-5.6 Sol / Claude Fable 5&lt;/td&gt;
					&lt;td style="text-align: center"&gt;&lt;strong&gt;~5%&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;高难度代码生成、架构设计、研究级分析&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;这不是预算问题。换成 DeepSeek V4 Pro 每百万 token 只需 $0.44，全跑旗舰模型（Claude Fable 5 $10/1M）也就多花二十几倍。真正的原因是：&lt;strong&gt;对于 80% 的任务，换旗舰模型的提升用户感知不到。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;写一篇博客、整理一份调研、做一个决策分析——这些任务 DeepSeek V4 Pro 完成得很好。只有当你需要处理极其复杂的推理链条、或者生成需要深度理解上下文的高难度代码时，旗舰模型的优势才会显现。而且即便是这些时候，差距也在快速缩小：DeepSeek V4 Pro 的 Benchmark 已经追平了两年前的旗舰模型。&lt;/p&gt;
&lt;p&gt;现在，旗舰模型针对的是「不可能轻松做到的业务」，是「需要博士级的研究分析」，是「5% 的场景」。大部分公司的绝大部分业务和大部分个人的日常任务，处在那个 80% 的范围内。&lt;/p&gt;
&lt;h2 id="ai-项目真正的死因"&gt;AI 项目真正的死因
&lt;/h2&gt;&lt;p&gt;如果模型已经够用了，那为什么那么多 AI 项目还是失败了？&lt;/p&gt;
&lt;p&gt;RAND 公司对 65 个企业 AI 项目的元分析给出了一个发人深省的数字：&lt;strong&gt;80% 的企业 AI 项目以失败告终。&lt;/strong&gt; Gartner 的追踪数据给出了类似的结论，MIT 的研究甚至将这个比例推高到了 95%。这些项目不是用 DeepSeek V4 Pro 做的——很多花了大价钱上了最好的模型。&lt;/p&gt;
&lt;p&gt;导致项目失败的原因，排在最前面的从来不是「模型不够聪明」。&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;%%{init: {'theme':'neutral', 'fontFamily':'monospace'}}%%
flowchart LR
 模型["📈 模型能力&lt;br/&gt;飞速提升"] --&gt;|"但……"| 失败["⚠️ 80-95% 项目失败"]
 失败 --&gt; 根因["为什么失败？"]
 根因 --&gt; 需求["❌ 需求没挖对&lt;br/&gt;解决了错误的问题"]
 根因 --&gt; 成本["❌ 成本跑飞了&lt;br/&gt;不分层 &gt; 预算超支"]
 根因 --&gt; 工程["❌ 工程不靠谱&lt;br/&gt;缺乏可观测性和错误处理"]
 style 模型 fill:#dbeafe,stroke:#2563eb,color:#1e3a5f
 style 失败 fill:#fecaca,stroke:#dc2626,color:#7f1d1d
 style 根因 fill:#fef3c7,stroke:#d97706,color:#78350f
 style 需求 fill:#fecaca,stroke:#dc2626,color:#7f1d1d
 style 成本 fill:#fecaca,stroke:#dc2626,color:#7f1d1d
 style 工程 fill:#fecaca,stroke:#dc2626,color:#7f1d1d&lt;/pre&gt;&lt;p&gt;数据来源：&lt;a class="link" href="https://mybusinessfuture.com/en/80-ai-failure-rate-2026-how-rand-and-gartner-expose-the-ai/" target="_blank" rel="noopener"
 &gt;RAND 企业 AI 元分析&lt;/a&gt;（65 个项目，80% 失败率）、&lt;a class="link" href="https://www.softwareseni.com/why-95-percent-of-enterprise-ai-projects-fail-mit-research-breakdown-and-implementation-reality-check/" target="_blank" rel="noopener"
 &gt;MIT 研究&lt;/a&gt;（95% 企业 AI 项目未交付价值）。&lt;/p&gt;
&lt;p&gt;我跑了几个月多 Agent 系统，最深的感受就是：&lt;strong&gt;模型从来不是瓶颈。&lt;/strong&gt; 出错最多的地方，永远是需求没对齐、成本估算偏差、以及系统工程的细节。&lt;/p&gt;
&lt;h2 id="真正卡脖子的三件事"&gt;真正卡脖子的三件事
&lt;/h2&gt;&lt;p&gt;如果瓶颈不是模型，那是什么？基于实战观察，我认为有三件事比模型选型重要得多。&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;%%{init: {'theme':'neutral', 'fontFamily':'monospace'}}%%
flowchart LR
 旧认知["过去以为瓶颈&lt;br/&gt;是模型能力"] --&gt; 新认知["实际瓶颈&lt;br/&gt;（三件事）"]
 新认知 --&gt; 需求挖掘["🔍 需求挖掘&lt;br/&gt;解决对的问题"]
 新认知 --&gt; 成本控制["💰 成本控制&lt;br/&gt;分层选型不跑偏"]
 新认知 --&gt; Agent工程["⚙️ Agent 工程&lt;br/&gt;可靠系统需要 Engineering"]
 style 旧认知 fill:#fecaca,stroke:#dc2626,color:#7f1d1d
 style 新认知 fill:#fef3c7,stroke:#d97706,color:#78350f
 style 需求挖掘 fill:#dbeafe,stroke:#2563eb,color:#1e3a5f
 style 成本控制 fill:#dbeafe,stroke:#2563eb,color:#1e3a5f
 style Agent工程 fill:#dbeafe,stroke:#2563eb,color:#1e3a5f&lt;/pre&gt;&lt;h3 id="需求挖掘你确定你在解决对的问题"&gt;需求挖掘：你确定你在解决对的问题？
&lt;/h3&gt;&lt;p&gt;大部分 AI 项目死得冤枉。团队花了几周时间搭建一个完美的 RAG 流水线，上线后发现用户根本不需要这个功能。或者花了大价钱微调了一个模型，结果业务需求已经变了。&lt;/p&gt;
&lt;p&gt;这不是技术问题，这是需求挖掘问题。一个简单的判断标准：&lt;strong&gt;你能否一句话说清楚「这个 AI 系统做成了，用户的什么行为会改变？」&lt;/strong&gt; 如果你说不清楚，模型再强也没用。&lt;/p&gt;
&lt;p&gt;真实教训：hermes-home 里有一个 Agent 最早的设计是「帮我决定今天做什么」，上线后完全没人用。后来改成「帮我记录和管理待办事项」，用户每天在用。模型没换，Prompt 也没大幅改——换的是解决哪个问题。&lt;/p&gt;
&lt;h3 id="成本控制不分层的架构跑不远"&gt;成本控制：不分层的架构跑不远
&lt;/h3&gt;&lt;p&gt;很多团队的做法是：选一个最强的模型，全量流量都走它。结果第一个月账单出来，团队傻眼了。&lt;/p&gt;
&lt;p&gt;分层的逻辑很简单：&lt;strong&gt;不是所有请求都值得用最好的模型处理。&lt;/strong&gt; 80% 的请求可以用 DeepSeek V4 Pro 甚至 V4 Flash，15% 需要 GPT-5.6 Luna 级别，只有 5% 需要动用旗舰模型。&lt;/p&gt;
&lt;p&gt;实操层面，成本优化的手段远不止分层：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;语义缓存&lt;/strong&gt;：重复查询命中缓存，彻底省掉模型调用&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prompt 压缩&lt;/strong&gt;：精简历史记录和上下文，减少 token 消耗&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fallback 链&lt;/strong&gt;：小模型先处理，处理不了再升级到大模型&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;输出长度控制&lt;/strong&gt;：很多场景不需要完整输出，设置 max_tokens 能省一大半&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;2026 年的行业共识是：一个设计良好的分层架构，可以将 LLM 成本降低 30-50%，同时保持 95% 以上的用户体验不下降。&lt;/p&gt;
&lt;h3 id="agent-工程能力是-engineering-出来的不是模型送过来的"&gt;Agent 工程：能力是 Engineering 出来的，不是模型送过来的
&lt;/h3&gt;&lt;p&gt;这是最容易被忽视、但也是真正的壁垒所在。&lt;/p&gt;
&lt;p&gt;从 GPT-3.5 到 GPT-5.6，模型能力在涨。但把一个 LLM 从「能回答问题」变成「能可靠地完成一个任务」，需要的是一整套工程能力——&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tool 设计&lt;/strong&gt;：模型需要知道自己有什么工具可用，每个工具的输入输出是什么，什么时候该用哪个&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Memory 管理&lt;/strong&gt;：会话历史、长期记忆、知识库检索——怎么存、怎么查、怎么不爆上下文&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;错误处理&lt;/strong&gt;：模型调用超时怎么办？工具返回异常怎么办？重试逻辑怎么写？&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;可观测性&lt;/strong&gt;：每次调用花了多少 token？哪个环节耗时最长？出错了怎么定位？&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;多 Agent 协作&lt;/strong&gt;：多个 Agent 之间怎么发现彼此的能力、怎么传递任务、怎么避免冲突&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些东西，换再强的模型也不会自动变好。它们需要工程投入。&lt;/p&gt;
&lt;h2 id="实战案例一个跑在-deepseek-上的多-agent-系统"&gt;实战案例：一个跑在 DeepSeek 上的多 Agent 系统
&lt;/h2&gt;&lt;p&gt;hermes-home 是一个真实运行的多 Agent 系统，7 个 Agent 分布在云服务器和本地 Docker 中，通过 MCP 协议通信。这个系统 80% 的请求由 DeepSeek V4 Pro 处理。&lt;/p&gt;
&lt;p&gt;它能做什么？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;知识库 Agent 每天自动扫描 GitHub 新项目，整理入库&lt;/li&gt;
&lt;li&gt;博客 Agent 从知识库拉取素材，写成 Hugo 文章并部署&lt;/li&gt;
&lt;li&gt;待办 Agent 管理日常任务并定时提醒&lt;/li&gt;
&lt;li&gt;决策 Agent 综合分析多个来源，给出结构化建议&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所有这些任务，没有一个需要用到 Claude Fable 5 的全能力量。系统的瓶颈从来不在模型能力上——而是在 Tool 设计得够不够好、Memory 管理得够不够稳定、错误处理得够不够健壮。&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;%%{init: {'theme':'neutral', 'fontFamily':'monospace'}}%%
flowchart LR
 subgraph 模型层["模型层 (80% DeepSeek V4 Pro)"]
 A["LLM 推理"]
 end
 subgraph 工程层["工程层 (真正的壁垒)"]
 B["Tool 系统"]
 C["Memory 管理"]
 D["错误处理"]
 E["可观测性"]
 end
 subgraph 应用层["应用层"]
 F["7 个 Agent&lt;br/&gt;调研/写作/决策/待办"]
 end
 A --&gt; B --&gt; C --&gt; D --&gt; E --&gt; F
 style 模型层 fill:#dbeafe,stroke:#2563eb,color:#1e3a5f
 style 工程层 fill:#d1fae5,stroke:#059669,color:#064e3b
 style 应用层 fill:#fef3c7,stroke:#d97706,color:#78350f&lt;/pre&gt;&lt;p&gt;我花了大量时间优化的是中间这一层——Tool 的接口设计、Memory 的持久化策略、错误恢复逻辑、以及每次调用链路的可观测性。这些才是真正决定系统质量的因素。模型只要「够用」就行。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;下次有新模型发布的时候，先问自己三个问题：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;我的瓶颈真的是模型能力吗？&lt;/strong&gt; ——还是需求没挖对、成本没控好、工程没做扎实？&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;换模型能解决我的什么问题？&lt;/strong&gt; ——它会让用户感知到显著提升吗？&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;我的系统有足够好的可观测性吗？&lt;/strong&gt; ——如果你不知道每次调用花在哪、错在哪，换模型就是盲人摸象。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;模型在飞速进步，这是好事。但 &lt;strong&gt;90% 的日常任务已经越过了「够用」的基准线。&lt;/strong&gt; 真正的差距，从来不在模型本身。&lt;/p&gt;
&lt;p&gt;&lt;em&gt;数据来源：OpenRouter API 实时定价、DeepSeek 官方发布公告（2026-04-24）、OpenAI GPT-5.6 官方公告（2026-07-09）、Anthropic Claude Fable 5 公告（2026-06-09）、RAND 企业 AI 项目元分析、AP News Kimi K3 报道。&lt;/em&gt;&lt;/p&gt;</description></item><item><title>县城正在消失，而你还在犹豫要不要走</title><link>https://renxinblog.cn/post/county-disappearing/</link><pubDate>Fri, 17 Jul 2026 00:00:00 +0000</pubDate><guid>https://renxinblog.cn/post/county-disappearing/</guid><description>&lt;p&gt;你有没有在夜间卫星地图上注意过一个细节——&lt;/p&gt;
&lt;p&gt;北上广深的灯光像超新星一样向外蔓延，长三角、珠三角连成一片光海。而越往内陆走，那些曾经亮着星星点点灯光的地方，正在逐年暗淡。&lt;/p&gt;
&lt;p&gt;这不是停电。这是一个正在发生的经济地理学事实：&lt;strong&gt;县城在消失。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;不是物理消失，而是从资源版图上被剥离。&lt;/p&gt;
&lt;p&gt;2026年的中国经济版图上，正在发生一场静默的断裂。一边是AI产业以举国之力狂奔，算力中心日夜不熄，海量资金涌入北上广深的核心研发圈；另一边是两千多个县城，机构缩编、学校撤并、年轻人外出不再回来。&lt;/p&gt;
&lt;p&gt;这两件事之间有一根隐蔽的管道——&lt;strong&gt;资源正在从县城被系统性抽走，注入大城市的新质生产力机器。&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;%%{init: {'theme':'neutral', 'fontFamily':'monospace'}}%%
flowchart LR
 subgraph 大城市["💡 大城市"]
 direction TB
 L1["灯光如超新星&lt;br/&gt;向外蔓延"]
 L2["AI产业聚集&lt;br/&gt;资源持续注入"]
 end

 subgraph 县城["🌑 县城"]
 direction TB
 R1["灯光逐年暗淡"]
 R2["产业萎缩&lt;br/&gt;人口外流"]
 end

 大城市 --&gt;|"虹吸资源"| 县城

 style 大城市 fill:#dbeafe,stroke:#2563eb,color:#1e3a5f
 style 县城 fill:#fecaca,stroke:#dc2626,color:#7f1d1d
 style L1 fill:#dbeafe,stroke:#2563eb,color:#1e3a5f
 style L2 fill:#dbeafe,stroke:#2563eb,color:#1e3a5f
 style R1 fill:#fecaca,stroke:#dc2626,color:#7f1d1d
 style R2 fill:#fecaca,stroke:#dc2626,color:#7f1d1d&lt;/pre&gt;&lt;h2 id="两套政策一张底牌"&gt;两套政策，一张底牌
&lt;/h2&gt;&lt;p&gt;如果你把近三年中国关于AI的支持政策和关于县城的政策放在一起看，会发现这不是两套并行的体系，而是一次明确的资源重新配置。&lt;/p&gt;
&lt;p&gt;AI那一侧的关键词是「新型举国体制」「不惜代价」「资金狂奔」。从中央经济工作会议将新质生产力定为绝对核心驱动力，到东数西算工程、万亿产业大基金源源不断注入特定国家级算力枢纽——AI产业享受的是无限弹药的特权。&lt;/p&gt;
&lt;p&gt;县城那一侧的关键词则变成了「过紧日子」「底线思维」「战略降级」。中央要求人口小县推行机构改革，山西试点县党政机构被砍掉三分之一，事业编制缩减六成。国务院明确下文，要求中西部12个债务高风险省份严控甚至停建新建政府投资项目。县城的主体功能定位，被严格限制在了保证粮食安全、生态安全和服务农业农村上。&lt;/p&gt;
&lt;p&gt;翻译成大白话就是：&lt;strong&gt;你在后方待着，别添乱。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这不是歧视，这是财政分配的现实逻辑。在经济高速增长的年代，国家可以一边给大城市输血，一边通过转移支付给县城修路。那时叫雨露均沾。但现在进入了存量博弈的时代，当国家需要集中几万亿甚至几十万亿去搞大模型、算力中心、黑灯工厂的时候，这笔钱只能通过压缩对县城的转移支付来筹措。&lt;/p&gt;
&lt;p&gt;国家对大城市AI产业的每一次巨额注资，本质上都是对县城资金的一次合法抽血。&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;%%{init: {'theme':'neutral', 'fontFamily':'monospace'}}%%
flowchart LR
 subgraph 中央["💠 中央财政"]
 财源["财政资金"]
 end

 subgraph AI方向["🚀 AI/新质生产力"]
 A1["万亿产业基金"]
 A2["算力中心补贴"]
 A3["芯片研发投入"]
 end

 subgraph 县城方向["🏘️ 县城"]
 B1["转移支付缩减"]
 B2["机构编制压缩"]
 B3["基建项目叫停"]
 end

 财源 --&gt; 优先分配
 优先分配 --&gt; A1
 优先分配 --&gt; A2
 优先分配 --&gt; A3
 优先分配 -.-&gt;|压缩| 县城方向
 style A1 fill:#dbeafe,stroke:#2563eb,color:#1e3a5f
 style A2 fill:#dbeafe,stroke:#2563eb,color:#1e3a5f
 style A3 fill:#dbeafe,stroke:#2563eb,color:#1e3a5f
 style B1 fill:#fecaca,stroke:#dc2626,color:#7f1d1d
 style B2 fill:#fecaca,stroke:#dc2626,color:#7f1d1d
 style B3 fill:#fecaca,stroke:#dc2626,color:#7f1d1d
 style 财源 fill:#fef9c3,stroke:#ca8a04,color:#713f12&lt;/pre&gt;&lt;h2 id="雁行模型的失效廉价劳动力不再值钱"&gt;雁行模型的失效——廉价劳动力不再值钱
&lt;/h2&gt;&lt;p&gt;过去三十年，中国县城之所以还能保住一点工业基础、还能缓解一部分人的就业，全靠一个产业转移机制。&lt;/p&gt;
&lt;p&gt;大城市是头雁。当北京上海深圳的土地和人口成本高到一定程度，那些需要大量劳动力的低端制造业，就会像大雁排队一样，先转移到内地的二线城市，最后落到广大的中西部县城。&lt;/p&gt;
&lt;p&gt;这个模型成立的唯一前提是&lt;strong&gt;劳动力成本的差异&lt;/strong&gt;。县城招商引资最大的也是唯一的底牌就是：我这里人工便宜，只要两三千块钱，地皮几乎白送。&lt;/p&gt;
&lt;p&gt;但到了2026年，这张底牌正在失效。&lt;/p&gt;
&lt;p&gt;AI和智能机器人直接抹平了地理空间上的劳动力成本差异。试想一个场景：如果富士康或比亚迪要扩建产能，它是会把工厂建在距离深圳一千公里外、交通不便、配套落后的内地县城，去管理几万个每月拿三千块的工人，还是会在深圳周边的东莞或惠州，直接建一个全自动化的黑灯工厂？&lt;/p&gt;
&lt;p&gt;答案显而易见。&lt;/p&gt;
&lt;p&gt;搭载了最新AI视觉检测系统、多柔性机械臂的智能生产线全面普及之后，工厂可以24小时无休运转。这些机器人不用交社保、不需要住宿、没有情绪波动、良品率接近100%。即便精算到极致，在长三角珠三角布置一个机器人工位的综合成本，也一定会远远低于中西部县城一个最廉价工人的最低工资。&lt;/p&gt;
&lt;p&gt;既然机器的成本比县城的人工还要低，大企业为什么还要大费周折把产业链向内陆转移？它们完全可以把高度自动化的工厂留在核心城市周边——这里有世界级的港口、即刻可用的现代化物流、以及庞大的都市消费市场。&lt;/p&gt;
&lt;p&gt;这就是新质生产力带来的&lt;strong&gt;产业空间折叠&lt;/strong&gt;。过去产业是分散的，因为人需要吃喝拉撒，需要分布在不同地理空间里。但在AI时代，产业是极度集权的——它不再依赖人，只依赖算力和电力。&lt;/p&gt;
&lt;p&gt;这不仅仅掐断了低端产业向中西部县城转移的生命线，更可怕的是，它还在反方向地绞杀县城原本仅存的初级加工制造业。在机器面前，县城最后的那点廉价劳动力优势，彻底归零了。&lt;/p&gt;
&lt;p&gt;资本不再需要廉价的人，资本需要的是廉价的算力和不知疲倦的机械臂。&lt;/p&gt;
&lt;p&gt;过去，产业沿着成本梯度向下转移：&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;%%{init: {'theme':'neutral', 'fontFamily':'monospace'}}%%
flowchart LR
 A1("一线城市&lt;br/&gt;成本上升") --&gt;|产业外迁| A2("二线城市&lt;br/&gt;承接转移")
 A2 --&gt;|产业外迁| A3("县城&lt;br/&gt;靠廉价劳动力接盘")
 style A1 fill:#dbeafe,stroke:#2563eb,color:#1e3a5f
 style A2 fill:#dbeafe,stroke:#2563eb,color:#1e3a5f
 style A3 fill:#d1fae5,stroke:#059669,color:#064e3b&lt;/pre&gt;&lt;p&gt;现在，AI 让产业不再依赖人，工厂留在了城市圈：&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;%%{init: {'theme':'neutral', 'fontFamily':'monospace'}}%%
flowchart LR
 B1("一线城市&lt;br/&gt;AI + 机器人") --&gt; B2("黑灯工厂&lt;br/&gt;留在城市圈周边")
 B2 -.-&gt;|县城被踢出| B3(❌)
 style B1 fill:#dbeafe,stroke:#2563eb,color:#1e3a5f
 style B2 fill:#d1fae5,stroke:#059669,color:#064e3b
 style B3 fill:#fecaca,stroke:#dc2626,color:#7f1d1d&lt;/pre&gt;&lt;h2 id="ai产业的三个要素每一个都在排斥县城"&gt;AI产业的三个要素，每一个都在排斥县城
&lt;/h2&gt;&lt;p&gt;传统工业时代，基础设施是可以下沉的。你修一条公路到县城，县城就能通车；你拉一根电线到县城，县城的灯就亮了。&lt;/p&gt;
&lt;p&gt;但AI产业的核心要素——&lt;strong&gt;算力、数据、算法人才&lt;/strong&gt;——都具有极端空间排他性，每一个都在天然地抛弃县城。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;算力&lt;/strong&gt;：建设一个顶级的大模型算力中心，不仅需要几百亿的硬件投入，还需要特高压专线电网来保证绝对不能断电，需要海量的水资源来进行液冷散热，需要极低延迟的骨干光纤网络。这些资源国家不可能平均分配给每一个县城——这不经济，也不符合规模报酬递增的规律。更残酷的是，在夏季用电高峰期，为了保证东部核心城市的AI算力中心不断电，中西部某些省份的传统高能耗产业会被行政命令要求错峰生产——让电于算。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;数据&lt;/strong&gt;：高价值的数据来自高密度的数字场景——千万级的日活用户、亿级的交易记录、复杂的线上交互行为。县城没有这些。县城的数字活动是碎片化的、低频的、低价值的。数据不是均匀分布的，它是跟产业密度绑定的。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;人才&lt;/strong&gt;：AI领域的顶尖人才天然向最前沿的公司和机构聚集。这不是因为&amp;quot;大城市好&amp;quot;，而是因为最好的同事、最多的GPU、最快的信息流动都在那里。县城走出去的高端人才，几乎不可能回流。&lt;/p&gt;
&lt;p&gt;更隐蔽也更残酷的是AI产业的&lt;strong&gt;乘数效应差异&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;传统工业时代，一个主导产业会拉动上下游一系列配套产业：汽车工业会拉动钢铁、橡胶、玻璃等上游产业，同时催生公路、加油站、维修店等下游产业。这些关联产业需要大量物理空间的劳动力，财富分配是发散型的，能够惠及县城和小镇。&lt;/p&gt;
&lt;p&gt;但人工智能产业是一个极度罕见的高密度、闭环、单轴产业。它对上下游的索取表现为完全的虹吸而非溢出。上游的算力与芯片抽干县城的廉价电能，中游的模型与算法虹吸县城走出去的全部高端人才，下游的应用则清洗县城本地的中产。&lt;/p&gt;
&lt;p&gt;AI产业链的运行逻辑，本质上就是 &lt;strong&gt;大城市开机、大厂收钱、县城失业、资金北上&lt;/strong&gt; 的财富单向流动机器。&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;%%{init: {'theme':'neutral', 'fontFamily':'monospace'}}%%
flowchart LR
 传统["🏭 传统工业"] --&gt;|"发散型就业→惠及县城"| A["县城受益"]
 AI["🤖 AI产业"] --&gt;|"虹吸型资源→抽干县城"| B["县城受损"]
 style 传统 fill:#dbeafe,stroke:#2563eb,color:#1e3a5f
 style AI fill:#fecaca,stroke:#dc2626,color:#7f1d1d
 style A fill:#d1fae5,stroke:#059669,color:#064e3b
 style B fill:#fecaca,stroke:#dc2626,color:#7f1d1d&lt;/pre&gt;&lt;pre class="mermaid" style="visibility:hidden"&gt;%%{init: {'theme':'neutral', 'fontFamily':'monospace'}}%%
flowchart LR
 上游["⚡ 上游&lt;br/&gt;算力+芯片"] --&gt;|电能| 县城["🏘️ 县城"]
 中游["🧠 中游&lt;br/&gt;模型+算法"] --&gt;|人才| 县城
 下游["📱 下游&lt;br/&gt;AI应用"] --&gt;|岗位| 县城
 上游 --&gt; 中游 --&gt; 下游
 style 上游 fill:#dbeafe,stroke:#2563eb,color:#1e3a5f
 style 中游 fill:#d1fae5,stroke:#059669,color:#064e3b
 style 下游 fill:#d1fae5,stroke:#059669,color:#064e3b
 style 县城 fill:#fecaca,stroke:#dc2626,color:#7f1d1d&lt;/pre&gt;&lt;h2 id="县城经济循环的崩塌正在无声发生"&gt;县城经济循环的崩塌，正在无声发生
&lt;/h2&gt;&lt;p&gt;在经济学中有一个核心概念叫「乘数效应」——一笔初始支出的变动，会通过经济体系内多轮循环消费，引发国民收入数倍于该初始支出的变动。&lt;/p&gt;
&lt;p&gt;在过去的健康状态下，县城的经济循环是这样的：&lt;/p&gt;
&lt;p&gt;外出打工的人寄钱回家 → 这笔钱发给县城的公务员、教师、工程老板 → 这批体制内中产和工程中产去饭店消费、去商场买衣服、去本地学校交学费 → 饭店老板和商场员工赚到了钱，再去菜市场买菜 → 养活县城底层的体力劳动者。&lt;/p&gt;
&lt;p&gt;每一块钱在县城内部流转多次，就能创造出数倍的社会总价值。这就是县城的生命线。&lt;/p&gt;
&lt;p&gt;但现在，三重打击正在让这个循环发生剧烈的&lt;strong&gt;负乘数效应&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第一重打击：外出收入减少。&lt;/strong&gt; 大城市工厂全面换上机器人，服务业开始裁减人工。县城流出人口在大城市能赚到的钱正在大幅缩减。寄回家的汇款少了，县城消费的第一笔源头就断了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第二重打击：工程老板群体消失。&lt;/strong&gt; 顶层设计将资金集中于AI算力投资，县城传统基建项目被全面叫停。工程老板——这批县城最富有的群体——集体熄火了。没有他们的高消费，县城里高档餐厅、汽车维修店、建材市场这些依靠工程群体生存的产业，同步萎缩。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第三重打击：体制内中产萎缩。&lt;/strong&gt; AI大模型正在替代县城的白领岗位——会计、审批人员、文员。再加上人口小县机构改革对编制的大幅缩减，县城里唯一具有持续消费能力的体制内和半体制中产，数量正在急剧缩减。&lt;/p&gt;
&lt;p&gt;当这三重打击叠加发生，负乘数效应就开始循环放大：&lt;/p&gt;
&lt;p&gt;中产不再消费 → 餐馆倒闭 → 菜贩失去收入 → 保洁、搬运工等底层零工也接不到活 → 所有人都在缩减开支 → 更多店铺关门 → 更多就业岗位消失。&lt;/p&gt;
&lt;p&gt;这就是AI和新质生产力背景下，发生在县城底层的、无声无息的经济链式死亡。&lt;/p&gt;
&lt;p&gt;财富被AI技术和国家战略以最高效的方式抽调、压缩、打包，送往了大城市。留给县城的，只是一潭死水。&lt;/p&gt;
&lt;p&gt;过去，县城的经济循环是正向的：&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;%%{init: {'theme':'neutral', 'fontFamily':'monospace'}}%%
flowchart LR
 P1["外出收入汇回"] --&gt; P2["体制内中产消费"]
 P2 --&gt; P3["餐饮/零售/教育等服务"]
 P3 -.-&gt;|循环放大| P1
 style P1 fill:#d1fae5,stroke:#059669,color:#064e3b
 style P2 fill:#d1fae5,stroke:#059669,color:#064e3b
 style P3 fill:#d1fae5,stroke:#059669,color:#064e3b&lt;/pre&gt;&lt;p&gt;但现在，三重打击形成了负向的死亡螺旋：&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;%%{init: {'theme':'neutral', 'fontFamily':'monospace'}}%%
flowchart LR
 N1["①外出收入减少&lt;br/&gt;②工程老板消失&lt;br/&gt;③体制内中产萎缩"] --&gt; N2["中产消费降级"]
 N2 --&gt; N3["餐馆倒闭、底层失业"]
 N3 -.-&gt;|循环放大| N1
 style N1 fill:#fecaca,stroke:#dc2626,color:#7f1d1d
 style N2 fill:#fecaca,stroke:#dc2626,color:#7f1d1d
 style N3 fill:#fecaca,stroke:#dc2626,color:#7f1d1d&lt;/pre&gt;&lt;h2 id="三个不会说谎的硬指标"&gt;三个不会说谎的硬指标
&lt;/h2&gt;&lt;p&gt;逻辑推理可能出错，但数据不会。这里有三个判断县城是否在衰落的硬指标。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第一个指标：存贷差。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这是判断一个地区有没有造血功能最准确的标志。近些年，许多中西部县城的银行数据呈现出诡异的特点：居民存款在上升，但当地企业贷款的发放量却在持续下跌。&lt;/p&gt;
&lt;p&gt;这意味着什么？&lt;/p&gt;
&lt;p&gt;老百姓把辛辛苦苦存下来的钱放进县城的银行，但银行因为当地没有能产生利润的新产业，根本不敢把钱贷给本地企业。更糟糕的是，县城银行的分支机构拿到这笔存款后，通过金融系统内部的资金调度，把这些钱上交给省行和总行。总行拿到钱后，转头就把贷款额度发放给了北京、上海、深圳搞芯片、大模型、自动化工厂的科创巨头。&lt;/p&gt;
&lt;p&gt;结论很清楚：&lt;strong&gt;县城的金融系统已经完全异化为一台巨大的资金抽水机。&lt;/strong&gt; 县城老百姓的血汗钱通过金融工具，转化成了大城市AI公司的研发弹药。县城在用自己的血，养活大城市的再生长。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第二个指标：小学生在校人数。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;房地产研究员和人口经济学家判断一个城市未来五年基本面的最常用指标，就是小学生在校人数。因为这个数据最真实——学籍很难造假，家长也必须跟着孩子走。&lt;/p&gt;
&lt;p&gt;从2024到2026年，绝大多数普通县城的小学生在校人数出现了肉眼可见的下降。背后的推力一方面是总和生育率下降，但更致命的是公共资源的逆向虹吸。国家把钱砸向新基建，县城就没钱了，于是县里开始强制撤并乡村和普通公办学校。但凡有一点认知和购买力的家长，为了不让孩子在教育上掉队，把孩子送往地级市甚至省会去读书，并在那里买房租房。&lt;/p&gt;
&lt;p&gt;在经济学中，孩子是一个家庭资源投射的核心。县城学龄人口的断崖式下跌，意味着当地最有活力的中青年群体以及家庭的核心消费，正在对县城进行一场不可逆的物理逃离。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第三个指标：夜间灯光指数。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;空间遥感经济团队通过对比近五年中国夜间灯光的卫星影像，发现了一个极度撕裂的趋势：北上广深、长三角、中三角等核心都市圈的灯光不仅亮度在增加，而且快速向外蔓延；而那些远离核心都市圈的中西部普通县城，其夜间灯光强度出现了显著的暗淡和收缩。&lt;/p&gt;
&lt;p&gt;这是能源重配的视觉证据。大城市的万家灯火如同夜空中的超新星，吞噬着海量电力，点亮了数字经济的版图。而县城，因为传统高能耗产业被打压、工厂停工，不仅厂房黑了，连路灯都在被节能改造。&lt;/p&gt;
&lt;p&gt;三个指标叠在一起，就是一份对县城衰落的判决书。&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;%%{init: {'theme':'neutral', 'fontFamily':'monospace'}}%%
flowchart LR
 存贷差["📊 存贷差&lt;br/&gt;存款流向大城市企业"] ---&gt; 结论
 学生数["📚 在校生数&lt;br/&gt;学龄人口物理逃离"] ---&gt; 结论["📋 判决书：&lt;br/&gt;县城正在衰落"]
 灯光["🌙 夜间灯光&lt;br/&gt;县城逐年变暗"] ---&gt; 结论

 style 存贷差 fill:#fef3c7,stroke:#d97706,color:#78350f
 style 学生数 fill:#fef3c7,stroke:#d97706,color:#78350f
 style 灯光 fill:#fef3c7,stroke:#d97706,color:#78350f
 style 结论 fill:#fecaca,stroke:#dc2626,color:#7f1d1d&lt;/pre&gt;&lt;h2 id="个体怎么办不是恐慌是规划"&gt;个体怎么办：不是恐慌，是规划
&lt;/h2&gt;&lt;p&gt;前面的分析不是让人绝望的。看清楚了趋势，反而可以开始行动。&lt;/p&gt;
&lt;p&gt;在这个以新质生产力和算力集权为核心的大背景下，那些没有特定禀赋的普通县城，在宏观的战略沙盘里已经被正式定位为一种社会缓冲带——只需要按惯性待在那里，维持最低限度的消耗，不给前线正在打科技战的大城市添乱。&lt;/p&gt;
&lt;p&gt;但个体完全可以主动选择。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第一条路：境内移民。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这不是今天收拾行李明天冲去北上广深。而是把你的人生坐标从&amp;quot;我出生在哪里&amp;quot;慢慢改成&amp;quot;哪里更值得我长期配置自己&amp;quot;。&lt;/p&gt;
&lt;p&gt;一个三年的计划：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;阶段&lt;/th&gt;
					&lt;th&gt;时间&lt;/th&gt;
					&lt;th&gt;任务&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;信息迁移&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;第一年&lt;/td&gt;
					&lt;td&gt;研究目标城市的招聘、房租、工资、产业、学校、医疗、生活成本&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;技能迁移&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;第二年&lt;/td&gt;
					&lt;td&gt;确保你的技能在目标城市能换到钱——如果不够，就补技能：编程、运营、设计、销售、护理、维修、跨境电商、短视频运营，至少选一个能在城市里交易的技能&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;身份迁移&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;第三年&lt;/td&gt;
					&lt;td&gt;社保、居住证、工作、租房、孩子教育、父母医疗，一步一步往目标城市挪&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;你不需要去最贵的一线城市。强二线和核心都市圈——杭州、成都、武汉、苏州、长沙——完全够用。关键不是买不买房，而是先问自己能不能在那边活下来。先租房、先找工作、先看行业、先建立人脉，先让自己在那个城市有一个落脚点。&lt;/p&gt;
&lt;p&gt;普通人的迁移不是浪漫旅行，而是项目管理。你要有时间表，有预算表，有至少六个月的备用金，有一条撤退路线。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第二条路：不移民但接入。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;如果你因为各种原因不能或不想离开县城，那么必须建立&lt;strong&gt;跨空间的货币获取能力&lt;/strong&gt;——通过互联网和数字技术，从大城市的高势能网络中赚钱，而不是在县城里跟存量做内卷。&lt;/p&gt;
&lt;p&gt;远程工作、自由职业、AI工具辅助的个体产出——这些东西不依赖你所在的地理位置，只依赖你接入网络的能力。如果你懂编程，可以远程接外包；如果你懂内容，可以做出海；如果你懂投流，可以在线上做生意。县城的生活成本低，只要你的收入来自大城市的渠道，你反而有套利空间。&lt;/p&gt;
&lt;p&gt;这两条路并不矛盾，甚至可以并行。境内移民解决的是长期的安全边际，跨空间赚钱解决的是当下的收入来源。&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;%%{init: {'theme':'neutral', 'fontFamily':'monospace'}}%%
flowchart LR
 起点["你的选择"] --&gt; 判断{"离开县城？"}
 判断 --&gt;|"是"| 移民["📍 境内移民&lt;br/&gt;三年计划：信息→技能→身份"]
 判断 --&gt;|"否"| 接入["🌐 跨空间赚钱&lt;br/&gt;远程工作/数字产出"]

 style 起点 fill:#fef9c3,stroke:#ca8a04,color:#713f12
 style 判断 fill:#fef9c3,stroke:#ca8a04,color:#713f12
 style 移民 fill:#dbeafe,stroke:#2563eb,color:#1e3a5f
 style 接入 fill:#d1fae5,stroke:#059669,color:#064e3b&lt;/pre&gt;&lt;hr&gt;
&lt;p&gt;回到开头的卫星地图。&lt;/p&gt;
&lt;p&gt;当一座城市的灯光在卫星图上逐年变暗，它不是消失了——它说明这座城市在资源版图上，正在变成&amp;quot;不被看见&amp;quot;的地方。&lt;/p&gt;
&lt;p&gt;你不能决定资源怎么分配，但你可以决定自己往哪里移动。越早开始规划，选择权越大。等到所有人都想走的时候，你才发现自己没有技能、没有存款、没有社保、没有信息渠道——那才是真正的困境。&lt;/p&gt;
&lt;p&gt;这件事情发生之前看起来离你很远，发生之后你才会知道：原来你所在的位置，决定了别人会不会及时看见你。&lt;/p&gt;
&lt;p&gt;这不是鸡汤，这是生存。&lt;/p&gt;
&lt;p&gt;&lt;em&gt;本文观点来自对两期B站视频内容的梳理与分析。&lt;/em&gt;&lt;/p&gt;</description></item><item><title>RAG 是什么？从一条文档的完整旅程说起</title><link>https://renxinblog.cn/post/rag-overview/</link><pubDate>Fri, 10 Jul 2026 00:00:00 +0000</pubDate><guid>https://renxinblog.cn/post/rag-overview/</guid><description>&lt;p&gt;你有没有想过一个问题——&lt;/p&gt;
&lt;p&gt;LLM 训练时读了几万亿字的互联网数据，几乎什么都知道。但它不知道你的业务数据——你的产品手册、售后政策、内部文档、客服对话记录。这些它没读过。&lt;/p&gt;
&lt;p&gt;怎么让它知道该知道的？&lt;/p&gt;
&lt;p&gt;这就是 RAG 要解决的问题。这篇文章从为什么需要 RAG 开始，一直讲到它的完整架构和最容易翻车的地方。&lt;/p&gt;
&lt;h2 id="llm-什么都知道但不知道你的业务"&gt;LLM 什么都知道，但不知道你的业务
&lt;/h2&gt;&lt;p&gt;LLM 有两个先天缺陷，在实际落地中很难绕过去。&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;缺陷&lt;/th&gt;
					&lt;th&gt;表现&lt;/th&gt;
					&lt;th&gt;影响&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;知识截止&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;训练数据停在某个时间点&lt;/td&gt;
					&lt;td&gt;问最新政策、实时数据，它不知道&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;不知道私有数据&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;没读过你的内部文档、产品手册、客服记录&lt;/td&gt;
					&lt;td&gt;业务场景下基本不可用&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;怎么解决？目前有三条路可以走。&lt;/p&gt;
&lt;h3 id="方案一微调fine-tuning"&gt;方案一：微调（Fine-tuning）
&lt;/h3&gt;&lt;p&gt;拿业务数据继续训练模型，让它把新知识学进去。&lt;/p&gt;
&lt;p&gt;听起来最直接，但实际操作成本很高。你需要准备高质量的训练数据、处理算力资源，而且每次业务文档更新了，又得重新训一遍。更麻烦的是，微调可能会破坏模型原有的通用能力——模型学会了你的业务术语，但写邮件的能力反而变差了。&lt;/p&gt;
&lt;h3 id="方案二塞长上下文long-context"&gt;方案二：塞长上下文（Long Context）
&lt;/h3&gt;&lt;p&gt;把所有资料都塞进 Prompt 里，让模型自己翻。&lt;/p&gt;
&lt;p&gt;实现最简单，不用动模型。现在有些模型支持 128K、1M 甚至更长的上下文，看起来够用。但实际效果没那么理想：一是 Token 成本会随着内容量线性增长；二是内容太多之后，模型很难从海量信息中找到准确的那一段——这就是著名的&amp;quot;大海捞针&amp;quot;问题。上下文再长，检索精度是会下降的。&lt;/p&gt;
&lt;h3 id="方案三rag检索增强生成"&gt;方案三：RAG（检索增强生成）
&lt;/h3&gt;&lt;p&gt;每次提问的时候，先去知识库里检索相关内容，拼到 Prompt 里，再让 LLM 基于这些材料回答。&lt;/p&gt;
&lt;p&gt;RAG 是目前最主流的方案。原因很实在：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;成本低&lt;/strong&gt;：不需要重新训练模型，省了算力&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;更新快&lt;/strong&gt;：知识库加个文档就行，不需要重训&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;可追溯&lt;/strong&gt;：LLM 是看着你给的资料回答的，能知道它引用的是哪份文档&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;幻觉少&lt;/strong&gt;：基于具体材料生成，比凭空回答可靠得多&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当然，RAG 也有自己的问题——它依赖检索质量。如果检索到的内容不对或者不完整，LLM 材料再好也回答不对。后面会详细讲这个。&lt;/p&gt;
&lt;h2 id="rag-不是搜索引擎它和搜索引擎的区别"&gt;RAG 不是搜索引擎——它和搜索引擎的区别
&lt;/h2&gt;&lt;p&gt;很多人第一次接触 RAG 的反应是：这不就是搜索引擎吗？用户搜关键词，系统返回匹配的文档——有什么新鲜的？&lt;/p&gt;
&lt;p&gt;这个理解对了一半，错的一半恰好是 RAG 的核心。&lt;/p&gt;
&lt;h3 id="搜索引擎esbm25怎么工作"&gt;搜索引擎（ES/BM25）怎么工作
&lt;/h3&gt;&lt;p&gt;你搜一个关键词，搜索引擎在你的文档库里找到包含这个词的所有文档，按匹配度排序返回。它做的是&lt;strong&gt;关键词精确匹配&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;比如说你搜&amp;quot;2025年Q3营收&amp;quot;，它能找到包含这几个词的那份财报。但如果你问&amp;quot;去年第三季度营收怎么样？&amp;quot;，它可能找不到——因为文档里写的是&amp;quot;2025年Q3营收同比增长15.3%&amp;quot;，关键词对不上。&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;%%{init: {'theme':'neutral'}}%%
graph LR
 A["搜：去年第三季度营收怎么样？"] --&gt; B[ES 关键词匹配]
 B --&gt; C["找到「去年」「第三」「季度」「营收」"]
 C --&gt; D[❌ 文档写的是「Q3营收同比增长15.3%」&lt;br/&gt;关键词对不上，找不到]&lt;/pre&gt;&lt;p&gt;这是一直以来搜索引擎的运作方式。在&amp;quot;搜文档、找文件&amp;quot;的场景下非常好用，但在&amp;quot;回答问题&amp;quot;的场景下就显得力不从心。&lt;/p&gt;
&lt;h3 id="rag向量检索怎么工作"&gt;RAG（向量检索）怎么工作
&lt;/h3&gt;&lt;p&gt;RAG 不一样。它先把你的文档库转成一组向量（可以理解成一组数字坐标），用户提问时也把问题转成向量，然后计算问题向量和文档向量之间的距离。距离越近，说明内容越相关。&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;%%{init: {'theme':'neutral'}}%%
graph LR
 A["同样的问题：去年第三季度营收怎么样？"] --&gt; B[RAG 向量检索]
 B --&gt; C[把问题和文档都转成向量&lt;br/&gt;计算语义距离]
 C --&gt; D[✅ 匹配到「Q3营收同比增长15.3%」&lt;br/&gt;语义相近，找到了]&lt;/pre&gt;&lt;p&gt;&amp;ldquo;去年第三季度营收怎么样？&amp;ldquo;和&amp;quot;2025年Q3营收同比增长15.3%&amp;ldquo;在字面上没有共同的关键词，但在语义上是同一件事。向量检索能捕捉到这种语义上的相近。&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;维度&lt;/th&gt;
					&lt;th&gt;搜索引擎（ES/BM25）&lt;/th&gt;
					&lt;th&gt;RAG（向量检索）&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;匹配方式&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;关键词精确匹配&lt;/td&gt;
					&lt;td&gt;语义匹配&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;搜&amp;quot;苹果&amp;rdquo;&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;返回含&amp;quot;苹果&amp;quot;二字的所有文档&lt;/td&gt;
					&lt;td&gt;能区分你在问水果还是手机品牌&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;输出&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;文档列表&lt;/td&gt;
					&lt;td&gt;相关内容 + LLM 生成的自然语言回答&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;适合场景&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;搜文档、找文件&lt;/td&gt;
					&lt;td&gt;回答问题、知识问答&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;局限性&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;同义词、近义词不识别&lt;/td&gt;
					&lt;td&gt;对数字/专有名词匹配不如精确搜索&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;所以搜索引擎和 RAG 不是替代关系，而是互补关系。生产环境最常用的方案是&lt;strong&gt;混合检索&lt;/strong&gt;：向量检索负责语义匹配，BM25 负责精确匹配，两者互补。&lt;/p&gt;
&lt;p&gt;但语义检索有一个前提条件：内容必须被正确地理解和切分。这就引出了下一个问题。&lt;/p&gt;
&lt;h2 id="一条文档在-rag-系统中的完整旅程"&gt;一条文档在 RAG 系统中的完整旅程
&lt;/h2&gt;&lt;p&gt;语义匹配的效果，很大程度上取决于文档在入库时被处理成了什么样子。一条文档从上传到最终被 LLM 用来回答问题，中间经历了一整套加工管道。&lt;/p&gt;
&lt;a href="https://renxinblog.cn/images/rag-pipeline.svg" target="_blank"&gt;
 &lt;figure&gt;&lt;img src="https://renxinblog.cn/images/rag-pipeline.svg"
 			alt="RAG系统完整管道图" width="100%"&gt;&lt;figcaption&gt;
 			&lt;p&gt;RAG 系统完整管道：入库阶段 → 检索阶段（点击图片查看大图）&lt;/p&gt;
 		&lt;/figcaption&gt;
 &lt;/figure&gt;

&lt;/a&gt;
&lt;h3 id="入库阶段让机器能读懂文档"&gt;入库阶段：让机器能&amp;quot;读懂&amp;quot;文档
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;环节&lt;/th&gt;
					&lt;th&gt;做什么&lt;/th&gt;
					&lt;th&gt;为什么重要&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;文档解析&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;把 PDF、Word、HTML 等格式转成纯文本&lt;/td&gt;
					&lt;td&gt;PDF 看着是文字，实际是一堆坐标指令。解析不好，后面的所有环节都白费&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;文本清洗&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;去噪、去重、格式归一化&lt;/td&gt;
					&lt;td&gt;把乱码、多余的空格、无关的页眉页脚清掉&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;分块&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;把长文本切成语义完整的片段&lt;/td&gt;
					&lt;td&gt;不能整篇检索——太大了检索不准，太小了语境不够&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;向量化&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;用 Embedding 模型把文本片段转成向量&lt;/td&gt;
					&lt;td&gt;向量是语义匹配的基础&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;存入向量库&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;把向量和原文存入向量数据库&lt;/td&gt;
					&lt;td&gt;供后续检索使用&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="检索阶段找到相关内容并让-llm-回答"&gt;检索阶段：找到相关内容并让 LLM 回答
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;环节&lt;/th&gt;
					&lt;th&gt;做什么&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;问题向量化&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;把用户提问也转成向量&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;向量检索&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;在向量库里找距离最近的文档片段&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;重排序&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;对检索结果重新精排，提升 Top 结果的准确率&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;拼入 Prompt&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;把检索到的内容拼到 Prompt 里，加上指令让 LLM 基于材料回答&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="为什么检索质量是关键"&gt;为什么检索质量是关键
&lt;/h3&gt;&lt;p&gt;整个管道里，最核心的瓶颈不是 LLM 本身，而是&lt;strong&gt;检索质量&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;Andrew Ng 在一个分享里提过一个数据：优化 RAG 系统时，检索质量的提升对最终答案准确率的影响远大于模型本身的升级。换句话说，用更强的模型不能弥补检索结果差的问题——模型再聪明，材料给错了也答不对。&lt;/p&gt;
&lt;p&gt;而检索质量又依赖于前面的入库环节：文档解析是否正确、分块是否合理、向量化是否准确。这是一个完整的链路，短板出在任何一环都会影响最终效果。&lt;/p&gt;
&lt;h2 id="最容易在哪里翻车"&gt;最容易在哪里翻车？
&lt;/h2&gt;&lt;p&gt;把各个环节按翻车概率排序，前三个是：&lt;/p&gt;
&lt;h3 id="1-文档解析最大的坑"&gt;1. 文档解析——最大的坑
&lt;/h3&gt;&lt;p&gt;你传上去的文档是 PDF。PDF 看着是文本，但本质上是一堆坐标指令的集合——&amp;ldquo;在坐标 (x,y) 处渲染字符 A，在 (x+5,y) 处渲染字符 B&amp;rdquo;。它并不知道什么是段落、什么是表格、什么是页眉。&lt;/p&gt;
&lt;p&gt;遇到以下几种 PDF，解析很容易翻车：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;PDF 类型&lt;/th&gt;
					&lt;th style="text-align: center"&gt;难度&lt;/th&gt;
					&lt;th&gt;翻车方式&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;数字原生 PDF&lt;/td&gt;
					&lt;td style="text-align: center"&gt;⭐ 简单&lt;/td&gt;
					&lt;td&gt;基本没问题&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;扫描件 PDF（图片）&lt;/td&gt;
					&lt;td style="text-align: center"&gt;⭐⭐⭐ 中等&lt;/td&gt;
					&lt;td&gt;需要 OCR，识别率取决于清晰度&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;双栏/多栏排版&lt;/td&gt;
					&lt;td style="text-align: center"&gt;⭐⭐⭐⭐ 困难&lt;/td&gt;
					&lt;td&gt;阅读顺序恢复错误，左右栏混在一起&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;含表格 PDF&lt;/td&gt;
					&lt;td style="text-align: center"&gt;⭐⭐⭐⭐⭐ 极难&lt;/td&gt;
					&lt;td&gt;无线框表格、合并单元格、跨页表格，很容易解析错位&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;含公式 PDF&lt;/td&gt;
					&lt;td style="text-align: center"&gt;⭐⭐⭐⭐⭐ 极难&lt;/td&gt;
					&lt;td&gt;LaTeX 公式、化学结构式，专用模型才能处理好&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="2-分块切得不合适"&gt;2. 分块——切得不合适
&lt;/h3&gt;&lt;p&gt;解析完的文本不能整篇扔进去检索。整篇检索的问题：一篇文档可能几千字，但用户问的只是其中一小段。整篇匹配会让不相关的内容稀释相关内容的信号。&lt;/p&gt;
&lt;p&gt;但切得太细也不行。比如只切一两句话——检索时可能命中了，但上下文缺失，LLM 看了也不知道前因后果。&lt;/p&gt;
&lt;p&gt;这就是分块的核心矛盾：&lt;strong&gt;检索精度 vs 上下文完整性&lt;/strong&gt;。切小了检索精准但语境不足，切大了语境完整但检索不精准。&lt;/p&gt;
&lt;p&gt;实际生产中有好几种分块策略来解决这个矛盾——按固定大小切、按语义边界切、按文档结构切、父子分块等等。每种策略各有优缺点，选型取决于你的文档类型和场景。&lt;/p&gt;
&lt;h3 id="3-检索精确匹配-vs-语义匹配的盲区"&gt;3. 检索——精确匹配 vs 语义匹配的盲区
&lt;/h3&gt;&lt;p&gt;即使解析和分块都做好了，检索环节仍然可能翻车。典型场景：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;找不到相关内容&lt;/strong&gt;：你的文档里确实有答案，但向量检索没把它排到前面&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;找到太多噪音&lt;/strong&gt;：检索返回了大量不太相关的内容，稀释了有效信号&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;数字/专有名词匹配弱&lt;/strong&gt;：向量检索对&amp;quot;Q3-2025营收同比增长率15.3%&amp;ldquo;这种精确表达不如关键词搜索&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这也是为什么生产环境通常用混合检索——语义 + 关键词组合，取长补短。&lt;/p&gt;
&lt;h2 id="回头看看"&gt;回头看看
&lt;/h2&gt;&lt;p&gt;把整篇文章的问题串起来：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;LLM 不知道你的业务数据
 → 三种方案对比，RAG 最实用（成本低、更新快、可追溯）
 → RAG 不是搜索引擎，是语义匹配
 → 但语义匹配的前提是内容被正确加工
 → 入库阶段：解析 → 清洗 → 分块 → 向量化 → 存储
 → 检索阶段：检索 → 重排序 → 拼入 Prompt → 生成
 → 最容易翻车的地方：解析、分块、检索
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;RAG 看起来简单——&amp;ldquo;查资料再回答&amp;rdquo;——但做了才发现，每一步都有坑。理解了这个全貌，后续不管是选型还是排查问题，都知道问题可能出在哪一环。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;参考资料&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Andrew Ng, &lt;em&gt;Building RAG Agents with LLMs&lt;/em&gt;, DeepLearning.AI, 2025 — 检索质量对 RAG 效果影响的分享&lt;/li&gt;
&lt;li&gt;Lewis et al., &lt;em&gt;Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks&lt;/em&gt;, arXiv:2005.11401, 2020 — RAG 论文原文&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>向量化原理——为什么向量能算语义相似度</title><link>https://renxinblog.cn/post/embedding-principle/</link><pubDate>Fri, 10 Jul 2026 00:00:00 +0000</pubDate><guid>https://renxinblog.cn/post/embedding-principle/</guid><description>&lt;p&gt;你有没有想过一个问题——&lt;/p&gt;
&lt;p&gt;RAG 的核心是「语义匹配」：你说「去年第三季度营收怎么样」，它能找到文档里写的「Q3 营收同比增长 15.3%」。字面不一样，但意思一样。&lt;/p&gt;
&lt;p&gt;这到底是怎么做到的？一段文字怎么变成一个「向量」？为什么两个向量离得近就代表意思相近？&lt;/p&gt;
&lt;p&gt;这篇文章从最基础的概念讲起，不涉及复杂的数学公式。&lt;/p&gt;
&lt;h2 id="人能判断语义相似度机器也能"&gt;人能判断语义相似度，机器也能
&lt;/h2&gt;&lt;p&gt;先想一个简单的问题：人和人之间怎么判断两句话意思差不多？&lt;/p&gt;
&lt;p&gt;「今天天气真好」和「今天阳光明媚」——你一看就知道它们说的是一回事。&lt;/p&gt;
&lt;p&gt;背后的过程很复杂（你用了多年的语言经验、对词汇的理解、对语境的把握），但直觉上很简单：你在大脑里给这两句话各自建立了一个「语义位置」，发现它们靠得很近。&lt;/p&gt;
&lt;p&gt;机器做同样的事，只是用的方法不一样——它用&lt;strong&gt;向量&lt;/strong&gt;来表示语义位置。&lt;/p&gt;
&lt;h2 id="向量是什么一组数字而已"&gt;向量是什么？一组数字而已
&lt;/h2&gt;&lt;p&gt;向量听起来很高深，其实就是一组数字。&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;[0.52, -0.13, 0.87, -0.42, 0.11, ...]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;你可以把向量想象成&lt;strong&gt;语义空间中的一个坐标点&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;比如我们想象一个二维的语义空间，每一段话都对应一个坐标点：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;「今天天气真好」→ 坐标 (0.9, 0.3)
「今天阳光明媚」→ 坐标 (0.8, 0.4)
「苹果很好吃」 → 坐标 (0.1, 0.2)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;在语义空间里，「今天天气真好」和「今天阳光明媚」靠得近（意思相近），和「苹果很好吃」离得远（不相关）。&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://renxinblog.cn/images/semantic-space.svg"
			alt="语义空间坐标示意图" width="80%"&gt;&lt;figcaption&gt;
			&lt;p&gt;二维语义空间示意：意思相近的文本在空间中靠得近&lt;/p&gt;
		&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;当然，现实中的语义向量不是两维，而是几百甚至几千维——但原理一样。两个向量在空间中的距离越近，代表它们的意思越相近。&lt;/p&gt;
&lt;h2 id="语义从哪来embedding-模型怎么训练的"&gt;语义从哪来：Embedding 模型怎么训练的
&lt;/h2&gt;&lt;p&gt;刚才的水果例子是我手动编的维度（甜度、大小）。但在真实场景中，不可能有人来给每个词标注「甜度 = 0.9」这种数据。&lt;/p&gt;
&lt;p&gt;那向量的数值从哪来？答案是 Embedding 模型自己学出来的。&lt;/p&gt;
&lt;p&gt;训练方法的核心思路很简单：&lt;strong&gt;出现在相似语境中的词，应该有相似的向量&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;一个经典的例子：&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;「国王」和「女王」经常出现在类似的句子里（「__ 统治着国家」「__ 戴着一顶王冠」）。所以它们的向量应该离得近。&lt;/p&gt;
&lt;p&gt;「国王」和「苹果」很少出现在同一个语境里。所以它们的向量应该离得远。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;训练时，模型会读海量的文本，对每个词做一个调整：如果两个词经常出现在相似的上下文里，就把它们的向量拉近一点；如果很少同时出现，就把它们推远一点。&lt;/p&gt;
&lt;p&gt;经过无数次这样的调整，模型最终学会了一个语义空间——意思相近的词，在空间里靠得近；意思不相关的词，离得远。&lt;/p&gt;
&lt;p&gt;这一步就是 Embedding 模型做的事。你给它输入一段文本，它返回一组向量。&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;%%{init: {'theme':'neutral'}}%%
graph LR
 A["输入文本&lt;br/&gt;去年第三季度赚了多少"] --&gt; B[Embedding 模型]
 B --&gt; C["输出向量&lt;br/&gt;[0.23, -0.56, 0.91, ...]"]

 style A fill:#dbeafe,stroke:#3b82f6,color:#1e3a5f
 style B fill:#d1fae5,stroke:#10b981,color:#064e3b
 style C fill:#fce7f3,stroke:#ec4899,color:#831843&lt;/pre&gt;&lt;h2 id="如何判断两个向量离得近"&gt;如何判断两个向量离得近
&lt;/h2&gt;&lt;p&gt;有了向量之后，怎么计算两段文字的相似度？&lt;/p&gt;
&lt;p&gt;最常用的方法叫&lt;strong&gt;余弦相似度&lt;/strong&gt;（Cosine Similarity）。你不需要记住公式，只要理解它的直觉：&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;两个向量在空间中有一个夹角。夹角越小，说明方向越一致，内容越相似。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;完全相同的文本 → 夹角 0°，相似度 = 1&lt;/li&gt;
&lt;li&gt;完全不相关的文本 → 夹角 90°，相似度 ≈ 0&lt;/li&gt;
&lt;li&gt;意思相反的文本 → 夹角 180°，相似度 = -1&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;%%{init: {'theme':'neutral'}}%%
graph LR
 A["文本A: 今天天气真好"] --&gt; C[Embedding 模型]
 B["文本B: 今天阳光明媚"] --&gt; C
 C --&gt; D["向量A: [0.8, 0.5, ...]&lt;br/&gt;向量B: [0.7, 0.6, ...]"]
 D --&gt; E["余弦相似度 = 0.92&lt;br/&gt;✅ 意思相近"]

 style A fill:#dbeafe,stroke:#3b82f6,color:#1e3a5f
 style B fill:#dbeafe,stroke:#3b82f6,color:#1e3a5f
 style C fill:#d1fae5,stroke:#10b981,color:#064e3b
 style D fill:#fce7f3,stroke:#ec4899,color:#831843
 style E fill:#d1fae5,stroke:#10b981,color:#064e3b&lt;/pre&gt;&lt;h2 id="回到-rag向量检索就是这样工作的"&gt;回到 RAG：向量检索就是这样工作的
&lt;/h2&gt;&lt;p&gt;RAG 的检索过程，就是把上面的逻辑倒过来：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;入库时&lt;/strong&gt;：把每篇文档的每个片段都通过 Embedding 模型转成向量，存进向量数据库&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;查询时&lt;/strong&gt;：把用户的问题也转成向量&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;匹配时&lt;/strong&gt;：计算问题向量和所有文档向量的余弦相似度，找出最接近的那几个片段&lt;/li&gt;
&lt;/ol&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;用户问题：去年第三季度我们赚了多少钱？
 │
 ▼ Embedding 模型
 │
[0.23, -0.56, 0.91, ...]
 │
 ▼ 跟库里所有文档向量算相似度
 │
文档中匹配到的内容：Q3营收同比增长15.3%（相似度 0.87）
 去年全年营收1.2亿元（相似度 0.45）
 公司成立于2018年（相似度 0.12）
 │
 ▼ 取 Top-K，拼入 Prompt
 │
LLM 基于这些内容生成回答
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;向量检索不只是「找到包含关键词的文档」，而是「找到意思最相近的内容」。这也解释了为什么在 RAG 中，&lt;strong&gt;分块和向量化的质量决定了检索的天花板&lt;/strong&gt;——如果文档切得不好、向量化得不准确，后面用多好的 LLM 也弥补不了。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;参考资料&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Mikolov et al., &lt;em&gt;Efficient Estimation of Word Representations in Vector Space&lt;/em&gt;, arXiv:1301.3781, 2013 — Word2Vec，向量化技术的奠基论文&lt;/li&gt;
&lt;li&gt;Reimers &amp;amp; Gurevych, &lt;em&gt;Sentence-BERT: Sentence Embeddings using Siamese BERT-Networks&lt;/em&gt;, EMNLP 2019 — 现代 Embedding 模型的基础架构&lt;/li&gt;
&lt;li&gt;Datawhale, &lt;em&gt;hello-agents&lt;/em&gt;, 第八章 记忆与检索, &lt;a class="link" href="https://github.com/datawhalechina/hello-agents" target="_blank" rel="noopener"
 &gt;https://github.com/datawhalechina/hello-agents&lt;/a&gt; — 从认知科学到向量检索的实践教程&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>从聊天到干活：LLM 是怎么一步步变成 Agent 的</title><link>https://renxinblog.cn/post/from-chat-to-agent/</link><pubDate>Wed, 08 Jul 2026 00:00:00 +0000</pubDate><guid>https://renxinblog.cn/post/from-chat-to-agent/</guid><description>&lt;p&gt;你有没有想过一个问题——&lt;/p&gt;
&lt;p&gt;几年前我们用 LLM，还只是拿来聊天查资料，把它当做一个更高效的搜索引擎。你问它一句，它答一句，答完就结束了。怎么现在它们突然就能干活了？调接口、读文件、写代码、自己决定下一步做什么——这些东西跟文本生成有什么关系？&lt;/p&gt;
&lt;p&gt;答案是：从「聊天」到「干活」，中间叠加了好几层工程手段。每一层解决一个问题，又会暴露一个更深层的问题。我们这篇文章就沿着这条问题链往下分析。&lt;/p&gt;
&lt;h2 id="第一层llm-本身什么也干不了"&gt;第一层：LLM 本身什么也干不了
&lt;/h2&gt;&lt;p&gt;我们都知道 LLM 的本质是一个&lt;strong&gt;一次性的文本预测器&lt;/strong&gt;：你给它输入一段文本，它就输出一段文本，然后结束。总体而言，它有四个根本限制：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;限制&lt;/th&gt;
					&lt;th&gt;什么意思&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;无状态&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;每次调用是独立的。不记得上一次聊了什么，除非把历史都塞回去&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;无行动能力&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;只能输出文字。不能调 API、不能读文件、不能执行命令&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;知识截止&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;训练完之后就停在那个时间点了，不知道最新消息&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;单步推理&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;复杂任务需要多步，它只能走一步&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;这些限制在简单问答场景下不明显——你问一句它答一句。但一旦任务变成「帮我排查一下这个 bug」，它需要：读文件 → 看报错 → 查文档 → 改代码 → 跑测试 → 看结果。这根本不是一次 LLM 调用能完成的。&lt;/p&gt;
&lt;p&gt;那么：&lt;strong&gt;怎么让 LLM 做一个完整的事？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;答案是：不给它加任何东西，它确实什么也干不了。但你可以围绕它叠加工程层——就像给一个只有大脑的躯体装上感官、手脚和神经系统。&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;%%{init: {'theme':'neutral'}}%%
graph TD
 subgraph Agent[Agent]
 direction TB
 subgraph 工程层[工程层]
 FC[Function Calling&lt;br/&gt;让模型能输出工具调用] --&gt; RA[ReAct 循环&lt;br/&gt;持续行动 + 反馈]
 RA --&gt; CM[上下文管理&lt;br/&gt;不让循环撑爆窗口]
 CM --&gt; MEM[记忆系统&lt;br/&gt;跨会话复用经验]
 MEM --&gt; HAR[Harness&lt;br/&gt;统一框架装好一切]
 end

 subgraph 核心[核心 · LLM]
 LLM[LLM&lt;br/&gt;文本预测器]
 end

 核心 --&gt;|叠加| 工程层
 end

 style Agent fill:#f8fafc,stroke:#64748b,color:#0f172a
 style 核心 fill:#dbeafe,stroke:#3b82f6,color:#1e3a5f
 style 工程层 fill:#d1fae5,stroke:#059669,color:#064e3b
 style LLM fill:#eff6ff,stroke:#60a5fa,color:#1e3a5f
 style FC fill:#ecfdf5,stroke:#34d399,color:#064e3b
 style RA fill:#ecfdf5,stroke:#34d399,color:#064e3b
 style CM fill:#ecfdf5,stroke:#34d399,color:#064e3b
 style MEM fill:#ecfdf5,stroke:#34d399,color:#064e3b
 style HAR fill:#ecfdf5,stroke:#34d399,color:#064e3b&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;蓝色&lt;/strong&gt;是 LLM 核心，&lt;strong&gt;绿色&lt;/strong&gt;是工程层，整个大框就是 &lt;strong&gt;Agent&lt;/strong&gt;。后面的章节就按这个顺序一层一层拆开来看。&lt;/p&gt;
&lt;h2 id="第二层function-calling让-llm说出要调什么工具"&gt;第二层：Function Calling——让 LLM「说」出要调什么工具
&lt;/h2&gt;&lt;p&gt;在 Function Calling 出现之前，想让 LLM 调用工具，做法很原始。&lt;/p&gt;
&lt;p&gt;你要在 prompt 里告诉 LLM：「你有哪些工具可以用、每个工具是干什么的、参数是什么」。然后 LLM 在回答的时候，把工具调用&lt;strong&gt;写在文本里&lt;/strong&gt;——比如输出一段 JSON，或者一段特定格式的文字。你在代码里写一堆正则表达式去匹配这段文字，解析出工具名和参数，再去执行。&lt;/p&gt;
&lt;p&gt;这个方法的问题很明显：LLM 输出文本是不受约束的。今天它输出 &lt;code&gt;{&amp;quot;tool&amp;quot;: &amp;quot;get_weather&amp;quot;, &amp;quot;args&amp;quot;: {&amp;quot;city&amp;quot;: &amp;quot;北京&amp;quot;}}&lt;/code&gt;，明天它可能输出 &lt;code&gt;让我来查一下北京的天气吧！[调用：get_weather(北京)]&lt;/code&gt;。格式稍微一变，你的正则就匹配不上了。而且每换一个模型，输出的格式习惯不一样，你的正则又得重写。&lt;/p&gt;
&lt;p&gt;2023 年中，OpenAI 推出了 Function Calling。这个改动看似不大，但影响深远。&lt;/p&gt;
&lt;p&gt;OpenAI 做的事其实就两件：第一，在模型微调阶段加入了大量「用户提问 → 模型输出 tool_calls」的训练样本，让模型学会在合适的时机输出结构化工具调用；第二，在 API 层面加了一个 &lt;code&gt;tools&lt;/code&gt; 参数，开发者直接把工具定义传进去，模型输出里就会自动带上 &lt;code&gt;tool_calls&lt;/code&gt; 字段。&lt;/p&gt;
&lt;p&gt;至于微调数据具体怎么构造、工具调用的能力边界在哪里——这是个可以单独写一篇文章的话题，这里先不展开。&lt;/p&gt;
&lt;p&gt;Function Calling 做的事很简单：&lt;strong&gt;模型在输出时，除了生成文本，还能输出一个结构化的对象&lt;/strong&gt;，里面明确指定了要调什么工具、传什么参数。&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;// 以前的写法：模型用文字描述
输出：&amp;#34;让我查一下天气。\n\n```json\n{\&amp;#34;tool\&amp;#34;: \&amp;#34;get_weather\&amp;#34;, \&amp;#34;args\&amp;#34;: {\&amp;#34;city\&amp;#34;: \&amp;#34;北京\&amp;#34;}}\n```&amp;#34;

// Function Calling：模型直接输出结构化调用
输出：{
 tool_calls: [{
 name: &amp;#34;get_weather&amp;#34;,
 args: { city: &amp;#34;北京&amp;#34; }
 }]
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;区别在哪？第一个是「模型用文字描述了自己想做什么」，第二个是模型&lt;strong&gt;结构化地输出函数名称和参数列表&lt;/strong&gt;——API 层收到后直接按这个字段去路由和执行，不需要任何文本解析。&lt;/p&gt;
&lt;p&gt;说到这里你可能会好奇：LLM 不是拿对话和文本训练出来的吗，它怎么会「知道」要输出结构化的 tool_calls？&lt;/p&gt;
&lt;p&gt;答案在微调阶段。OpenAI 在推出 Function Calling 之前，在微调数据里加入了大量「用户提问 → 模型输出 tool_calls」的训练样本。模型在预训练时就已经见过代码和 JSON，微调只是教它&lt;strong&gt;在什么时机输出&lt;/strong&gt;：&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;%%{init: {'theme':'neutral'}}%%
graph LR
 subgraph 训练流程[LLM 训练流程]
 direction LR
 A[预训练&lt;br/&gt;海量文本] --&gt; B[监督微调 SFT&lt;br/&gt;指令数据]
 B --&gt; C[偏好对齐 RLHF&lt;br/&gt;人类偏好]
 C --&gt; D[工具调用微调&lt;br/&gt;tool_calls 样本]
 end

 style 训练流程 fill:#f8fafc,stroke:#64748b,color:#0f172a
 style A fill:#eff6ff,stroke:#60a5fa,color:#1e3a5f
 style B fill:#dbeafe,stroke:#3b82f6,color:#1e3a5f
 style C fill:#d1fae5,stroke:#10b981,color:#064e3b
 style D fill:#ecfdf5,stroke:#34d399,color:#064e3b&lt;/pre&gt;&lt;p&gt;最后一个阶段是关键。更直白一点：&lt;strong&gt;模型不是「学会调工具」，而是学会了「在需要调工具的场景下，输出一段看起来像 tool_calls 的 token 序列」。&lt;/strong&gt; 它以为自己只是在接着写文本，但对使用者来说，它在干活。&lt;/p&gt;
&lt;p&gt;清楚了 Function Calling 的原理之后，一个新的问题自然浮现了：&lt;strong&gt;光能说一次还不够——一个完整的任务往往需要多步操作：查了数据、分析、再查、再分析。能不能让模型不止调一次，而是一直干下去直到任务完成？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这就引出了下一层：&lt;strong&gt;ReAct 循环。&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="第三层react-循环从一次调用到持续行动"&gt;第三层：ReAct 循环——从一次调用到持续行动
&lt;/h2&gt;&lt;p&gt;一次 Function Calling 只能完成一步。要完成一个复杂任务，需要多步。这时候就需要一个循环。&lt;/p&gt;
&lt;p&gt;ReAct（Reasoning + Acting）是 2022 年一篇论文提出的思路，核心骨架就是一个持续循环：&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;%%{init: {'theme':'neutral'}}%%
graph LR
 A[观察当前状态&lt;br/&gt;Observation] --&gt; B[推理下一步&lt;br/&gt;Thought]
 B --&gt; C{任务完成？}
 C --&gt;|否| D[执行工具调用&lt;br/&gt;Action]
 D --&gt; A
 C --&gt;|是| E[输出最终答案]

 style A fill:#eff6ff,stroke:#60a5fa,color:#1e3a5f
 style B fill:#dbeafe,stroke:#3b82f6,color:#1e3a5f
 style C fill:#fef9c3,stroke:#fbbf24,color:#92400e
 style D fill:#d1fae5,stroke:#10b981,color:#064e3b
 style E fill:#ecfdf5,stroke:#34d399,color:#064e3b&lt;/pre&gt;&lt;p&gt;每一轮循环做三件事：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Thought&lt;/strong&gt;：LLM 推理当前步骤。比如「发现了这个 bug，需要先看一下这个文件的源代码」&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Action&lt;/strong&gt;：LLM 输出一个工具调用。比如 &lt;code&gt;read_file(&amp;quot;src/main.py&amp;quot;)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Observation&lt;/strong&gt;：工具执行结果塞回下一轮 prompt，LLM 看到了继续推理&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;用代码实现也就几十行：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;done&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;build_prompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;observation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;llm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parse_action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;final_answer&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;done&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;observation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;execute_tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;observation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个循环就是所有现代 Agent 的基座。Claude Code、Codex、Manus、Cline——不管上面叠了多少层，最底层跑的都是这个循环。&lt;/p&gt;
&lt;p&gt;ReAct 循环很好用，任务越复杂跑的轮数就越多。但跑起来之后，人们很快发现一个问题：每轮都要把全部历史塞回 prompt，跑了 8 轮之后光历史记录可能就已经占了 30K token。而且很多早期的对话其实已经没用了——第一轮的推理早就被后续结果覆盖了。&lt;/p&gt;
&lt;p&gt;Token 越积越多，效率越来越低——能不能在保留必要上下文的同时，不让循环撑爆窗口？&lt;/p&gt;
&lt;p&gt;解决方法有几个方向：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;策略&lt;/th&gt;
					&lt;th&gt;做法&lt;/th&gt;
					&lt;th&gt;适用场景&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;滑动窗口&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;只保留最近 N 轮对话，丢弃最旧的&lt;/td&gt;
					&lt;td&gt;简单任务，早期对话不重要&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;摘要压缩&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;把旧对话用 LLM 压缩成一段摘要&lt;/td&gt;
					&lt;td&gt;需要长期记忆的任务&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;结构化上下文&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;把历史信息按类型组织，LLM 按需读取&lt;/td&gt;
					&lt;td&gt;复杂任务&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;渐进性披露&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;不一次给全部信息，先给概要再展开&lt;/td&gt;
					&lt;td&gt;长文档分析&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Mitchell Hashimoto（Harness Engineering 提出者）说过一句话：&lt;strong&gt;长上下文不是银弹。关键是上下文的质量和组织方式，不是长度。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;对话管理解决了「一次任务内」的持久化问题。但关掉会话之后呢？下次遇到同样的问题，能不能复用上次的排查经验？&lt;/p&gt;
&lt;p&gt;这就引出了下一层：&lt;strong&gt;记忆系统。&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="第五层记忆让经验跨会话复用"&gt;第五层：记忆——让经验跨会话复用
&lt;/h2&gt;&lt;p&gt;想象一个场景：上周花了半天排查了一个连接池超时问题，找到了根因。这周又遇到一个类似的报错，但你又得从头排查一遍——因为上次的排查结果在上次对话里，已经关了，没了。&lt;/p&gt;
&lt;p&gt;这就是记忆要解决的问题。&lt;/p&gt;
&lt;p&gt;记忆可以分为几个层次：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;层次&lt;/th&gt;
					&lt;th&gt;存储方式&lt;/th&gt;
					&lt;th&gt;生命周期&lt;/th&gt;
					&lt;th&gt;示例&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;上下文窗口&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;prompt 里的消息列表&lt;/td&gt;
					&lt;td&gt;当前会话&lt;/td&gt;
					&lt;td&gt;刚才的对话历史&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;文件存储&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Markdown / JSON 文件&lt;/td&gt;
					&lt;td&gt;持久化&lt;/td&gt;
					&lt;td&gt;MEMORY.md、USER.md&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;向量数据库&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Embedding 检索&lt;/td&gt;
					&lt;td&gt;持久化&lt;/td&gt;
					&lt;td&gt;RAG 知识库&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;结构化数据库&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;PostgreSQL 等&lt;/td&gt;
					&lt;td&gt;持久化&lt;/td&gt;
					&lt;td&gt;业务实体、修复记录&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;关键点：&lt;strong&gt;分层不是替代关系，是互补关系。&lt;/strong&gt; 文件层存结构化知识，向量层存语义可检索的内容，上下文层存当前会话的状态。实际工程中，通常会为每个 Agent 分配独立的数据库 schema，同时把技能和记忆以文件形式备份到代码仓库——既能在会话中快速检索，又能在仓库里版本回溯。&lt;/p&gt;
&lt;p&gt;有了循环、上下文管理、记忆，LLM 终于能完整地完成一个任务了。但这些东西是一块一块拼上去的——Function Calling、ReAct、上下文管理、记忆，各是一套独立的组件。到了这一步，人们开始想：能不能把这些零散的组件装进一个统一的框架里？&lt;/p&gt;
&lt;h2 id="第六层harness给-llm-装一个操作系统"&gt;第六层：Harness——给 LLM 装一个操作系统
&lt;/h2&gt;&lt;p&gt;Harness Engineering 的核心思想是：&lt;strong&gt;围绕 LLM 构建一个「操作系统」——包括工具系统、上下文管理、权限控制、反馈回路、可观测性。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;没有 Harness 的话，做 Agent 就是 LLM + 循环 + 几个工具，拼起来就完事了。Harness 的视角不一样——它认为 Agent 能不能用好，瓶颈往往不在模型本身，而在于&lt;strong&gt;怎么装&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;LangChain 的 Deep Agents 项目有一个实验很能说明问题：仅仅优化 Harness（不改模型），Terminal Bench 2.0 排名从第 30 位直接跃升至第 5 位。&lt;/p&gt;
&lt;p&gt;Harness 有四条铁律：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;工具签名即文档&lt;/strong&gt;——每个工具的名称、参数、返回值本身就是使用说明&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;结果必须可验证&lt;/strong&gt;——每一步的输出需要有明确的验证标准&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;错误不可沉默&lt;/strong&gt;——所有失败必须可见并结构化回传（Error-as-Data）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;渐进性披露&lt;/strong&gt;——不要让 Agent 同时面对所有信息，按需呈现&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;除此之外，权限控制、反馈回路、可观测性也都是 Harness 的重要组成部分——这些是值得单独展开的话题，这里先不深入。&lt;/p&gt;
&lt;p&gt;总结一下就是：&lt;strong&gt;Agent = LLM + Harness&lt;/strong&gt;。LLM 负责推理，Harness 负责把它装好，让它能干活。&lt;/p&gt;
&lt;h2 id="回头看整条演化路径"&gt;回头看整条演化路径
&lt;/h2&gt;&lt;p&gt;把这几层串起来，就是一条清晰的演化路径：&lt;/p&gt;
&lt;a href="https://renxinblog.cn/images/llm-to-agent-evolution.svg" target="_blank"&gt;
 &lt;figure&gt;&lt;img src="https://renxinblog.cn/images/llm-to-agent-evolution.svg"
 			alt="LLM到Agent的六层演化路径" width="85%"&gt;&lt;figcaption&gt;
 			&lt;p&gt;LLM → Agent 演化路径：六层叠加，每层解决上一层的新问题（点击图片查看大图）&lt;/p&gt;
 		&lt;/figcaption&gt;
 &lt;/figure&gt;

&lt;/a&gt;
&lt;p&gt;每一层都在解决上一层暴露出来的新问题。LLM 本身没有变「更聪明」，但加上这些工程组件之后，它从一个只会聊天的文本预测器，变成了一个能干活、能调接口、能写代码、能自己决定下一步的 Agent。&lt;/p&gt;
&lt;p&gt;从 Function Calling 到 ReAct 到 Harness，每一层都不复杂。就像搭积木——每一块都很简单，但搭对了顺序，就能搭出一个能干活的东西来。&lt;/p&gt;</description></item><item><title>AI Agent 入门：程序员视角的概念与实践</title><link>https://renxinblog.cn/post/ai-agent-introduction/</link><pubDate>Sun, 05 Jul 2026 00:00:00 +0000</pubDate><guid>https://renxinblog.cn/post/ai-agent-introduction/</guid><description>&lt;p&gt;如果说 2024 年是&amp;quot;AI 聊天机器人&amp;quot;普及的一年，那么 2025-2026 年则是&amp;quot;AI Agent&amp;quot;从概念走向工程的一年。Claude Code、OpenAI Codex、Manus、Cline……越来越多的产品不再满足于&amp;quot;你问我答&amp;quot;，而是主动帮你完成任务——读代码、改文件、跑测试、甚至自己写一篇博客。&lt;/p&gt;
&lt;p&gt;但 Agent 到底是什么？它和普通的 LLM 对话有什么区别？这篇文章将从程序员熟悉的概念出发，系统地梳理 AI Agent 的核心概念、关键特性和基础架构模式。&lt;/p&gt;
&lt;h2 id="一从对话到自主agent-的核心定义"&gt;一、从对话到自主：Agent 的核心定义
&lt;/h2&gt;&lt;p&gt;最简单的定义来自 LangChain：&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;Agent = Model + Harness&lt;/strong&gt;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;翻译成程序员能理解的语言：&lt;strong&gt;Agent 不是更聪明的 LLM，而是把 LLM 装进了一个有工具、有记忆、有控制循环的&amp;quot;运行时环境&amp;quot;里。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;你可以把 LLM 想象成一个天才程序员，但你只能跟他口头交流——他再聪明，不动手也写不了代码。Agent 就是给了这个天才一台电脑、一套工具链、和一份&amp;quot;你自己想办法搞定&amp;quot;的指令。&lt;/p&gt;
&lt;p&gt;Anthropic 的 Barry Zhang 有一个更简洁的说法：&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;Agent = 在 Loop 中使用工具的模型&lt;/strong&gt;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;关键的区别在于：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;特性&lt;/th&gt;
					&lt;th style="text-align: center"&gt;普通 LLM 对话&lt;/th&gt;
					&lt;th style="text-align: center"&gt;Agent&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;交互方式&lt;/td&gt;
					&lt;td style="text-align: center"&gt;一问一答&lt;/td&gt;
					&lt;td style="text-align: center"&gt;给定目标，自主行动&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;工具使用&lt;/td&gt;
					&lt;td style="text-align: center"&gt;不能&lt;/td&gt;
					&lt;td style="text-align: center"&gt;可以调 API、读写文件、执行命令&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;记忆&lt;/td&gt;
					&lt;td style="text-align: center"&gt;上下文窗口（易失）&lt;/td&gt;
					&lt;td style="text-align: center"&gt;持久化记忆（跨会话）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;决策&lt;/td&gt;
					&lt;td style="text-align: center"&gt;用户决定下一步&lt;/td&gt;
					&lt;td style="text-align: center"&gt;自主决定下一步&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;错误处理&lt;/td&gt;
					&lt;td style="text-align: center"&gt;用户发现并纠正&lt;/td&gt;
					&lt;td style="text-align: center"&gt;自行检测和重试&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="二agent-的五个关键特性"&gt;二、Agent 的五个关键特性
&lt;/h2&gt;&lt;p&gt;从工程角度看，一个完整的 Agent 系统通常具备以下五个特性：&lt;/p&gt;
&lt;h3 id="1-工具调用tool-use"&gt;1. 工具调用（Tool-use）
&lt;/h3&gt;&lt;p&gt;Agent 不只&amp;quot;说&amp;quot;，还能&amp;quot;做&amp;quot;。通过工具调用操作外部系统——读文件、搜网页、发 API、执行命令。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;💡 &lt;strong&gt;类比&lt;/strong&gt;：工具的接口就像微服务的 API endpoint，有 schema、参数、返回值。Agent 根据任务自主选择调哪个&amp;quot;端点&amp;quot;。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h3 id="2-记忆memory"&gt;2. 记忆（Memory）
&lt;/h3&gt;&lt;p&gt;Agent 需要跨会话记住你的偏好、工作环境、学到的经验。记忆分为多个层级：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;文件层&lt;/strong&gt;：&lt;code&gt;MEMORY.md&lt;/code&gt;、&lt;code&gt;USER.md&lt;/code&gt; 等结构化文件，持久化存储&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;语义层&lt;/strong&gt;：向量检索，用于快速召回相关历史&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;上下文层&lt;/strong&gt;：当前会话窗口，易失但高效&lt;/li&gt;
&lt;/ul&gt;

 &lt;blockquote&gt;
 &lt;p&gt;💡 &lt;strong&gt;类比&lt;/strong&gt;：上下文窗口是 Redis（缓存，易失），文件系统是 PostgreSQL（持久存储）。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h3 id="3-规划planning"&gt;3. 规划（Planning）
&lt;/h3&gt;&lt;p&gt;复杂任务需要拆解。Agent 先制定计划（如 &lt;code&gt;plan.md&lt;/code&gt;），再分步执行——每一步完成后再决定下一步做什么。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;💡 &lt;strong&gt;类比&lt;/strong&gt;：就像你写代码之前先画架构图、列 TODO 清单。Agent 也需要先规划再行动。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h3 id="4-自主决策autonomous-decision"&gt;4. 自主决策（Autonomous Decision）
&lt;/h3&gt;&lt;p&gt;这是 Agent 和&amp;quot;带工具的聊天机器人&amp;quot;的本质区别。Agent 自主决定调哪个工具、用什么参数、是否重试。&lt;/p&gt;
&lt;p&gt;关键设计原则：&lt;strong&gt;Error-as-Data&lt;/strong&gt;。工具失败时，错误信息作为数据回写给 LLM，而不是抛异常——Agent 自己决定是重试还是换工具。&lt;/p&gt;
&lt;h3 id="5-验证与反馈verification"&gt;5. 验证与反馈（Verification）
&lt;/h3&gt;&lt;p&gt;Agent 需要自己检查结果是否正确。没有验证的 Agent 就像没有测试用例的 CI/CD 流水线——跑得再快也不知道对不对。&lt;/p&gt;
&lt;p&gt;Boris Cherny（Claude Code 负责人）的一条核心经验：&lt;strong&gt;给 LLM 自我验证的能力，输出质量能提升 2-3 倍。&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="三四层工程模型理解-agent-系统的骨架"&gt;三、四层工程模型：理解 Agent 系统的骨架
&lt;/h2&gt;&lt;p&gt;这是理解 Agent 技术栈最清晰的可视化框架，由浅入深分为四层：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;L4 Loop Engineering —— 设计替你跑 Agent 的系统
L3 Harness Engineering —— 怎么把 Agent 装好
L2 Context Engineering —— 怎么给 Agent 喂对信息
L1 Prompt Engineering —— 怎么把话说清楚
&lt;/code&gt;&lt;/pre&gt;
 &lt;blockquote&gt;
 &lt;p&gt;⚠️ 注意：四层是&lt;strong&gt;嵌套关系&lt;/strong&gt;而非替代关系。L3 不覆盖 L2，而是在它上面叠加。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h3 id="l1-prompt-engineering"&gt;L1: Prompt Engineering
&lt;/h3&gt;&lt;p&gt;最基本的层次。研究&amp;quot;怎么写指令&amp;quot;能让 LLM 给出更好的回答。包括角色设定、示例引导、思维链（Chain-of-Thought）等技巧。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;程序员熟悉的起点&lt;/strong&gt;：就像写一个好的函数注释和调用说明。不同之处在于 Prompt 的&amp;quot;读者&amp;quot;是 LLM，它比编译器宽容得多，但也会产生你意想不到的输出。&lt;/p&gt;
&lt;h3 id="l2-context-engineering"&gt;L2: Context Engineering
&lt;/h3&gt;&lt;p&gt;这一层关注&amp;quot;给 LLM 什么信息&amp;quot;。Andrej Karpathy 提出的概念——长上下文不是银弹，关键是上下文的质量和结构。&lt;/p&gt;
&lt;p&gt;核心实践包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;渐进性披露&lt;/strong&gt;：先给概要，逐步展开细节，避免信息过载&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;上下文窗口管理&lt;/strong&gt;：当上下文超长时，如何压缩、优先排序、丢弃&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;结构化上下文&lt;/strong&gt;：用 XML、JSON 等格式组织信息，让 LLM 更容易解析&lt;/li&gt;
&lt;/ul&gt;

 &lt;blockquote&gt;
 &lt;p&gt;💡 &lt;strong&gt;类比&lt;/strong&gt;：Prompt Engineering 是&amp;quot;怎么问&amp;quot;，Context Engineering 是&amp;quot;给什么参考材料&amp;quot;。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h3 id="l3-harness-engineering"&gt;L3: Harness Engineering
&lt;/h3&gt;&lt;p&gt;这是 Agent 工程的核心创新层。Mitchell Hashimoto（Harness Engineering 提出者）将其定义为：&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;围绕 LLM 构建一个&amp;quot;操作系统&amp;quot;——包括工具系统、权限控制、上下文管理、反馈回路、可观测性。&lt;/strong&gt;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;Harness 的四条铁律：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;工具签名即文档&lt;/strong&gt; — 每个工具的名称、参数、返回值的设计本身就是使用说明&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;结果必须可验证&lt;/strong&gt; — 每一步的输出需要有明确的验证标准&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;错误不可沉默&lt;/strong&gt; — 所有失败必须可见并结构化回传（Error-as-Data）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;渐进性披露&lt;/strong&gt; — 不要让 Agent 同时面对所有信息，按需呈现&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;LangChain 的 Deep Agents 项目做过一个令人印象深刻的实验：&lt;strong&gt;仅仅优化 Harness（不改模型），Terminal Bench 2.0 排名从第 30 位直接跃升至第 5 位。&lt;/strong&gt; 这证明了瓶颈往往不在模型本身，而在&amp;quot;怎么装&amp;quot;。&lt;/p&gt;
&lt;h3 id="l4-loop-engineering"&gt;L4: Loop Engineering
&lt;/h3&gt;&lt;p&gt;最高层次，研究&amp;quot;自动触发 Agent 的循环系统&amp;quot;。不是你自己跑一次 Agent，而是系统定期或按事件自动启动 Agent。&lt;/p&gt;
&lt;p&gt;Boris Cherny 的实践是代表性案例——他不再&amp;quot;提示&amp;quot;Claude，而是&amp;quot;写循环&amp;quot;（I don&amp;rsquo;t prompt Claude anymore. I write loops.）。&lt;/p&gt;
&lt;p&gt;典型的 Loop 模式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;事件驱动&lt;/strong&gt;：文件变更 → 自动触发代码审查&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;定时任务&lt;/strong&gt;：每日自动抓取信息、生成摘要&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pipeline&lt;/strong&gt;：多个 Agent 接力完成复杂工作流&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="四基础架构模式"&gt;四、基础架构模式
&lt;/h2&gt;&lt;h3 id="41-react-loop核心循环"&gt;4.1 ReAct Loop（核心循环）
&lt;/h3&gt;&lt;p&gt;ReAct（Reasoning + Acting）是所有现代 Agent 的基座模式。它的执行循环可以用一行伪代码概括：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;while (task_not_complete) {
 think() // 推理：当前状态 + 下一步做什么
 act() // 行动：调用工具或生成输出
 observe() // 观察：收集执行结果
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Manus、Cline、Claude Code 都是 ReAct Loop 的具体实现。不管上层叠了多少层 Harness 或 Loop，最底层永远是 observe-think-act 这个基本循环。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;💡 &lt;strong&gt;类比&lt;/strong&gt;：一个 &lt;code&gt;while(true) { think → act → observe }&lt;/code&gt; 的事件循环。Agent 每次迭代都自主决定是调用工具还是给出最终答案。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h3 id="42-plan-and-execute"&gt;4.2 Plan-and-Execute
&lt;/h3&gt;&lt;p&gt;Agent 先制定完整计划，再分步执行。典型流程：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Init 阶段&lt;/strong&gt;：分析任务，生成 &lt;code&gt;plan.md&lt;/code&gt;，分解为子步骤&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Exec 阶段&lt;/strong&gt;：按计划逐步执行，每步完成后更新进度&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Check 阶段&lt;/strong&gt;：验证结果是否符合预期，必要时回退或修正&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这种模式的优点是任务可追溯、可断点续传。缺点是灵活性不如纯 ReAct——当实际情况偏离计划时，需要 Agent 具备&amp;quot;重新规划&amp;quot;的能力。&lt;/p&gt;
&lt;h3 id="43-tool-use-模式"&gt;4.3 Tool-use 模式
&lt;/h3&gt;&lt;p&gt;专门优化工具调用的架构，关键要点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;工具名用动词短语&lt;/strong&gt;：&lt;code&gt;parse_resume&lt;/code&gt;、&lt;code&gt;score_match&lt;/code&gt;，而不是 &lt;code&gt;resume_tool&lt;/code&gt;、&lt;code&gt;match&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;参数含正反面说明&lt;/strong&gt;：告诉 LLM 什么情况下用什么参数&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;返回值结构稳定&lt;/strong&gt;：格式可预测，方便 LLM 解析&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;工具隔离&lt;/strong&gt;：每个 Sub-Agent 只装它真正需要的工具&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="44-mcp-协议"&gt;4.4 MCP 协议
&lt;/h3&gt;&lt;p&gt;MCP（Model Context Protocol）是 Anthropic 提出的工具层标准协议。可以理解为 &lt;strong&gt;Agent 世界的 USB 协议&lt;/strong&gt;——任何工具只要实现 MCP，就能即插即用。&lt;/p&gt;
&lt;p&gt;&amp;ldquo;OneAgent + MCPs&amp;rdquo; 范式正在成为趋势：用一个统一的基础 Agent，通过不同领域的 MCP 服务器扩展能力，代替传统的&amp;quot;每个场景一个独立 Agent&amp;quot;的模式。&lt;/p&gt;
&lt;h2 id="五关键术语速查表"&gt;五、关键术语速查表
&lt;/h2&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;术语&lt;/th&gt;
					&lt;th&gt;一句话解释&lt;/th&gt;
					&lt;th&gt;程序员类比&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Agent&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;能自主决定下一步做什么的 LLM&lt;/td&gt;
					&lt;td&gt;一个有 main loop 的微服务，每次迭代自己选路由&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;LLM&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Agent 的&amp;quot;大脑&amp;quot;，负责推理和决策&lt;/td&gt;
					&lt;td&gt;一个超级强大的 if-else 引擎，输入是自然语言&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Tool&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Agent 操作外部世界的接口&lt;/td&gt;
					&lt;td&gt;微服务的 API endpoint，有 schema、参数、返回值&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Memory&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;跨会话持久化知识&lt;/td&gt;
					&lt;td&gt;数据库（持久层）+ 缓存（上下文窗口）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;ReAct Loop&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;基础执行循环&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;while(true) { think → act → observe }&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Harness&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;把 Agent 装起来的&amp;quot;操作系统&amp;quot;&lt;/td&gt;
					&lt;td&gt;相比&amp;quot;怎么写&amp;quot;（Prompt），优化&amp;quot;怎么装&amp;quot;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Loop&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;自动触发 Agent 的循环系统&lt;/td&gt;
					&lt;td&gt;cron + event-driven 架构&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Workspace&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Agent 的&amp;quot;当前工作目录&amp;quot;&lt;/td&gt;
					&lt;td&gt;不是变量，是 git 仓库——每一步可回放、可审计&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Verifier&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;检查 Agent 输出是否正确&lt;/td&gt;
					&lt;td&gt;断言之于测试&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Skill&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;可复用的知识包&lt;/td&gt;
					&lt;td&gt;插件系统 + 懒加载库&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;MCP&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;工具层的标准协议&lt;/td&gt;
					&lt;td&gt;Agent 世界的 USB 协议&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="六从哪里开始"&gt;六、从哪里开始？
&lt;/h2&gt;&lt;p&gt;如果你是一个有编程基础的程序员，想开始实践 Agent 工程，以下资源值得关注：&lt;/p&gt;
&lt;h3 id="一手信息源英文需网络环境"&gt;一手信息源（英文，需网络环境）
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;来源&lt;/th&gt;
					&lt;th&gt;推荐理由&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a class="link" href="https://lilianweng.github.io/posts/2023-06-23-agent/" target="_blank" rel="noopener"
 &gt;Lilian Weng, &amp;ldquo;LLM Powered Autonomous Agents&amp;rdquo;&lt;/a&gt;&lt;/td&gt;
					&lt;td&gt;Agent 入门圣经，系统讲工具调用、记忆、规划三大支柱&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a class="link" href="https://docs.anthropic.com/en/docs/build-with-claude/agentic" target="_blank" rel="noopener"
 &gt;Anthropic, &amp;ldquo;Build Effective Agents&amp;rdquo;&lt;/a&gt;&lt;/td&gt;
					&lt;td&gt;官方最佳实践，简洁实用&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a class="link" href="https://mitchellh.com/" target="_blank" rel="noopener"
 &gt;Mitchell Hashimoto 博客&lt;/a&gt;&lt;/td&gt;
					&lt;td&gt;Harness Engineering 原创者&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a class="link" href="https://howborisusesclaudecode.com/" target="_blank" rel="noopener"
 &gt;Boris Cherny, howborisusesclaudecode.com&lt;/a&gt;&lt;/td&gt;
					&lt;td&gt;Claude Code 之父，loop 实战&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;a class="link" href="https://addyosmani.com/blog/" target="_blank" rel="noopener"
 &gt;Addy Osmani Substack&lt;/a&gt;&lt;/td&gt;
					&lt;td&gt;Loop Engineering 提出者&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="国内可访问的中文资料"&gt;国内可访问的中文资料
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;文章&lt;/th&gt;
					&lt;th&gt;来源&lt;/th&gt;
					&lt;th&gt;推荐角度&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Agent Harness 工程实践&lt;/td&gt;
					&lt;td&gt;阿里云开发者&lt;/td&gt;
					&lt;td&gt;Harness 定义 + 四条铁律&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Harness 工程之道：Skill 原理与最佳实践&lt;/td&gt;
					&lt;td&gt;阿里云开发者&lt;/td&gt;
					&lt;td&gt;渐进性披露、Skill 目录结构&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Loop Engineering 四层模型&lt;/td&gt;
					&lt;td&gt;腾讯云开发者&lt;/td&gt;
					&lt;td&gt;四层嵌套框架（本文骨架来源）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;OneAgent + MCPs 范式&lt;/td&gt;
					&lt;td&gt;阿里云开发者&lt;/td&gt;
					&lt;td&gt;Agent 发展四阶段模型&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Boris Cherny 的 /loop 实战&lt;/td&gt;
					&lt;td&gt;歪脖抠腚&lt;/td&gt;
					&lt;td&gt;验证先行、CLAUDE.md 知识积累&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="七结语"&gt;七、结语
&lt;/h2&gt;&lt;p&gt;回到最核心的那句话：&lt;strong&gt;Agent = Model + Harness&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;模型本身的能力固然重要，但工程落地的瓶颈往往不在模型够不够聪明，而在&lt;strong&gt;有没有把它装好&lt;/strong&gt;。Prompt Engineering 只是起点，往上还有 Context Engineering（喂对信息）、Harness Engineering（装好系统）、Loop Engineering（自动化循环）——每一层都是值得深入的方向。&lt;/p&gt;
&lt;p&gt;从今天开始，不妨试着用 Agent 的思维来思考问题：不是&amp;quot;让 AI 帮我回答这个问题&amp;quot;，而是&amp;quot;给 AI 一个目标、一套工具、一个自主决策的环境，让它自己去搞定&amp;quot;。&lt;/p&gt;
&lt;p&gt;这才是 Agent 时代真正的编程范式转变。&lt;/p&gt;</description></item><item><title>JDK21新特性</title><link>https://renxinblog.cn/post/java/jdk21-new-features/</link><pubDate>Mon, 21 Apr 2025 00:00:00 +0000</pubDate><guid>https://renxinblog.cn/post/java/jdk21-new-features/</guid><description>&lt;p&gt;笔者在过去主要使用的JDK版本是JDK8，最近在学习最新的JDK长期支持版本——JDK21，本文将简要记录一下JDK21相比于JDK8的一些新特性，对于一些比较有意思的新特性也会在后续文章中逐步展开研究。&lt;/p&gt;
&lt;h3 id="var-关键字局部变量推断"&gt;var 关键字局部变量推断
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 仅限局部变量&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;zhangsan&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;18&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;isMan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="switch-表达式增强"&gt;switch 表达式增强
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 假设有枚举定义为&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;enum&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Direction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EAST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SOUTH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;WEST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NORTH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NORTHWEST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// switch 表达式为变量赋值&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;witchCity&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;direction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EAST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NORTHWEST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;成都&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;WEST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;上海&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SOUTH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;广州&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NORTH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;北京&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;throw&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Invalid direction: &amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;direction&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// yield 关键字返回值，并跳出switch表达式（相当于break）&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;witchCity&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;direction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EAST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NORTHWEST&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;成都&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;yield&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;成都&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;WEST&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;上海&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;yield&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;上海&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SOUTH&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;广州&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;yield&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;广州&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NORTH&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;北京&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;yield&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;北京&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;未知&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;yield&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;未知&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// yield 关键字结合lambda表达式&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;witchCity&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;direction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EAST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NORTHWEST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;成都&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;yield&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;成都&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;WEST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;上海&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;yield&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;上海&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SOUTH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;广州&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;yield&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;广州&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NORTH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;北京&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;yield&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;北京&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;未知&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;yield&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;未知&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="记录类record-class"&gt;记录类（record class）
&lt;/h3&gt;&lt;p&gt;记录类的使用场景是存储数据，尤其是那些纯粹做数据传输的对象如DTO等，其每个字段都是不可变的。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 定义一个记录类,标注了record关键字，同时指定了name和age两个字段，编译器已经自动为其生成了构造函数、字段访问方法name()和age()。&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 除字段不能被修改、不能继承其他类、不能添加实例字段之外其他的特性与普通类相同。&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;record&lt;/span&gt; &lt;span class="nc"&gt;Student&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 不能添加实例字段&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// private String teacher;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 构造器可以自定义&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Student&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;throw&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;年龄不能小于0&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;throw&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;姓名不能为空&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 可以定义方法&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 可以实现接口&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="密封类sealed-classes"&gt;密封类（Sealed Classes）
&lt;/h3&gt;&lt;p&gt;密封类的使用场景是定义一个类的继承规则，只有指定的类可以继承该类，其他类不能继承该类。类之间耦合更紧了，但是也提升了类型安全。在编写三方库提供给别人用又不希望被使用者随意继承使用时这个特性会特别有用。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// sealed关键字定义一个密封类，同时permits关键字指定了可以继承该类的类&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;sealed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Job&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;permits&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Author&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Teacher&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;renxin&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 定义一个final类为密封类的子类，该类不能被继承&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Author&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;extends&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Job&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;renxin&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 定义一个non-sealed修饰的类为密封类的子类，该类放弃密封性可以被普通类继承&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;non&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="kd"&gt;sealed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Author&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;extends&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Job&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;子类必须与密封类处于同一个模块（或同一个包，如果没有模块系统）&lt;/p&gt;
&lt;p&gt;子类必须显式继承密封类，否则编译不通过&lt;/p&gt;
&lt;p&gt;密封类的子类必须被显式声明为final、sealed或non-sealed。这是密封类设计的核心原则。这样做有两方面的好处。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;明确类的继承结构，防止继承链失控&lt;/li&gt;
&lt;li&gt;与模式匹配结合可以在编译期做到穷举检查&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// Author类、Teacher被明确定义为final类，编译期可以知道该类被哪些子类继承，做到穷举检查&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;abstract&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;sealed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Job&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;permits&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Author&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Teacher&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Author&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;extends&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Job&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Teacher&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;extends&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Job&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Job&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Author&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Author&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Teacher&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Teacher&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 编译通过，若缺失case Teacher分支，编译错误&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="虚拟线程virtual-threads"&gt;虚拟线程（Virtual Threads）
&lt;/h3&gt;&lt;p&gt;虚拟线程是一种用户态的轻量级线程，类似于其他语言的协程，它的显著提高了Java程序的并发支持能力。细节请参考笔者另一篇文章：&lt;a class="link" href="https://www.renxinblog.cn/docs/101_java/concurrent_programming/introduction/" target="_blank" rel="noopener"
 &gt;理解虚拟线程&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="新的http客户端api"&gt;新的HTTP客户端API
&lt;/h3&gt;&lt;p&gt;支持同步调用和异步调用，异步调用使用CompletableFuture来返回结果。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 同步调用&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;HttpClient&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HttpClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newHttpClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;HttpRequest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HttpRequest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newBuilder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;URI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;https://httpbin.org/get&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;HttpResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;BodyHandlers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 异步调用&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stringBodyCompletableFuture&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sendAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;BodyHandlers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofString&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenApply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="instance-of-模式匹配"&gt;instance of 模式匹配
&lt;/h3&gt;&lt;p&gt;instance of 语法增强，可以省去类型转换步骤。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// jdk8写法&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;read.renxinblog.cn&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;instanceof&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// jdk21写法&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;read.renxinblog.cn&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;instanceof&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="新一代gczgc"&gt;新一代GC：ZGC
&lt;/h3&gt;&lt;p&gt;相较于上一代的G1，ZGC的性能更加优秀，同时也更加稳定。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;几乎所有GC阶段都并发进行，STW时间极短，这意味着GC暂停对应用程序造成的性能波动非常小。&lt;/li&gt;
&lt;li&gt;能够支持更大的堆，最多达16TB，并且随着堆的增大，GC性能几乎没有降低，这对于数据密集型的大堆系统非常有用。&lt;/li&gt;
&lt;li&gt;ZGC能够保证GC停顿时间可控，更容易实现系统的SLO要求。&lt;/li&gt;
&lt;li&gt;更高的并发能力同时也意味着更高的CPU消耗。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;总之，ZGC以复杂的技术实现换来了极低的延迟时间和大堆性能表现，是G1控制延迟的进化版。性能的提升也带来更高的CPU消耗，但这不是一个缺点，而是一个非常的选择。&lt;/p&gt;
&lt;h3 id="其他"&gt;其他
&lt;/h3&gt;&lt;p&gt;其他特性还包括Stream API的增强、集合工厂方法、文本块（字符串增强）、日期API增强等，这里不多做介绍。&lt;/p&gt;</description></item><item><title>理解虚拟线程</title><link>https://renxinblog.cn/post/java/understanding-virtual-threads/</link><pubDate>Thu, 10 Apr 2025 00:00:00 +0000</pubDate><guid>https://renxinblog.cn/post/java/understanding-virtual-threads/</guid><description>&lt;h1 id="理解虚拟线程"&gt;理解虚拟线程
&lt;/h1&gt;&lt;p&gt;JDK21中正式引入了虚拟线程，这是Java标准库首次正式支持用户态轻量级线程，它的出现让Java并发编程更加简单高效。这篇文章将深入探讨虚拟线程的概念和原理，帮助你更好的理解和使用虚拟线程。&lt;/p&gt;
&lt;h2 id="为什么需要虚拟线程"&gt;为什么需要虚拟线程
&lt;/h2&gt;&lt;p&gt;在虚拟线程出现之前，Java中主要依靠线程（Thread）实现并发编程，通过将多个任务分配给多个线程来实现并发执行，每个线程具有独立的执行栈，一个线程就是一个并发执行单元。
而Java语言中的线程和操作系统中的线程是一一对应的，Java代码中每创建一个线程，JVM都会调用操作系统的API来创建一个操作系统线程并映射到Java线程。这种并发方式有以下特点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;创建销毁：线程的创建和销毁都由需要操作系统内核来完成，涉及用户态和内核态的切换，开销较大。&lt;/li&gt;
&lt;li&gt;内存占用：在Linux系统上运行的JVM，每创建一个线程，JVM会为其默认分配1MB的内存空间，用于存储线程的执行栈等信息，对应的操作系统线程也会分配约10KB的内存空间用于保存操作系统线程栈，内存占用量较大。&lt;/li&gt;
&lt;li&gt;上下文切换：线程由操作系统调度运行，每次切换线程都需要保存和恢复线程的上下文，这涉及保存和恢复大量寄存器、栈和其他状态信息，也会使CPU缓存失效，且同样涉及用户态和内核态的切换，开销较大，且过多的线程还会导致一个结果就是大量的CPU资源都消耗在调度和切换执行线程上，用到执行线程任务的比例就会变小，CPU负载也会很大。&lt;/li&gt;
&lt;li&gt;可用数量（支持并发数）：在Linux系统中，一个进程可以创建的线程数有限，又由于线程创建占用内存资源较多，调度切换执行消耗的CPU资源也大，因此可用线程数很有限，通常为数千个，因此应用所能够支持的并发任务数也有限。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;基于以上几个特点，一些现代编程语言纷纷引入了“&lt;strong&gt;轻量线程&lt;/strong&gt;”的概念，例如Go语言中的协程、Kotlin语言中的协程等。Java语言也终于在JDK21中正式引入了虚拟线程，这是Java标准库首次正式支持用户态轻量级线程。&lt;/p&gt;
&lt;h2 id="虚拟线程解决了哪些问题"&gt;虚拟线程解决了哪些问题
&lt;/h2&gt;&lt;p&gt;虚拟线程实际上是用户态的轻量级线程，有以下特点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;创建销毁：虚拟线程的创建和销毁都由JVM在用户态完成，不需要操作系统的参与，因此避免了操作系统内核态与用户态的切换带来的性能损耗。&lt;/li&gt;
&lt;li&gt;内存占用：虚拟线程使用的内存由JVM控制，通常只需要几KB的内存空间，远小于操作系统线程的1MB内存空间。&lt;/li&gt;
&lt;li&gt;上下文切换：全部在用户态，且足够轻量，只需保存和恢复少量的状态信息。&lt;/li&gt;
&lt;li&gt;可用数量（支持并发数）：由于虚拟线程的控制权在JVM，内存占用小，调度执行时的上下文切换都在内核态的JVM中不会有操作系统线程上下文切换那样高的性能损耗，因此可创建的数量相比线程多很多，通常为数百万，意味着应用能够支持的并发任务数巨大。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;总结来看，使用线程实现的并发系统，在创建销毁、内存占用、上下文切换、可用数量等方面都有明显的性能瓶颈，而使用虚拟线程实现的并发系统，在这些方面都有了明显的改善，能够支持更多的并发任务，提高系统的并发性能。&lt;/p&gt;
&lt;h2 id="虚拟线程是如何运行的"&gt;虚拟线程是如何运行的
&lt;/h2&gt;&lt;p&gt;JVM后台管理了一组用于运行虚拟线程的操作系统线程，虚拟线程会被JVM中内置的调度器调度到这些操作系统线程上运行，而当虚拟线程调用到阻塞API时，JVM运行时会将这个虚拟线程挂起，然后取调用操作系统非阻塞API去帮虚拟线程完成IO操作，此时运行该虚拟线程的操作系统线程就会被释放用于运行其他虚拟线程，而不会被IO阻塞。待虚拟线程的IO操作完成，调度器再选择合适的操作系统线程恢复被挂起的这个虚拟线程。
可见，是JVM识别了虚拟线程中的阻塞API，然后将实际调用替换为非阻塞API，这一点很关键，如果虚拟线程调用了JVM所不能识别并转换的阻塞API，那么运行虚拟线程的操作系统线程将被阻塞，无法运行其他虚拟线程，这一点需要特别注意。会造成操作系统线程阻塞的API有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;文件IO操作 &lt;code&gt;FileInputStream&lt;/code&gt;, &lt;code&gt;FileOutputStream&lt;/code&gt;, &lt;code&gt;FileChannel&lt;/code&gt;, &lt;code&gt;RandomAccessFile&lt;/code&gt;等类的读写&lt;/li&gt;
&lt;li&gt;Native（本地代码）中的阻塞操作，因为JVM无法干预本地代码的执行。&lt;/li&gt;
&lt;li&gt;一些数据库驱动，尤其是基于JDBC的数据库驱动如MySQL Connector/J、PostgreSQL JDBC 等。因为其底层使用了会阻塞操作系统线程的API。&lt;/li&gt;
&lt;li&gt;synchronized 关键字方法，由于synchronized 关键字方法是基于操作系统的锁实现的，而虚拟线程无法直接使用操作系统的锁。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="虚拟线程适合哪些业务场景"&gt;虚拟线程适合哪些业务场景
&lt;/h2&gt;&lt;p&gt;类似Golang的协程，虚拟线程以更低的成本支持了系统更高的并发性能，对于IO密集型系统有很大的提升，而对于CPU密集型系统，虚拟线程并没有优势。这是因为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对于CPU密集型系统，更重要的是将计算任务合理的分配到多个CPU核心上执行，并非支持很高的并发数。&lt;/li&gt;
&lt;li&gt;对于IO密集型系统，更重要的在于通过低成本创建大量并发执行单元而几乎不增加CPU负载。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="其他问题"&gt;其他问题
&lt;/h2&gt;&lt;h3 id="1-用户态线程"&gt;1. 用户态线程
&lt;/h3&gt;
 &lt;blockquote&gt;
 &lt;p&gt;进程的轻量化 =&amp;gt; 线程&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;早期的操作系统没有线程这样的概念，最小的并发执行单元是进程，每个进程有自己独立的执行环境，包括内存空间、文件描述符等，进程之间相互隔离。进程的创建和销毁消耗很大，后来随着多核CPU的兴起，为了充分利用多核CPU的性能，使得进程这个最基本执行单元内能够同时使用多个CPU核心，于是引入了线程概念，操作系统调度执行的执行的最小单元变成了线程，由于多个线程可以共享同一个进程的执行环境如内存空间和文件描述符，而无需像进程那样独立创建，这使得线程的创建和销毁成本大大小于进程，成为当时的并发编程利器。
有意思的是，在此之前就已经有人实现了一种完全在用户态管理和调度的轻量级进程，随后操作系统也实现了内核线程，也就是内核态轻量级进程。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;用户态线程支持的并发才能避免内核态和用户态的切换&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;在操作系统的调度逻辑中，线程和进程都是的 &lt;code&gt;task_struct&lt;/code&gt;,区别是前者支持共享内存空间和文件描述符等，线程已经是进程的轻量级实现，操作系统继续优化线程的内存使用即可，而想要避免用户态和内核态的切换，就只能由应用程序本身实现完全用户态的轻量级线程即可。&lt;/p&gt;
&lt;h3 id="2-虚拟线程和传统基于jdbc数据库连接池搭配不是好的选择"&gt;2. 虚拟线程和传统基于JDBC数据库连接池搭配不是好的选择
&lt;/h3&gt;&lt;p&gt;先说结论，虚拟线程和JDBC连接池搭配使用并非好的选择。&lt;/p&gt;
&lt;p&gt;根本矛盾是数据库连接对应的是真实的物理连接，这是一种稀缺资源，一个应用中的数据库连接数在虚拟线程所支持的超高并发面前显的微不足道，而以HikariCP为例的传统数据库连接池，当连接不足时获取连接的虚拟线程会被阻塞挂起，虽然操作系统线程不会被阻塞却也无法发挥作用。&lt;/p&gt;</description></item></channel></rss>