<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>码农的自留地 - 码农的自留地</title>
    <subtitle>语法 语义 语用</subtitle>
    <link rel="self" type="application/atom+xml" href="https://scp.net.cn/blog/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-08-08T19:30:00+08:00</updated>
    <id>https://scp.net.cn/blog/atom.xml</id>
    <entry xml:lang="en">
        <title>Git Worktree 实践指南</title>
        <published>2026-08-08T19:30:00+08:00</published>
        <updated>2026-08-08T19:30:00+08:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/git-worktree/"/>
        <id>https://scp.net.cn/blog/git-worktree/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/git-worktree/">&lt;p&gt;在维护一个稍具规模的仓库时，我最常遇到的烦躁时刻不是代码冲突，而是“分支切换”：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;功能分支写到一半，产品经理过来说“先帮我看一眼线上这个 bug”；&lt;/li&gt;
&lt;li&gt;刚切到 &lt;code&gt;main&lt;/code&gt; 准备 review 同事的 PR，IDE 立刻因为依赖版本不同而重新索引；&lt;/li&gt;
&lt;li&gt;想跑一个耗时 10 分钟的基准测试，却舍不得放下当前未提交的改动；&lt;/li&gt;
&lt;li&gt;只好 &lt;code&gt;git stash push -m &quot;wip&quot;&lt;/code&gt;，处理完再 &lt;code&gt;git stash pop&lt;/code&gt;，然后发现 stash 堆成了小山。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Git Worktree 就是为这种场景设计的。它允许同一个仓库拥有多个独立的工作目录，每个目录可以关联不同的分支，却共享同一个 &lt;code&gt;.git&lt;/code&gt; 对象库。这篇文章会覆盖它的核心概念、常用命令、实战场景以及我踩过的坑。&lt;/p&gt;
&lt;h2 id=&quot;1-he-xin-gai-nian-yi-ge-cang-ku-duo-ge-gong-zuo-mu-lu&quot;&gt;1. 核心概念：一个仓库，多个工作目录&lt;/h2&gt;
&lt;p&gt;在普通 Git 仓库里，工作目录（working tree）和 &lt;code&gt;.git&lt;/code&gt; 目录是一一对应的。&lt;code&gt;git worktree&lt;/code&gt; 打破了这个限制：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一个仓库可以有一个 &lt;strong&gt;main worktree&lt;/strong&gt;（你最初 &lt;code&gt;git clone&lt;/code&gt; 出来的那个目录）和多个 &lt;strong&gt;linked worktree&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;所有 worktree 共享同一个对象库，因此不重复占用磁盘空间；&lt;/li&gt;
&lt;li&gt;每个 linked worktree 内部有一个 &lt;code&gt;.git&lt;/code&gt; 文件，里面只保存 &lt;code&gt;gitdir&lt;/code&gt; 指针，指向主仓库的 &lt;code&gt;.git/worktrees/&amp;lt;id&amp;gt;&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;不同 worktree 不能同时检出同一个分支（Git 会拒绝，避免工作树状态互相覆盖），但可以用同一个分支的不同 commit（detached HEAD）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;简单理解：Worktree 是“分支级别的多窗口”，而不是“重新 clone 一份代码”。&lt;/p&gt;
&lt;h2 id=&quot;2-ming-ling-su-cha&quot;&gt;2. 命令速查&lt;/h2&gt;
&lt;p&gt;最常用的命令就这几条，记不住时可以回来查：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 创建新的 worktree，默认以当前分支名作为目录名&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; worktree add ../my-feature&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 指定目录和分支（分支不存在则自动创建）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; worktree add -b hotfix/123 ../hotfix origin/main&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 查看所有 worktree&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; worktree list&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 删除 worktree（不会删除分支，仅移除目录和登记信息）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; worktree remove ../my-feature&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 移动 worktree 目录&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; worktree move ../my-feature ../my-feature-v2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 清理已经不存在目录的登记记录&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; worktree prune&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 锁定 worktree，防止被误删除或清理&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; worktree lock ../my-feature&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; worktree unlock ../my-feature&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;3-dian-xing-shi-yong-chang-jing&quot;&gt;3. 典型使用场景&lt;/h2&gt;
&lt;h3 id=&quot;3-1-dai-ma-shen-cha-bu-zhong-duan-dang-qian-gong-zuo&quot;&gt;3.1 代码审查不中断当前工作&lt;/h3&gt;
&lt;p&gt;我正在 &lt;code&gt;feature/ai-summary&lt;/code&gt; 上写代码，同事让我 review 他的 &lt;code&gt;feature/new-auth&lt;/code&gt;。&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; worktree add ../roc-blog-review feature/new-auth&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; ../roc-blog-review&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 查看代码、运行测试、留下 review 意见&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; worktree remove ../roc-blog-review&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;主工作目录完全不动，review 结束后整个世界还是原来的样子。&lt;/p&gt;
&lt;h3 id=&quot;3-2-jin-ji-re-xiu-fu&quot;&gt;3.2 紧急热修复&lt;/h3&gt;
&lt;p&gt;线上告警，需要基于 &lt;code&gt;main&lt;/code&gt; 修一个 hotfix。常规做法是 &lt;code&gt;git stash&lt;/code&gt; 然后切分支，但 Worktree 更干脆：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; worktree add -b hotfix/2026-08-08 ../hotfix origin/main&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; ../hotfix&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 修改 -&amp;gt; 提交 -&amp;gt; push -&amp;gt; 发 PR&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; push origin hotfix/2026-08-08&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; ..&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; worktree remove ../hotfix&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;3-3-chang-shi-jian-ren-wu-yu-hou-tai-gou-jian&quot;&gt;3.3 长时间任务与后台构建&lt;/h3&gt;
&lt;p&gt;某些仓库构建一次需要十几分钟，我不想占用当前窗口等待：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; worktree add ../roc-blog-build release/v2.3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; ../roc-blog-build&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;nohup&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; zola build -o ../build-output&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; build.log&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;amp;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我可以在原目录继续写代码，另一个目录在后台慢慢构建。&lt;/p&gt;
&lt;h3 id=&quot;3-4-tan-suo-xing-shi-yan-yu-yuan-xing&quot;&gt;3.4 探索性实验与原型&lt;/h3&gt;
&lt;p&gt;想验证一个大胆的重构，但不确定能不能成功：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; worktree add -b experiment/refactor-cache ../experiment&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; ../experiment&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 开始拆东墙补西墙&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;即使改烂了，直接删除目录即可，主工作目录毫发无伤。&lt;/p&gt;
&lt;h2 id=&quot;4-shi-zhan-cong-chuang-jian-dao-qing-li&quot;&gt;4. 实战：从创建到清理&lt;/h2&gt;
&lt;p&gt;假设仓库路径是 &lt;code&gt;~/Work/roc-blog&lt;/code&gt;，我们新建一个并排的 worktree：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; cd ~/Work/roc-blog&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; git worktree add ../roc-blog-draft -b draft/git-worktree&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Preparing&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; worktree&lt;/span&gt;&lt;span&gt; (new&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; branch&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;draft/git-worktree&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;HEAD&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; is now at a1b2c3d 上次提交&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; git worktree list&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;/Users/shichaopeng/Work/roc-blog&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;      a1b2c3d&lt;/span&gt;&lt;span&gt; [main]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;/Users/shichaopeng/Work/roc-blog-draft&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; a1b2c3d&lt;/span&gt;&lt;span&gt; [draft/git-worktree]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;此时 &lt;code&gt;~/Work/roc-blog-draft&lt;/code&gt; 是一个完整的工作目录，可以独立编辑、推送。完成后清理：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; cd ~/Work/roc-blog&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; git worktree remove ../roc-blog-draft&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; git branch -D draft/git-worktree&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        # 如果不再需要该分支&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注意：&lt;code&gt;git worktree remove&lt;/code&gt; 会删除目录本身，但不会删除分支。如果分支还想保留，可以只执行 remove。&lt;/p&gt;
&lt;h2 id=&quot;5-jin-jie-ji-qiao&quot;&gt;5. 进阶技巧&lt;/h2&gt;
&lt;h3 id=&quot;5-1-yong-bare-cang-ku-zuo-wei-da-ben-ying&quot;&gt;5.1 用 bare 仓库作为“大本营”&lt;/h3&gt;
&lt;p&gt;对于经常需要多个 worktree 的项目，可以先 clone 一个 bare 仓库：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; clone --bare git@github.com:dllen/roc-blog.git roc-blog.git&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; roc-blog.git&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; worktree add ../roc-blog-main main&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; worktree add -b feature/xyz ../roc-blog-feature&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样中央目录只保存 &lt;code&gt;.git&lt;/code&gt; 数据，没有工作树，管理起来更清爽。&lt;/p&gt;
&lt;h3 id=&quot;5-2-suo-ding-yu-xiu-fu&quot;&gt;5.2 锁定与修复&lt;/h3&gt;
&lt;p&gt;如果 worktree 目录位于外部磁盘或网络存储，Git 在清理时可能误判它“已消失”。可以手动锁定：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; worktree lock ../roc-blog-feature&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; worktree unlock ../roc-blog-feature&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果目录被手动删除，Git 记录还在，用 &lt;code&gt;prune&lt;/code&gt; 或 &lt;code&gt;remove --force&lt;/code&gt; 清理：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; worktree prune&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;            # 安全清理已不存在的目录&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; worktree remove --force ../roc-blog-feature&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;5-3-yu-ide-he-git-hooks-de-jian-rong&quot;&gt;5.3 与 IDE 和 Git hooks 的兼容&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;大多数现代 IDE（VS Code、IntelliJ、Cursor）都能识别 worktree 目录作为独立项目打开；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.git&lt;/code&gt; 在主仓库，linked worktree 里的 &lt;code&gt;.git&lt;/code&gt; 是文件不是目录，依赖 &lt;code&gt;git rev-parse --git-dir&lt;/code&gt; 的脚本通常无感；&lt;/li&gt;
&lt;li&gt;但 &lt;strong&gt;Git hooks&lt;/strong&gt; 是按 &lt;code&gt;core.hooksPath&lt;/code&gt; 或 &lt;code&gt;.git/hooks&lt;/code&gt; 生效的，linked worktree 共享同一套 hooks，如果 hooks 里硬编码了仓库路径，需要改成相对路径或 Git 变量；&lt;/li&gt;
&lt;li&gt;子模块（submodule）在 worktree 中行为较复杂，子模块默认不会自动初始化，需要手动处理。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;5-4-bi-mian-tong-yi-ge-fen-zhi-bei-duo-ge-worktree-jian-chu&quot;&gt;5.4 避免“同一个分支被多个 worktree 检出”&lt;/h3&gt;
&lt;p&gt;Git 会阻止两个 worktree 同时关联同一个分支，因为那样会导致 HEAD 指针冲突。解决方式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用不同的分支；&lt;/li&gt;
&lt;li&gt;或者使用 detached HEAD：&lt;code&gt;git worktree add ../foo &amp;lt;commit-sha&amp;gt;&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;6-worktree-vs-qi-ta-fang-an&quot;&gt;6. Worktree vs 其他方案&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;方案&lt;/th&gt;&lt;th&gt;优点&lt;/th&gt;&lt;th&gt;缺点&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;git stash&lt;/code&gt;&lt;/td&gt;&lt;td&gt;零额外空间&lt;/td&gt;&lt;td&gt;容易堆积，状态恢复易出错，无法并行&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;重新 &lt;code&gt;git clone&lt;/code&gt;&lt;/td&gt;&lt;td&gt;完全隔离&lt;/td&gt;&lt;td&gt;重复下载历史，占用双倍磁盘，跨仓库操作麻烦&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;直接切换分支&lt;/td&gt;&lt;td&gt;最简单&lt;/td&gt;&lt;td&gt;中断当前上下文，依赖/索引需要重建&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;git worktree&lt;/code&gt;&lt;/td&gt;&lt;td&gt;共享对象库、独立目录、并行工作&lt;/td&gt;&lt;td&gt;需要管理多个目录，不能同分支双检出&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;对“需要并行处理两个以上分支”的场景，Worktree 通常是最平衡的解法。&lt;/p&gt;
&lt;h2 id=&quot;7-checklist-he-shi-gai-yong-worktree&quot;&gt;7. checklist：何时该用 Worktree？&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
需要 review 别人代码，但不想 stash 自己未完成的改动；&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
线上突发 bug，需要立刻基于 main 修一个 hotfix；&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
运行长时间构建/测试，想不阻塞当前编辑窗口；&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
想做一个破坏性实验，失败后能一键删除；&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
同一个仓库需要维护多个长期发布分支，频繁切换成本太高。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;8-jie-yu&quot;&gt;8. 结语&lt;/h2&gt;
&lt;p&gt;Git Worktree 不是银弹，但它把“分支切换”从一种中断变成了一种并行的选择。当你开始把 &lt;code&gt;git worktree add&lt;/code&gt; 当作开新标签页而不是换房间时，工作的流畅度会明显提升。下次再想 &lt;code&gt;git stash&lt;/code&gt; 的时候，不妨试试先 &lt;code&gt;git worktree add&lt;/code&gt;。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;参考命令：&lt;code&gt;git worktree --help&lt;/code&gt;，&lt;code&gt;git help worktree&lt;/code&gt;&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Prime Agent 深度技术分析：让 AI 代理真正长跑的架构设计</title>
        <published>2026-08-08T00:00:00+00:00</published>
        <updated>2026-08-08T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/prime-agent-architecture-analysis/"/>
        <id>https://scp.net.cn/blog/prime-agent-architecture-analysis/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/prime-agent-architecture-analysis/">&lt;h2 id=&quot;yi-wei-shen-me-xian-you-ai-agent-pao-bu-yuan&quot;&gt;一、为什么现有 AI Agent “跑不远”？&lt;/h2&gt;
&lt;p&gt;当前主流编码代理（Claude Code、Cursor、Codex 等）普遍存在三个结构性限制：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;无状态执行&lt;/strong&gt;——每次工具调用是独立进程，上一轮定义的变量下一轮消失，重复劳动多&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;线性会话&lt;/strong&gt;——对话无法分支，走错了只能回滚或重来，探索成本高&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;会话有寿命&lt;/strong&gt;——上下文超窗口就截断丢信息，终端关闭代理就死亡，长任务无法持续&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Prime Agent（v0.7.1，MIT 协议）的目标是构建一个&lt;strong&gt;真正适合长时间自主工作&lt;/strong&gt;的编码和研究代理。它的核心思路是 &lt;strong&gt;RLM（Recursive Language Model）&lt;/strong&gt;——把上下文当作变量，工具调用当作递归函数，代理运行在一个持久的 REPL 里。&lt;/p&gt;
&lt;p&gt;本文将拆解其六大核心机制，并用实战案例说明每一步。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;er-he-xin-ji-zhi-yi-chi-jiu-ipython-nei-he-mo-xing-you-liao-shou-he-jiao&quot;&gt;二、核心机制一：持久 IPython 内核——“模型有了手和脚”&lt;/h2&gt;
&lt;h3 id=&quot;she-ji-yuan-li&quot;&gt;设计原理&lt;/h3&gt;
&lt;p&gt;Prime Agent 默认只给模型&lt;strong&gt;一个工具：&lt;code&gt;ipython&lt;/code&gt;&lt;/strong&gt;。文件读写、Shell 命令、代码执行、网络请求——一切通过一个持久运行的 IPython 内核完成。&lt;/p&gt;
&lt;p&gt;关键在于&lt;strong&gt;持久&lt;/strong&gt;：内核中的变量、导入、函数定义在整个会话期间始终存活。模型不需要每次重新 import、重新定义数据结构。&lt;/p&gt;
&lt;h3 id=&quot;ji-shu-shi-xian&quot;&gt;技术实现&lt;/h3&gt;
&lt;p&gt;内核通过 &lt;strong&gt;ZeroMQ&lt;/strong&gt; 运行标准 Jupyter 协议，三条通道分工明确：&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;通道&lt;/th&gt;&lt;th&gt;Socket 类型&lt;/th&gt;&lt;th&gt;用途&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Shell&lt;/td&gt;&lt;td&gt;Dealer&lt;/td&gt;&lt;td&gt;执行请求/回复（&lt;code&gt;execute_request&lt;/code&gt;）&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;IOPub&lt;/td&gt;&lt;td&gt;Subscriber&lt;/td&gt;&lt;td&gt;标准输出、错误、结果、comm 消息&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Control&lt;/td&gt;&lt;td&gt;Dealer&lt;/td&gt;&lt;td&gt;中断、关闭、宿主请求回复&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;最关键的创新是&lt;strong&gt;双向通信&lt;/strong&gt;：Python 代码可以通过 Jupyter comm 通道（&lt;code&gt;host.request&lt;/code&gt; target）向 TypeScript 宿主发送类型化请求——生成子代理、管理目标、发送代理间消息。回复走 Control 通道而非 Shell 通道，避免 IPython 串行处理导致的死锁。&lt;/p&gt;
&lt;p&gt;内核还支持 &lt;strong&gt;&lt;code&gt;dill&lt;/code&gt; 序列化命名空间快照&lt;/strong&gt;：每次成功执行后自动快照（1.5s 防抖），内核重启或会话恢复时可还原全部变量状态。&lt;/p&gt;
&lt;h3 id=&quot;shi-zhan-an-li-shu-ju-fen-xi-hui-hua&quot;&gt;实战案例：数据分析会话&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 第一轮：模型加载数据&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span&gt; pandas&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; as&lt;/span&gt;&lt;span&gt; pd&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;df&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; pd&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;read_csv&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;metrics.csv&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;df&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;head&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 第二轮：用户追问——变量还在，无需重载&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;revenue_by_region&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; df&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;groupby&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;region&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;revenue&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;].&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sum&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;revenue_by_region&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 第三轮：建模——所有中间变量可用&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;from&lt;/span&gt;&lt;span&gt; sklearn&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;linear_model&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; import&lt;/span&gt;&lt;span&gt; LinearRegression&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;model&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; LinearRegression&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;model&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;fit&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;df&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;users&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;sessions&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]],&lt;/span&gt;&lt;span&gt; df&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;revenue&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;R² = &lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;model&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;score&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;df&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[[&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;users&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;sessions&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;]],&lt;/span&gt;&lt;span&gt; df&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;revenue&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;])&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:.4f&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在无状态 Agent 中，每轮都要重新 &lt;code&gt;import pandas&lt;/code&gt; 和 &lt;code&gt;pd.read_csv()&lt;/code&gt;，浪费 token 和时间。Prime Agent 的内核让变量跨轮次存活，效率显著提升。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;san-he-xin-ji-zhi-er-san-ceng-xiao-xi-dui-lie-shi-shi-gan-yu-bu-zhong-duan-gong-zuo-liu&quot;&gt;三、核心机制二：三层消息队列——“实时干预不中断工作流”&lt;/h2&gt;
&lt;h3 id=&quot;she-ji-yuan-li-1&quot;&gt;设计原理&lt;/h3&gt;
&lt;p&gt;用户在代理工作期间往往想补充指令或调整方向。大多数 Agent 只有“打断/不打断“二元选择——要么粗暴中断当前轮次，要么等代理干完再说。&lt;/p&gt;
&lt;p&gt;Prime Agent 设计了&lt;strong&gt;三级消息注入通道&lt;/strong&gt;：&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;通道&lt;/th&gt;&lt;th&gt;时机&lt;/th&gt;&lt;th&gt;用途&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Steering&lt;/strong&gt;（转向）&lt;/td&gt;&lt;td&gt;当前助手轮次结束后立即注入&lt;/td&gt;&lt;td&gt;调整方向、纠正错误&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Follow-up&lt;/strong&gt;（跟进）&lt;/td&gt;&lt;td&gt;代理完成所有工作后要停止时才触发&lt;/td&gt;&lt;td&gt;追加新任务&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Continuation&lt;/strong&gt;（延续）&lt;/td&gt;&lt;td&gt;宿主策略层控制是否继续&lt;/td&gt;&lt;td&gt;自主模式、目标系统&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3 id=&quot;ji-shu-shi-xian-1&quot;&gt;技术实现&lt;/h3&gt;
&lt;p&gt;Agent 类内部维护两个 &lt;code&gt;PendingMessageQueue&lt;/code&gt;，支持可配置的排空模式（&lt;code&gt;&quot;all&quot;&lt;/code&gt; 或 &lt;code&gt;&quot;one-at-a-time&quot;&lt;/code&gt;）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;steeringQueue&lt;/code&gt;：助手轮次结束后，循环先检查此队列，有消息就注入下一轮&lt;/li&gt;
&lt;li&gt;&lt;code&gt;followUpQueue&lt;/code&gt;：只在代理会话即将结束时触发（&lt;code&gt;shouldStopAfterTurn&lt;/code&gt; 返回 true 但还有 follow-up 消息）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;Continuation&lt;/code&gt; 层由宿主策略（如 Goals、Autonomous Mode）控制，决定代理是否在正常停止点继续工作。&lt;/p&gt;
&lt;h3 id=&quot;shi-zhan-an-li-dai-li-gong-zuo-zhong-shi-shi-yin-dao&quot;&gt;实战案例：代理工作中实时引导&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;用户：重构认证模块，把 JWT 迁移到 OAuth2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[代理开始工作，读取文件、分析结构...]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;用户（Enter 发送 Steering）：优先处理 token 刷新逻辑，其他先放放&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[代理当前轮次结束后，立即收到转向消息，调整工作重心]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[代理完成 token 刷新逻辑...]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;用户（Alt+Enter 发送 Follow-up）：完成后顺便检查下测试覆盖率&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[代理全部工作完成后，Follow-up 触发，开始检查测试]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Steering 不打断当前轮次的完整性（避免半成品状态），Follow-up 不浪费代理“还想干活“的惯性——两者配合实现了流畅的人机协作。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;si-he-xin-ji-zhi-san-die-dai-ya-suo-hui-hua-wu-xian-xin-xi-bu-diu&quot;&gt;四、核心机制三：迭代压缩——“会话无限，信息不丢”&lt;/h2&gt;
&lt;h3 id=&quot;she-ji-yuan-li-2&quot;&gt;设计原理&lt;/h3&gt;
&lt;p&gt;长会话必然超出模型上下文窗口。常见做法是截断旧消息或一次性摘要，但前者丢信息，后者摘要质量随对话增长而下降。&lt;/p&gt;
&lt;p&gt;Prime Agent 的压缩机制核心是&lt;strong&gt;迭代链接式摘要&lt;/strong&gt;：每次压缩都把上一次压缩的摘要作为输入，确保信息跨多轮压缩累积保留。&lt;/p&gt;
&lt;h3 id=&quot;ji-shu-shi-xian-2&quot;&gt;技术实现&lt;/h3&gt;
&lt;p&gt;触发条件：&lt;code&gt;contextTokens &amp;gt; contextWindow - reserveTokens&lt;/code&gt;（默认保留 16384 tokens）。&lt;/p&gt;
&lt;p&gt;流程：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;从最新消息往回走，累积 token 直到 &lt;code&gt;keepRecentTokens&lt;/code&gt;（默认 20k），确定切割点&lt;/li&gt;
&lt;li&gt;提取从上次压缩边界到切割点之间的消息&lt;/li&gt;
&lt;li&gt;调用 LLM 生成结构化摘要，&lt;strong&gt;附带上一次压缩摘要&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;插入 &lt;code&gt;CompactionEntry&lt;/code&gt;，记录 &lt;code&gt;firstKeptEntryId&lt;/code&gt; 链接下一次压缩的起点&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;摘要格式是结构化的：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;##&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Goal&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;##&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Constraints &amp;amp; Preferences&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;##&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Progress&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;###&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Done / In Progress / Blocked&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;##&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Key Decisions&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;##&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Next Steps&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;##&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Critical Context&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;read-files&amp;gt;&lt;/span&gt;&lt;span&gt;path/to/file1.ts&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/read-files&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;modified-files&amp;gt;&lt;/span&gt;&lt;span&gt;path/to/changed.ts&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/modified-files&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;关键细节&lt;/strong&gt;：文件追踪是跨压缩累积的——第 1 次压缩记录的已修改文件，第 3 次压缩的摘要中仍然可见。内核持久化也会在摘要中注明（“Python variables survive across calls”），避免模型重复定义。&lt;/p&gt;
&lt;h3 id=&quot;shi-zhan-an-li-3-xiao-shi-zhong-gou-hui-hua&quot;&gt;实战案例：3 小时重构会话&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[会话开始] 上下文：0/200k&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# 第 1-15 轮：探索代码结构、理解架构&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;上下文达到 185k → 触发自动压缩&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;→ 摘要1：保留了架构分析、关键决策、已读文件列表&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# 第 16-35 轮：实现 OAuth2 迁移&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;上下文再次达到 185k → 触发第二次压缩&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;→ 摘要2 输入 = 摘要1 + 新消息 → 保留架构+迁移进度+关键代码位置&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# 第 36-50 轮：写测试、修 bug&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;上下文第三次达到 185k → 触发第三次压缩&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;→ 摘要3 输入 = 摘要2 + 新消息 → 全部关键信息仍在&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;手动压缩可以加自定义指令：&lt;code&gt;/compact 重点保留失败的测试名和迁移 checklist&lt;/code&gt;。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;wu-he-xin-ji-zhi-si-daemon-jia-gou-dai-li-yong-bu-si&quot;&gt;五、核心机制四：Daemon 架构——“代理永不死”&lt;/h2&gt;
&lt;h3 id=&quot;she-ji-yuan-li-3&quot;&gt;设计原理&lt;/h3&gt;
&lt;p&gt;用户关闭终端不应该杀死代理。网络闪断不应该丢失工作进度。进程崩溃应该自动恢复。&lt;/p&gt;
&lt;h3 id=&quot;ji-shu-shi-xian-3&quot;&gt;技术实现&lt;/h3&gt;
&lt;p&gt;Daemon 是三层进程拓扑：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Supervisor（路由 + 全局调度）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ├─ Catalog（保存会话扫描）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ├─ Worker A（Session 1 的代理执行）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ├─ Worker B（Session 2 的代理执行）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  └─ Worker C（...）&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;核心能力：&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;能力&lt;/th&gt;&lt;th&gt;实现&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;崩溃恢复&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Worker 崩溃 → 重启 → 回放日志 → 跳过不确定命令&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Supervisor 自愈&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Worker 检测 Supervisor 消失 → 原子竞租 → 启动新 Supervisor&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;幂等日志&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;clientId + commandId&lt;/code&gt; 去重，崩溃时未完成命令不重复执行&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;代际感知游标&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;每个 Event 属于某个 Worker 代际，重连时精确回放&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;会话租约&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;进程安全锁防止同会话并发写入&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;协议 v7（JSONL 帧）支持 50+ 命令类型，包括会话生命周期、提示、转向、定时任务、心跳、模型切换、树导航、子代理管理等。&lt;/p&gt;
&lt;h3 id=&quot;shi-zhan-an-li-chang-ren-wu-bu-zhong-duan&quot;&gt;实战案例：长任务不中断&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 场景：让代理跑一个 30 分钟的自动化迁移任务&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;prime-agent&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; --autonomous&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;  --autonomous-gate&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;npm run check&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;  --autonomous-max-turns&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 20&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;  --autonomous-timeout-ms&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1800000&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Migrate all API routes from Express to Fastify, fix all type errors&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 关掉笔记本下班&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 第二天回到办公室&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;prime-agent&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; attach&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;agent-i&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 代理还在跑，或者已经完成，所有进度完好&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 如果昨晚进程崩溃了？&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# Daemon 自动恢复 Worker，从崩溃点继续&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;liu-he-xin-ji-zhi-wu-shu-xing-hui-hua-tan-suo-bu-diu-li-shi&quot;&gt;六、核心机制五：树形会话——“探索不丢历史”&lt;/h2&gt;
&lt;h3 id=&quot;she-ji-yuan-li-4&quot;&gt;设计原理&lt;/h3&gt;
&lt;p&gt;编码工作中经常需要探索多个方案：方案 A 走了一半发现不对，想回退到分叉点尝试方案 B。线性对话要么丢失方案 A 的探索成果，要么创建新会话重新开始。&lt;/p&gt;
&lt;h3 id=&quot;ji-shu-shi-xian-4&quot;&gt;技术实现&lt;/h3&gt;
&lt;p&gt;会话以 JSONL 文件存储，每条记录有 &lt;code&gt;id&lt;/code&gt; 和 &lt;code&gt;parentId&lt;/code&gt;，构成树结构：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Root&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├─ A1 (用户消息: &amp;quot;方案A&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   ├─ A2 (助手: 实现 A...)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   └─ A3 (助手: 发现问题)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├─ B1 (从 A1 分叉, 用户: &amp;quot;试方案B&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   ├─ B2 (助手: 实现 B...)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   └─ B3 (助手: 完成)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;└─ C1 (从 B2 分叉, 用户: &amp;quot;优化 B&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    └─ C2 (助手: 优化完成)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;三种分支操作：&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;命令&lt;/th&gt;&lt;th&gt;效果&lt;/th&gt;&lt;th&gt;典型场景&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;/tree&lt;/code&gt;&lt;/td&gt;&lt;td&gt;同一文件内导航到任意节点，离开的分支可自动摘要&lt;/td&gt;&lt;td&gt;方案探索&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;/fork&lt;/code&gt;&lt;/td&gt;&lt;td&gt;从早期用户消息创建新会话文件&lt;/td&gt;&lt;td&gt;独立实验&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;/clone&lt;/code&gt;&lt;/td&gt;&lt;td&gt;复制当前活动分支到新文件&lt;/td&gt;&lt;td&gt;备份当前工作&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;分支摘要是关键：当你用 &lt;code&gt;/tree&lt;/code&gt; 从方案 B 跳回方案 A 时，方案 B 的工作成果会被自动摘要附加到方案 A 的上下文中——探索不丢信息。&lt;/p&gt;
&lt;h3 id=&quot;shi-zhan-an-li-qian-duan-kuang-jia-xuan-xing&quot;&gt;实战案例：前端框架选型&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;用户：用 React 重构首页&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[代理实现 React 版本，写了 15 轮...]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;用户：/tree    # 打开会话树视图&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# 导航回最初的分叉点&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;用户：试一下 Vue 版本&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[代理实现 Vue 版本，写了 12 轮...]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;用户：/tree    # 再次查看&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Vue 分支的探索自动摘要，附加到当前位置&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# 现在代理同时知道两个方案的关键差异&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;用户：对比两个方案的性能，选最优的&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;qi-he-xin-ji-zhi-liu-kua-gong-ying-shang-qie-huan-zhong-tu-huan-nao&quot;&gt;七、核心机制六：跨供应商切换——“中途换脑”&lt;/h2&gt;
&lt;h3 id=&quot;she-ji-yuan-li-5&quot;&gt;设计原理&lt;/h3&gt;
&lt;p&gt;不同模型各有所长：Claude 擅长分析推理，GPT 擅长代码生成，Gemini 上下文窗口最大。但现有 Agent 绑定单一模型，无法在对话中按需切换。&lt;/p&gt;
&lt;h3 id=&quot;ji-shu-shi-xian-5&quot;&gt;技术实现&lt;/h3&gt;
&lt;p&gt;Prime Agent 的统一 API 层用 &lt;strong&gt;&lt;code&gt;api&lt;/code&gt; 字段&lt;/strong&gt;（而非 &lt;code&gt;provider&lt;/code&gt;）作为分发键。同一 API 实现可被多个供应商复用（如 OpenAI 和 Azure OpenAI 共享 &lt;code&gt;openai-completions&lt;/code&gt;）。&lt;/p&gt;
&lt;p&gt;25+ 供应商懒注册——provider 代码从不静态导入，只在需要时加载。切换模型时消息格式自动转换，对用户透明。&lt;/p&gt;
&lt;h3 id=&quot;shi-zhan-an-li-hun-he-mo-xing-gong-zuo-liu&quot;&gt;实战案例：混合模型工作流&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 开启多模型循环&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;prime-agent&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; --models&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;claude-*,gpt-4o&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 交互中使用 Ctrl+L 切模型&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;用户：分析这段遗留代码的架构问题&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    # 用 Claude Sonnet（分析强）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;Ctrl+L&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span&gt; → 切到 GPT-4o&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;用户：根据上面的分析重构代码&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        # 用 GPT-4o（代码生成强）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;Ctrl+L&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span&gt; → 切到 Gemini&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;用户：总结所有改动，生成变更文档&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     # 用 Gemini（上下文窗口大，适合长文）&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也可以在提示中直接指定：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 子代理用不同模型&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;review&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = await&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; rlm&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Review auth code&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span&gt; name&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;reviewer&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span&gt; model&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;anthropic/claude-sonnet-4&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;implement&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = await&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; rlm&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Implement the fix&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span&gt; name&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;worker&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span&gt; model&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;openai/gpt-4o&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;ba-yuan-sheng-zi-dai-li-yu-dai-li-jian-tong-xin&quot;&gt;八、原生子代理与代理间通信&lt;/h2&gt;
&lt;h3 id=&quot;she-ji-yuan-li-6&quot;&gt;设计原理&lt;/h3&gt;
&lt;p&gt;复杂任务需要分工协作。Prime Agent 的子代理不是“模拟“的——是真实的独立 &lt;code&gt;AgentSession&lt;/code&gt; 实例，运行在独立的 Worker 进程中。&lt;/p&gt;
&lt;h3 id=&quot;ji-shu-shi-xian-6&quot;&gt;技术实现&lt;/h3&gt;
&lt;p&gt;在 IPython 内核中，&lt;code&gt;rlm()&lt;/code&gt; 是一个原生可调用对象：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 并行派出三个子代理&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;review&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = await&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; rlm&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Review auth module and reply to parent&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span&gt; name&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;auth-reviewer&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;tests&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = await&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; rlm&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Find missing tests and reply to parent&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span&gt; name&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;test-reviewer&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;docs&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = await&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; rlm&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Find stale docs and reply to parent&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span&gt; name&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;docs-reviewer&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 子代理通过 agent_message 回复&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;await&lt;/span&gt;&lt;span&gt; agent_message&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;send&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Auth review: 3 vulnerabilities found&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span&gt; receiver_role&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;parent&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 父代理可以后续给子代理发消息&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;await&lt;/span&gt;&lt;span&gt; agent_message&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;send&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Also check authorization boundaries&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    receiver_role&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;child&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    receiver_name&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;auth-reviewer&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;关键特性：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;rlm()&lt;/code&gt; &lt;strong&gt;立即返回&lt;/strong&gt;句柄（非阻塞），子代理在后台独立运行&lt;/li&gt;
&lt;li&gt;子代理继承父模型，也可指定不同模型&lt;/li&gt;
&lt;li&gt;子代理用量/成本归因到父代理的当前轮次&lt;/li&gt;
&lt;li&gt;注册表在压缩、内核重启、父代理恢复后仍存活&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;shi-zhan-an-li-dai-ma-shen-cha-liu-shui-xian&quot;&gt;实战案例：代码审查流水线&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 主代理调度三个子代理并行工作&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;security&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = await&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; rlm&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Security audit: check for SQL injection, XSS, auth bypass in src/&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    name&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;security-auditor&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    model&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;anthropic/claude-sonnet-4&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  # 推理强&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;performance&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = await&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; rlm&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Performance review: find N+1 queries, memory leaks, slow loops&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    name&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;perf-reviewer&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    model&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;openai/gpt-4o&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  # 代码分析快&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;style&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = await&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; rlm&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Code style: check naming, comments, error handling patterns&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    name&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;style-reviewer&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 三个子代理各自完成后通过 agent_message 回复&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 主代理汇总结果，生成综合报告&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;jiu-continual-harness-yu-refine-xi-tong-yue-yong-yue-zhun&quot;&gt;九、Continual Harness 与 /refine——“系统越用越准”&lt;/h2&gt;
&lt;h3 id=&quot;she-ji-yuan-li-7&quot;&gt;设计原理&lt;/h3&gt;
&lt;p&gt;大多数 Agent 是静态系统——同样的系统提示从头用到尾。Prime Agent 的 Continual Harness 存储补充提示、记忆、skill 描述、子代理规格，这些都是&lt;strong&gt;可精炼的持久状态&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;/refine&lt;/code&gt; 分析对话轨迹，对 Harness 状态应用小幅、有证据支撑的更新。&lt;/p&gt;
&lt;h3 id=&quot;shi-zhan-an-li&quot;&gt;实战案例&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 代理在工作中发现一个模式反复出现&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 手动触发精炼&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;await&lt;/span&gt;&lt;span&gt; refine&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Create a memory: always run typecheck before committing in this repo&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 精炼结果：一个持久记忆被写入 Harness&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 后续会话自动加载这条记忆，代理会主动先跑 typecheck&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 全局精炼——跨所有会话生效&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;await&lt;/span&gt;&lt;span&gt; refine&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Promote the error-handling pattern to a global skill&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span&gt; global_&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=True&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 查看精炼状态&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;await&lt;/span&gt;&lt;span&gt; refine&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  # {pending: 1, in_flight: 0}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;还可以用交互命令：&lt;code&gt;/refine 添加一条记忆：本项目的 PR 必须通过 CI 才能合并&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;精炼支持回滚：每次精炼记录修改前后的快照，可以撤回错误更新。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;shi-zi-zhu-mo-shi-wu-ren-zhi-shou-de-ai-gong-cheng-shi&quot;&gt;十、自主模式——“无人值守的 AI 工程师”&lt;/h2&gt;
&lt;h3 id=&quot;she-ji-yuan-li-8&quot;&gt;设计原理&lt;/h3&gt;
&lt;p&gt;Autonomous Mode 让代理在受边界约束的情况下自主运行：轮次上限、token 预算、时间限制、质量门禁。&lt;/p&gt;
&lt;h3 id=&quot;shi-zhan-an-li-zi-dong-xiu-fu-ci&quot;&gt;实战案例：自动修复 CI&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;prime-agent&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;  --autonomous&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;  --autonomous-gate&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;npm run check&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;  --autonomous-gate-retries&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;  --autonomous-max-turns&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 15&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;  --autonomous-max-tokens&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 80000&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;  --autonomous-timeout-ms&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1800000&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;  --model openai/gpt-4o&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Fix the failing CI checks and report the verified result&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;门禁机制&lt;/strong&gt;是关键创新：每个助手轮次结束后，所有门禁命令执行。失败门禁的输出会作为上下文喂给下一轮续行——代理知道哪里还没修好。门禁通过即视为完成，即使其他限制未到上限。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;shi-yi-skills-yu-kuo-zhan-ji-mu-shi-neng-li-zu-zhuang&quot;&gt;十一、Skills 与扩展——“积木式能力组装”&lt;/h2&gt;
&lt;h3 id=&quot;skills-python-hou-duan&quot;&gt;Skills（Python 后端）&lt;/h3&gt;
&lt;p&gt;Skills 遵循 &lt;a rel=&quot;external&quot; href=&quot;https://agentskills.io&quot;&gt;Agent Skills 标准&lt;/a&gt;。Prime Agent 扩展了 &lt;strong&gt;Python-backed Skills&lt;/strong&gt;——不只是提示词，而是安装到内核中的可调用 Python 包。&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 内置 websearch skill&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;from&lt;/span&gt;&lt;span&gt; websearch&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; import&lt;/span&gt;&lt;span&gt; web_search&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;results&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = await&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; web_search&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;RLM pattern in AI agents&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;results&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 内置 edit skill&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;from&lt;/span&gt;&lt;span&gt; edit&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; import&lt;/span&gt;&lt;span&gt; edit&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; edit&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;path&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;src/auth.ts&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span&gt; old_str&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;jwt.sign(payload)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span&gt; new_str&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;oauth2.createToken(payload)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 内置 goal skill&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;from&lt;/span&gt;&lt;span&gt; goal&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; import&lt;/span&gt;&lt;span&gt; goal&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;await&lt;/span&gt;&lt;span&gt; goal&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;create&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Ship v2 API with OAuth2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;current&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = await&lt;/span&gt;&lt;span&gt; goal&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;await&lt;/span&gt;&lt;span&gt; goal&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;complete&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  # 完成目标&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;自定义 skill 只需一个目录：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;my-skill/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  SKILL.md          # 指令和元数据&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  pyproject.toml    # Python 包定义&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  src/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    my_skill/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      __init__.py   # 导出 run() 或可调用对象&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;kuo-zhan-typescript-hou-duan&quot;&gt;扩展（TypeScript 后端）&lt;/h3&gt;
&lt;p&gt;TypeScript 扩展可以注册工具、命令、快捷键、事件处理器、UI 组件：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// ~/.prime/agent/extensions/permission-gate.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; ExtensionAPI&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;@earendil-works/pi-coding-agent&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;export default function&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;pi&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; ExtensionAPI&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  pi&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;on&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;tool_call&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;event&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (event&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;toolName&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ===&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;bash&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span&gt; event&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;input&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;command&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;?.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;includes&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;rm -rf&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      const&lt;/span&gt;&lt;span&gt; ok&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = await&lt;/span&gt;&lt;span&gt; ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;ui&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;confirm&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;危险操作！&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;允许 rm -rf？&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;!&lt;/span&gt;&lt;span&gt;ok)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; block&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; reason&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;被用户阻止&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot; }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  }&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;30+ 事件类型（&lt;code&gt;session_start&lt;/code&gt;、&lt;code&gt;tool_call&lt;/code&gt;、&lt;code&gt;context&lt;/code&gt;、&lt;code&gt;model_select&lt;/code&gt; 等）让扩展可以介入代理生命周期的几乎每个环节。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;shi-er-dui-bi-zong-jie-prime-agent-de-wei-zhi&quot;&gt;十二、对比总结：Prime Agent 的位置&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;维度&lt;/th&gt;&lt;th&gt;Prime Agent&lt;/th&gt;&lt;th&gt;Claude Code&lt;/th&gt;&lt;th&gt;Cursor&lt;/th&gt;&lt;th&gt;Devin/OpenHands&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;执行环境&lt;/td&gt;&lt;td&gt;持久有状态 IPython&lt;/td&gt;&lt;td&gt;无状态 Bash&lt;/td&gt;&lt;td&gt;IDE 终端&lt;/td&gt;&lt;td&gt;Docker 容器&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;长时间运行&lt;/td&gt;&lt;td&gt;Daemon + 压缩 + 自愈&lt;/td&gt;&lt;td&gt;tmux 保活&lt;/td&gt;&lt;td&gt;不支持&lt;/td&gt;&lt;td&gt;任务式，有限&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;模型切换&lt;/td&gt;&lt;td&gt;25+ 供应商，中途切换&lt;/td&gt;&lt;td&gt;仅 Claude&lt;/td&gt;&lt;td&gt;多模型但不中途切换&lt;/td&gt;&lt;td&gt;有限&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;并行工作&lt;/td&gt;&lt;td&gt;原生子代理 + 代理间通信&lt;/td&gt;&lt;td&gt;无&lt;/td&gt;&lt;td&gt;多 tab 非协作&lt;/td&gt;&lt;td&gt;有限并行&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;自我改进&lt;/td&gt;&lt;td&gt;&lt;code&gt;/refine&lt;/code&gt; 持久 Harness&lt;/td&gt;&lt;td&gt;无&lt;/td&gt;&lt;td&gt;无&lt;/td&gt;&lt;td&gt;无&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;会话分支&lt;/td&gt;&lt;td&gt;树形 + 分支摘要&lt;/td&gt;&lt;td&gt;线性&lt;/td&gt;&lt;td&gt;线性&lt;/td&gt;&lt;td&gt;线性&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;扩展性&lt;/td&gt;&lt;td&gt;TS 扩展 + Python Skills + MCP&lt;/td&gt;&lt;td&gt;有限 MCP&lt;/td&gt;&lt;td&gt;扩展市场&lt;/td&gt;&lt;td&gt;有限&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;安装门槛&lt;/td&gt;&lt;td&gt;较高（ZeroMQ + Python）&lt;/td&gt;&lt;td&gt;低&lt;/td&gt;&lt;td&gt;低（桌面 App）&lt;/td&gt;&lt;td&gt;中&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;成熟度&lt;/td&gt;&lt;td&gt;v0.7.1 早期&lt;/td&gt;&lt;td&gt;成熟&lt;/td&gt;&lt;td&gt;成熟&lt;/td&gt;&lt;td&gt;成熟&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3 id=&quot;he-xin-you-shi&quot;&gt;核心优势&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;真正适合长时间自主工作&lt;/strong&gt;——Daemon + 迭代压缩 + 进程自愈，三者组合目前独一无二&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;有状态执行&lt;/strong&gt;——内核变量跨调用存活，远比无状态 Shell 高效&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;可自我改进&lt;/strong&gt;——&lt;code&gt;/refine&lt;/code&gt; 让系统在持续使用中越来越精准&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;探索友好&lt;/strong&gt;——树形会话 + 分支摘要，试错成本极低&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;he-xin-lie-shi&quot;&gt;核心劣势&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;安装复杂&lt;/strong&gt;——ZeroMQ + Python 依赖，上手门槛明显高于竞品&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;早期项目&lt;/strong&gt;——v0.7.1，API 可能变动，文档和社区生态不成熟&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;仅 TUI&lt;/strong&gt;——没有 Web 界面或桌面 App，不习惯终端的用户不友好&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;社区小&lt;/strong&gt;——遇到问题可参考的资料和讨论较少&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;shi-san-jie-lun&quot;&gt;十三、结论&lt;/h2&gt;
&lt;p&gt;Prime Agent 的架构设计瞄准了一个被忽视但至关重要的方向：&lt;strong&gt;让 AI 代理真正能“长跑“&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;它的六大核心机制（持久内核、三层消息队列、迭代压缩、Daemon 架构、树形会话、跨供应商切换）形成了一个相互支撑的系统——持久内核让执行有状态，迭代压缩让会话无上限，Daemon 让代理不死，树形会话让探索无代价，三层队列让人机协作流畅，跨模型切换让每个子任务用最合适的“大脑“。&lt;/p&gt;
&lt;p&gt;虽然项目还处于早期阶段，但其架构思想——RLM 模式、Continual Harness、Daemon-backed 会话——值得所有 AI Agent 开发者关注。这些不是锦上添花的功能，而是解决“代理跑不远“这一根本问题的结构性方案。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;can-kao&quot;&gt;参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/PrimeIntellect-ai/prime-agent&quot;&gt;PrimeIntellect-ai/prime-agent&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://www.primeintellect.ai/&quot;&gt;PrimeIntellect 官网&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://arxiv.org/abs/2512.24601&quot;&gt;Recursive Language Models (RLM) 论文&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>AI 时代软件工程的变与不变</title>
        <published>2026-08-07T00:00:00+00:00</published>
        <updated>2026-08-07T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/ai-era-software-engineering/"/>
        <id>https://scp.net.cn/blog/ai-era-software-engineering/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/ai-era-software-engineering/">&lt;p&gt;过去两年，大家对“AI 写代码“的讨论经常停留在两个层面：要么是模型能力的跃迁（更强的推理、更好的代码），要么是提示词技巧（Prompt Engineering）。&lt;/p&gt;
&lt;p&gt;但当你真的想把 AI 放进一个持续演进的代码库，让它能在几个月、几年尺度上持续贡献、持续修复、持续维护时，真正决定成败的往往不是模型，而是模型周围那套&lt;strong&gt;工程系统&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;本文从三个具体角度聊聊 AI 时代软件工程的变与不变，以及工程师如何建立与之匹配的判断力。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;1-bian-ma-men-jian-zai-jiang-di-jue-ce-men-jian-zai-shang-sheng&quot;&gt;1. 编码门槛在降低，决策门槛在上升&lt;/h2&gt;
&lt;p&gt;以前写一个分布式系统，需要三年才能上手；现在有 AI 辅助，初级工程师也能写出来。&lt;/p&gt;
&lt;p&gt;但“什么时候该用分布式““什么时候该拆分”“什么时候该容忍不一致”，这些不是代码能力，是工程经验。AI 能帮你写代码，但帮不了你判断该不该写这段代码。&lt;/p&gt;
&lt;p&gt;更关键的是：AI 让更多人能碰到更复杂的系统——&lt;strong&gt;决策错误的代价变大了&lt;/strong&gt;。以前你的烂系统撑死影响几千用户，现在可以一键触达百万。&lt;/p&gt;
&lt;p&gt;一个具体的感受是：代码审查的价值在上升，而不是下降。AI 生成代码的速度远快于人类读代码审查的速度——如果没有人严格把关，烂代码的上线速度会比以前快十倍。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;2-fan-kui-huan-shi-ai-shi-dai-zui-xi-que-de-gong-cheng-neng-li&quot;&gt;2. 反馈环是 AI 时代最稀缺的工程能力&lt;/h2&gt;
&lt;p&gt;软件开发中最有价值的 discipline 不是写代码，是&lt;strong&gt;建立反馈环&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;没有一条能 red 的命令，什么调试技术都救不了你。这是调试问题的核心——但它同样是 AI 编程的核心。&lt;/p&gt;
&lt;p&gt;直接对话大模型，大模型的默认行为：读代码 → 猜原因 → 改 → 看结果运气好对，运气差把本来没问题的代码改坏了。这套循环在没有真实反馈信号的情况下，准确率很低。&lt;/p&gt;
&lt;p&gt;有反馈环的人和没有反馈环的人，在 AI 辅助下的表现差距会越拉越大前者知道什么时候该信 AI 的输出，什么时候该质疑，因为他们有独立的验证手段。后者只能跟着 AI 的节奏走：AI 对了他对，AI 错了他不知道。&lt;/p&gt;
&lt;p&gt;培养反馈环意识最简单的方式：每次遇到 bug，先写一条能复现的命令，再去读代码——不要先读代码再猜原因。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;3-jia-gou-she-ji-zhong-xin-zhi-qian&quot;&gt;3. 架构设计重新值钱&lt;/h2&gt;
&lt;p&gt;“这个模块该暴露什么接口”“两块代码之间的依赖怎么组织”“哪些变化应该放在一起”——这些问题 AI 目前没有稳定的好答案。&lt;/p&gt;
&lt;p&gt;代码生成是执行，架构是决策。执行变快后，决策的相对成本在上升。&lt;/p&gt;
&lt;p&gt;Kent Beck 说过一句话现在读起来更有意思：“每天都投入系统的设计。“AI 让执行变快了，意味着你每天能做的决策轮次变多；决策质量差的话，执行越快浪费越大。&lt;/p&gt;
&lt;p&gt;一个具体场景：AI 生成的代码通常在一个 session 内看起来完全合理，但在时间维度上未必。选择用哪个方案，判断基准应该包括“这个方案一年后还能读吗“。这种跨时间的判断力来自维护代码的经验，不是读教程能学到的&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;4-bian-jie-he-ji-cheng-de-gong-zuo-liang-zhan-bi-zai-shang-sheng&quot;&gt;4. 边界和集成的工作量占比在上升&lt;/h2&gt;
&lt;p&gt;单个函数、单块逻辑 AI 写得越来越好；但把多个 AI 生成的东西组合起来、让它们在边界上一致工作，这部分变化不大。&lt;/p&gt;
&lt;p&gt;就像装修：自己组装宜家家具越来越容易，但协调水电、暖通、泥瓦的接口永远需要人。&lt;/p&gt;
&lt;p&gt;AI 时代最有价值的工程师，可能是&lt;strong&gt;最擅长定义边界的人&lt;/strong&gt;——知道哪个模块该做什么、不该做什么，知道模块之间怎么通信、出了矛盾怎么仲裁。这些判断需要理解系统的全貌，不是 AI 能替你做的。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;5-ru-he-pei-yang-ai-shi-dai-de-gong-cheng-pin-wei&quot;&gt;5. 如何培养 AI 时代的工程品味&lt;/h2&gt;
&lt;p&gt;回到一个具体的问题：怎么培养“知道什么时候该信 AI、什么时候该质疑“的判断力？&lt;/p&gt;
&lt;p&gt;几个经过验证有效的路径：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;亲手把东西做坏，再亲手修好。&lt;/strong&gt; AI 能帮你写代码，但没法帮你承受“这段代码上线后崩了，半夜两点爬起来修“的后果。这个后果会刻进你的判断力里。调试一个你亲手引入的 bug，比读十篇“如何写出好代码“的文章收获更大。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;多读差代码，少读好代码。&lt;/strong&gt; 好代码是结果，你看不出设计者踩过什么坑。差代码把坑摊开给你看。有意识地读一些 legacy codebase、别人的 stackoverflow 答案、开源项目的老版本。看到别扭的地方停下来想：如果是我来改，怎么改？这比刷算法题更能训练工程直觉。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;问“这个 decision 改变了什么“。&lt;/strong&gt; 每次看到一个架构 decision，追问：如果反过来做，什么会变坏？能看清 tradeoff 的人，在 review AI 输出时不容易被牵着走。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;刻意练习“拒绝 AI 的建议“。&lt;/strong&gt; 选一个中等复杂的 task，让 AI 给你一个方案，然后你自己想清楚再评估它的方案。不一致的地方问自己：是我错了还是 AI 错了？慢慢地你会开始能预测 AI 在哪类问题上会出错。这不是玄学，是 pattern recognition。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;做一些需要维护的东西。&lt;/strong&gt; 写代码和养代码是两件不同的事。前者靠逻辑，后者靠品味。维护一个你一年前写的项目，你会惊讶于自己当时的很多“聪明“选择现在看来是噩梦。这个过程会教会你：什么样的决定在当时看起来合理，但一年后仍然合理。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;zui-hou&quot;&gt;最后&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;少问 AI 能做什么，多问自己不会做什么。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;AI 能做的事情越来越不需要培养；你不会做的事情才是你独特价值所在。&lt;/p&gt;
&lt;p&gt;找到你能力图谱里 AI 补不上的那块——可能是系统设计，可能是用户理解，可能是性能调优，也可能是团队协调——然后把精力往那里集中。&lt;/p&gt;
&lt;p&gt;技术品味不是读出来的，是&lt;strong&gt;做决策做到足够多次，被后果教育出来的&lt;/strong&gt;。AI 不会替代这个过程，只会加速它的节奏。&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Matt Pocock Skills 体系解析：设计哲学与核心 Skill 导读</title>
        <published>2026-08-07T00:00:00+00:00</published>
        <updated>2026-08-07T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/mattpocock-skills-design-analysis/"/>
        <id>https://scp.net.cn/blog/mattpocock-skills-design-analysis/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/mattpocock-skills-design-analysis/">&lt;p&gt;Matt Pocock 是 TypeScript 社区的知名布道者，同时也是一位在 AI 编程工具上投入很深的工程师。他开源了一套 AI Coding Skills，目标不是给 AI 塞更多知识，而是给 AI 编程建立&lt;strong&gt;工程纪律&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;本文不带滤镜地解析这套系统的设计思路、核心 Skill 的实现逻辑，以及它实际要解决什么问题。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;1-xiang-mu-jie-gou-promoted-vs-non-promoted&quot;&gt;1. 项目结构：promoted vs. non-promoted&lt;/h2&gt;
&lt;p&gt;项目把 skills 分成四个 bucket：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;skills/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  engineering/   # 18 个 promoted skills，出现在 plugin.json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  productivity/  # 7 个 promoted skills&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  misc/          # 不 promoted，不对外暴露&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  in-progress/   # beta 版本，同上&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  deprecated/    # 已废弃，同上&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这是一个很实用的边界设计：beta 和正式的要分开，没有充分验证的不能进 plugin.json。两个 promoted bucket 的 skills 同时需要在 &lt;code&gt;docs/&lt;/code&gt; 目录有对应的文档页，发布后的 URL 固定为 &lt;code&gt;aihero.dev/skills-&amp;lt;name&amp;gt;&lt;/code&gt;，与文件路径解耦。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;.claude-plugin/plugin.json&lt;/code&gt; 是精确的白名单——里面列的每一个 skill 才被插件打包。用户装了什么完全透明，没有隐藏的 magic。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;2-skill-md-de-frontmatter-yue-ding&quot;&gt;2. SKILL.md 的 frontmatter 约定&lt;/h2&gt;
&lt;p&gt;每个 skill 就是一个 &lt;code&gt;SKILL.md&lt;/code&gt; 文件，前端固定 YAML frontmatter：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; tdd&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;description&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; Test-driven development. Use when the user wants to build features or fix bugs test-first...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;---&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;name&lt;/code&gt; 是全局唯一标识，&lt;code&gt;description&lt;/code&gt; 有两个作用：人类读它理解 skill 是干什么的，更重要的是&lt;strong&gt;模型靠这段描述决定何时 reach for 这个 skill&lt;/strong&gt;。description 写得粗糙，模型就会 reach for 错。&lt;/p&gt;
&lt;p&gt;第三个隐含维度是“谁可以调用“，通过两个标记控制：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;user-invoked&lt;/strong&gt;：只在你显式调用时才触发&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;model-invoked&lt;/strong&gt;：模型可以自动 reach for&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所有 user-invoked skill 都是编排层（orchestration），它们负责协调；model-invoked skill 才是真正干活的底层能力。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;3-grill-de-ben-zhi-dui-kang-xing-zhui-wen-zhi-dao-dui-qi&quot;&gt;3. Grill 的本质：对抗性追问直到对齐&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;grilling&lt;/code&gt; 是整个 skill 体系的核心原子。它解决的是 AI 编程中最高频的失败模式：&lt;strong&gt;你以为它懂了，做出来发现完全不是那么回事&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;Grilling 的算法不复杂但有效：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;维护一个&lt;strong&gt;前沿（frontier）&lt;/strong&gt;：所有依赖已解决的决策集合&lt;/li&gt;
&lt;li&gt;每轮向前沿所有问题同时发起追问，每条问题附上推荐答案&lt;/li&gt;
&lt;li&gt;用户回答后重新计算前沿，继续下一轮&lt;/li&gt;
&lt;li&gt;前沿为空时结束&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;关键设计点：每个问题必须同时给出推荐答案。这不是给用户参考，是&lt;strong&gt;强迫 AI 自己先想清楚&lt;/strong&gt;。一个你自己都拿不出推荐答案的问题，大概率是还没想清楚该问什么。&lt;/p&gt;
&lt;p&gt;Fact（文件结构、工具行为）由 AI 自己派 sub-agent 去查，Decision（用哪个方案）留给用户——这消除了“用户答不上来因为信息本该 AI 自己查“这种内耗。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;grill-with-docs&lt;/code&gt; 在 grilling 之上叠了一层 &lt;code&gt;domain-modeling&lt;/code&gt;：把决策同步写入 &lt;code&gt;CONTEXT.md&lt;/code&gt;（术语表）和 ADR（架构决策记录）。 grilling 是 stateless 的追问；&lt;code&gt;grill-with-docs&lt;/code&gt; 是 stateful 的，同时留下文档。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;4-tdd-fan-kui-huan-you-xian-yu-cai-ce&quot;&gt;4. TDD：反馈环优先于猜测&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;tdd&lt;/code&gt; skill 的核心论点是：&lt;strong&gt;没有一条能 red 的命令，什么调试技术都救不了你。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Phase 1 花最大篇幅讲的不是怎么写测试，而是怎么构造反馈环。列了 10 种构造方式，从“failing test at the seam“到“replay captured trace“，再到“bisection harness“和“HITL bash script“。顺序就是优先级——优先构造确定性强的环，不行再退化。&lt;/p&gt;
&lt;p&gt;一旦有了环，才进入 Phase 2–5 的假设→验证循环。每个假设必须是&lt;strong&gt;可证伪&lt;/strong&gt;的，格式是“If X is the cause, then Y will happen“——能写出这个句子才算真假设，不是 vibe。&lt;/p&gt;
&lt;p&gt;这个 discipline 在直觉上跟大多数人的调试习惯相反：我们倾向于先读代码猜原因，再去验证。但 AI 生成的代码在没有上下文信号的情况下，猜测的准确率更低。强制先建环再推理，是针对这个场景的专项设计。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;5-code-review-shuang-zhou-zheng-jiao-fen-chi&quot;&gt;5. Code Review：双轴正交分离&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;code-review&lt;/code&gt; 把 review 拆成两个独立 sub-agent：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Standards 轴&lt;/strong&gt;：代码规范（repo 文档 + Fowler smell baseline）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Spec 轴&lt;/strong&gt;：实现是否忠实于需求&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;为什么要分开？因为一个变更可能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;完美符合规范，但实现了错误的功能 → Standards 通过，Spec 失败&lt;/li&gt;
&lt;li&gt;完全满足需求，但破坏了团队约定 → Spec 通过，Standards 失败&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;合并成一条报告，两者会互相掩盖。分开报告，每个轴独立出结论，上层聚合。&lt;/p&gt;
&lt;p&gt;Fowler smell baseline 是固定的 12 个 smells（Duplicated Code、Shotgun Surgery、Divergent Change 等），即使 repo 没有成文规范，这套 baseline 仍然适用。Repo 文档优先；没有文档时才用 baseline。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;6-zu-he-you-yu-ji-cheng&quot;&gt;6. 组合优于继承&lt;/h2&gt;
&lt;p&gt;一个值得注意的设计选择：skill 之间大量通过&lt;strong&gt;组合&lt;/strong&gt;而非&lt;strong&gt;继承&lt;/strong&gt;来复用逻辑。&lt;/p&gt;
&lt;p&gt;最典型的例子是 &lt;code&gt;grill-with-docs&lt;/code&gt; 的 SKILL.md，只有 3 行：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; grill-with-docs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;disable-model-invocation&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Run a &lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;`/grilling`&lt;/span&gt;&lt;span&gt; session, using the &lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;`/domain-modeling`&lt;/span&gt;&lt;span&gt; skill.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它不重复 grilling 的逻辑，只是把两个已验证的 skill 串联起来。router 层（&lt;code&gt;ask-matt&lt;/code&gt;）也只有 140 行，精确描述所有 skill 的关系图，自己不含业务逻辑。&lt;/p&gt;
&lt;p&gt;这个模式的好处是：每个 skill 只验证一次，组合方式无穷多，维护成本低。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;7-ping-jia-ta-jie-jue-liao-shen-me-mei-jie-jue-shen-me&quot;&gt;7. 评价：它解决了什么，没解决什么&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;它解决的问题：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AI 快速产出但质量不稳定 → TDD + code review 把质量门控前置&lt;/li&gt;
&lt;li&gt;对齐靠猜，做完才发现错 → grilling 强制前置追问&lt;/li&gt;
&lt;li&gt;反馈环缺失导致调试靠猜 → diagnosing-bugs 强制先建环再推理&lt;/li&gt;
&lt;li&gt;文档和决策记录随对话消失 → domain-modeling 和 ADRs 强制留档&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;它没解决的问题：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;团队内部的对齐（利益相关者、PM、设计师）——这部分还是靠人&lt;/li&gt;
&lt;li&gt;模型本身能力不足的场景——skill 是纪律，不提升模型智商&lt;/li&gt;
&lt;li&gt;需要创造性的架构突破——它优化的是决策质量，不是决策的创造性&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;最后一点值得多说：这套 skill 的设计哲学是&lt;strong&gt;收敛&lt;/strong&gt;，不是发散。它假设你已有一个要解决的问题，只是在实现路径上有歧义。如果问题是“我不知道要做什么“，skill 系统帮不了你——你需要的是市场调研、用户访谈，而不是一套调试流程。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;相关阅读：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/blog/deep-dive-into-agent-skills/&quot;&gt;彻底搞懂 Agent Skills：从原理到实践&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/spec-driven-development-depth-analysis/&quot;&gt;Spec-Driven Development 深度解析&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>用 Skill 系统开发 2048：完整的工程流程演示</title>
        <published>2026-08-07T00:00:00+00:00</published>
        <updated>2026-08-07T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/skill-system-2048-full-demo/"/>
        <id>https://scp.net.cn/blog/skill-system-2048-full-demo/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/skill-system-2048-full-demo/">&lt;p&gt;用 AI 写代码，直接对话当然可以更快地拿到结果。但当项目需要跨 session 维护、需要多人交接、需要稳定质量时，直接对话的代价就开始累积。&lt;/p&gt;
&lt;p&gt;本文用开发一个网页版 2048 游戏，完整演示 Skill 系统的工作流程。每一个阶段都给出真实产出，不是概念图。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;qi-dian-jin-mu-lu-pao-setup&quot;&gt;起点：进目录，跑 setup&lt;/h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 2048-game&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;/setup-matt-pocock-skills&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这一步问你三个问题：issue tracker 选哪个（GitHub / Linear / 本地文件）、triage 用哪些标签、文档放哪里。选本地文件即可，零配置。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;jie-duan-yi-grill-with-docs-dui-qi-xiang-fa&quot;&gt;阶段一：/grill-with-docs — 对齐想法&lt;/h2&gt;
&lt;p&gt;直接让 AI 写 2048，它大概率直接开干，做完你发现“UI 风格不是我想要的“或者“分数没有持久化“。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;/grill-with-docs&lt;/code&gt; 的做法：先问清楚，再动手。&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;/grill-with-docs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;❓ Q1 — 交付形式：单文件 HTML 还是分离成三个文件？&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ➡️ 推荐：单文件，开发最快&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;❓ Q2 — 移动方式：键盘方向键、触屏滑动、还是两者？&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ➡️ 推荐：先键盘，触屏作为 v2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;❓ Q3 — 分数机制：仅当前分数，还是 + 最高分持久化到 localStorage？&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ➡️ 推荐：两者都要，刷新不丢最高分&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;❓ Q4 — Game Over 处理：模态框还是覆盖层 + 按钮？&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ➡️ 推荐：覆盖层，不需要打断&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;❓ Q5 — UI 风格：纯色、渐变、还是图标？&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ➡️ 推荐：2n 对应不同背景色，2048 金色，经典配色&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;❓ Q6 — 分数动画：+N 飘字还是静默更新？&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ➡️ 推荐：先静默，后续可加&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;每条问题都附推荐答案——这是&lt;strong&gt;强迫 AI 自己先想清楚&lt;/strong&gt;的设计。Grilling 结束后，&lt;code&gt;CONTEXT.md&lt;/code&gt; 写入项目：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; 2048 Game — 项目术语表&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;##&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; 核心概念&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;font-weight: bold;&quot;&gt; **&lt;/span&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;格子 (Cell)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;font-weight: bold;&quot;&gt;**&lt;/span&gt;&lt;span&gt;：棋盘上 4×4 的 16 个固定位置&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;font-weight: bold;&quot;&gt; **&lt;/span&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;砖块 (Tile)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;font-weight: bold;&quot;&gt;**&lt;/span&gt;&lt;span&gt;：带数字的移动方块，初始为 2 或 4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;font-weight: bold;&quot;&gt; **&lt;/span&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;合并 (Merge)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;font-weight: bold;&quot;&gt;**&lt;/span&gt;&lt;span&gt;：同数字碰撞后合并为 2n&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;##&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; 技术约定&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; 单文件交付：index.html，内嵌 CSS/JS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; 输入：键盘方向键；触屏 v2 再加&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; 分数：当前 + 最高分，localStorage 持久化&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; Game Over：覆盖层 + 按钮，无模态框&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个文件是后续所有 decision 的参照系，后续 session 里 AI 读它，用同样的术语跟你沟通。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;jie-duan-er-to-spec-sheng-cheng-gui-ge-wen-dang&quot;&gt;阶段二：/to-spec — 生成规格文档&lt;/h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;/to-spec&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;输出 &lt;code&gt;SPEC.md&lt;/code&gt;，写入 &lt;code&gt;.scratch/&lt;/code&gt; 目录：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; 2048 游戏规格说明&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;##&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; 功能范围 (v1)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;###&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; 核心机制&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; 4×4 网格，初始随机 2 个砖块（2 或 4，各 50%）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; 方向键控制滑动&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; 同数字合并为 2n，合并计分&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; 有效移动后随机空格生成新砖块&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; 四方向均无效时 Game Over&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;###&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; 分数系统&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; 当前分数：累加每次合并得分&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; 最高分：localStorage 读写，跨 session 保持&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;###&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; 游戏控制&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; New Game 按钮：重置棋盘和当前分，最高分保持&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; Game Over 覆盖层 + Try Again 按钮&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;##&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; 验收标准&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; [ ] 初始状态两个随机砖块&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; [ ] 方向键正确触发滑动&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; [ ] 同数字合并正确，分数正确累加&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; [ ] 一次滑动中每砖块只合并一次&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; [ ] 有效移动后才生成新砖块&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; [ ] 最高分持久化，刷新保留&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; [ ] 无法移动时显示 Game Over&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; [ ] New Game 重置棋盘和当前分&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;jie-duan-san-to-tickets-chai-cheng-ke-yan-zheng-de-tickets&quot;&gt;阶段三：/to-tickets — 拆成可验证的 tickets&lt;/h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;/to-tickets&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;把 spec 拆成 tracer-bullet tickets：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;tickets/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  01-grid-structure.md     # blocking: none&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  02-tile-rendering.md     # blocking: 01&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  03-movement-logic.md     # blocking: 02&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  04-merge-logic.md        # blocking: 03&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  05-spawn-logic.md        # blocking: 03&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  06-score-system.md       # blocking: 04&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  07-game-over-detection.md # blocking: 05, 06&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  08-ui-polish.md          # blocking: 07&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;每个 ticket 独立可验证，不是“写前端““写后端“这种大块&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;jie-duan-si-implement-tdd-hong-lu-xun-huan&quot;&gt;阶段四：/implement — TDD 红绿循环&lt;/h2&gt;
&lt;p&gt;以 &lt;strong&gt;ticket 04：合并逻辑&lt;/strong&gt; 为例，看 TDD 循环怎么跑。&lt;/p&gt;
&lt;h3 id=&quot;red-xie-failing-test&quot;&gt;Red：写 failing test&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 合并两个相邻同值砖块&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;test&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;merge two adjacent same-value tiles&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, ()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  const&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; slideAndMerge&lt;/span&gt;&lt;span&gt;([&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; null&lt;/span&gt;&lt;span&gt;])&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  expect&lt;/span&gt;&lt;span&gt;(result)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;toEqual&lt;/span&gt;&lt;span&gt;([&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; null&lt;/span&gt;&lt;span&gt;])&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 合并只发生一次，不能链式合并&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;test&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;merged tile does not merge again in same move&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, ()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  const&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; slideAndMerge&lt;/span&gt;&lt;span&gt;([&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span&gt;])&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  expect&lt;/span&gt;&lt;span&gt;(result)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;toEqual&lt;/span&gt;&lt;span&gt;([&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; null&lt;/span&gt;&lt;span&gt;])&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; // 不是 [8, null, null, null]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 合并计分正确&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;test&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;merge score equals merged value&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, ()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; score&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; slideAndMergeWithScore&lt;/span&gt;&lt;span&gt;([&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; null&lt;/span&gt;&lt;span&gt;])&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  expect&lt;/span&gt;&lt;span&gt;(score)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;toBe&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;8&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;跑测试 → &lt;strong&gt;Red&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&quot;green-xie-zui-xiao-shi-xian&quot;&gt;Green：写最小实现&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; slideAndMerge&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;row&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  const&lt;/span&gt;&lt;span&gt; tiles&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; row&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;filter&lt;/span&gt;&lt;span&gt;(v&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; v&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; !== null&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  const&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; []&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  let&lt;/span&gt;&lt;span&gt; score&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  let&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  while&lt;/span&gt;&lt;span&gt; (i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span&gt; tiles&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;length)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span&gt; tiles&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;length&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span&gt; tiles[i]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ===&lt;/span&gt;&lt;span&gt; tiles[i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span&gt;])&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      const&lt;/span&gt;&lt;span&gt; merged&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; tiles[i]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      result&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;push&lt;/span&gt;&lt;span&gt;(merged)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      score&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +=&lt;/span&gt;&lt;span&gt; merged&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; else&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      result&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;push&lt;/span&gt;&lt;span&gt;(tiles[i])&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  while&lt;/span&gt;&lt;span&gt; (result&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;length&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 4&lt;/span&gt;&lt;span&gt;) result&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;push&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;null&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  return&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;跑测试 → &lt;strong&gt;Green&lt;/strong&gt;。最小实现，不过度设计&lt;/p&gt;
&lt;h3 id=&quot;code-review-zi-jian&quot;&gt;Code Review：自检&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;## Standards&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- [x] 变量命名清晰（tiles, merged, score）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- [ ] 4 是 magic number，应提取为 SIZE 常量&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;## Spec&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- [x] 合并两个相邻同值砖块&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- [x] 一次滑动中每砖块只合并一次&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- [x] 计分正确&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Commit。下一个 ticket。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;zui-zhong-jiao-fu-wan-zheng-2048-dai-ma&quot;&gt;最终交付：完整 2048 代码&lt;/h2&gt;
&lt;p&gt;按 ticket 顺序串起来，大约 280 行单文件 HTML：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;html&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;!DOCTYPE&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; html&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;html&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; lang&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;zh&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;head&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  &amp;lt;meta&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; charset&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;UTF-8&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  &amp;lt;meta&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;viewport&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;width=device-width, initial-scale=1.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  &amp;lt;title&amp;gt;&lt;/span&gt;&lt;span&gt;2048&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  &amp;lt;style&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    *&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; box-sizing&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; border-box;&lt;/span&gt;&lt;span&gt; margin&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; padding&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    body&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      font-family&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Clear Sans&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Helvetica Neue&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; Arial&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; sans-serif;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      background&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: #&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;faf8ef&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      display&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; flex;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      justify-content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; center;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      align-items&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; center;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      min-height&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 100&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;vh;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    .&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;container&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; width&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 500&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    header&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; display&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; flex;&lt;/span&gt;&lt;span&gt; justify-content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; space-between;&lt;/span&gt;&lt;span&gt; align-items&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; center;&lt;/span&gt;&lt;span&gt; margin-bottom&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 20&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    h1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; font-size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 72&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px;&lt;/span&gt;&lt;span&gt; font-weight&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; bold;&lt;/span&gt;&lt;span&gt; color&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: #&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;776e65&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    .&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;scores&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; display&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; flex;&lt;/span&gt;&lt;span&gt; gap&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    .&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;score-box&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; background&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: #&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;bbada0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; color&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: #&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;eee4da&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; padding&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 8&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 20&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px;&lt;/span&gt;&lt;span&gt; border-radius&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 6&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px;&lt;/span&gt;&lt;span&gt; text-align&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; center;&lt;/span&gt;&lt;span&gt; min-width&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 80&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    .&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;score-box&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; label&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; font-size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 13&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px;&lt;/span&gt;&lt;span&gt; text-transform&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; uppercase;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    .&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;score-box&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; span&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; display&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; block;&lt;/span&gt;&lt;span&gt; font-size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 24&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px;&lt;/span&gt;&lt;span&gt; font-weight&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; bold;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    button&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; background&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: #&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;8f7a66&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; color&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: #&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;f9f6f2&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; border&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; none;&lt;/span&gt;&lt;span&gt; border-radius&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 6&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px;&lt;/span&gt;&lt;span&gt; padding&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 20&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px;&lt;/span&gt;&lt;span&gt; font-size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 16&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px;&lt;/span&gt;&lt;span&gt; cursor&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; pointer;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    .&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;board&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; background&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: #&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;bbada0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; border-radius&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 6&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px;&lt;/span&gt;&lt;span&gt; padding&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 12&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px;&lt;/span&gt;&lt;span&gt; display&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; grid;&lt;/span&gt;&lt;span&gt; grid-template-columns&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; repeat&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;fr&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; gap&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 12&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px;&lt;/span&gt;&lt;span&gt; position&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; relative;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    .&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;cell&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; aspect-ratio&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; background&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; rgba&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;238&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 228&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 218&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0.35&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; border-radius&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    .&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;tiles&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; position&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; absolute;&lt;/span&gt;&lt;span&gt; top&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 12&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px;&lt;/span&gt;&lt;span&gt; left&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 12&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px;&lt;/span&gt;&lt;span&gt; right&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 12&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px;&lt;/span&gt;&lt;span&gt; bottom&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 12&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px;&lt;/span&gt;&lt;span&gt; display&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; grid;&lt;/span&gt;&lt;span&gt; grid-template-columns&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; repeat&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;fr&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; gap&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 12&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px;&lt;/span&gt;&lt;span&gt; pointer-events&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; none;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    .&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;tile&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; aspect-ratio&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; display&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; flex;&lt;/span&gt;&lt;span&gt; align-items&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; center;&lt;/span&gt;&lt;span&gt; justify-content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; center;&lt;/span&gt;&lt;span&gt; font-size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 48&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px;&lt;/span&gt;&lt;span&gt; font-weight&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; bold;&lt;/span&gt;&lt;span&gt; border-radius&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    .&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;overlay&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; position&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; absolute;&lt;/span&gt;&lt;span&gt; inset&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; background&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; rgba&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;238&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 228&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 218&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0.73&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; border-radius&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 6&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px;&lt;/span&gt;&lt;span&gt; display&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; flex;&lt;/span&gt;&lt;span&gt; flex-direction&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; column;&lt;/span&gt;&lt;span&gt; align-items&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; center;&lt;/span&gt;&lt;span&gt; justify-content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; center;&lt;/span&gt;&lt;span&gt; gap&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 16&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px;&lt;/span&gt;&lt;span&gt; display&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; none;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    .&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;overlay&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;show&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; display&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; flex;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    .&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;overlay&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; h2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; font-size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 48&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px;&lt;/span&gt;&lt;span&gt; color&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: #&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;776e65&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  &amp;lt;/style&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;body&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  &amp;lt;div&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;container&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    &amp;lt;header&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      &amp;lt;h1&amp;gt;&lt;/span&gt;&lt;span&gt;2048&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      &amp;lt;div&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;scores&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        &amp;lt;div&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;score-box&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&amp;lt;label&amp;gt;&lt;/span&gt;&lt;span&gt;分数&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/label&amp;gt;&amp;lt;span&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;score&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        &amp;lt;div&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;score-box&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&amp;lt;label&amp;gt;&lt;/span&gt;&lt;span&gt;最高&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/label&amp;gt;&amp;lt;span&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;best&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      &amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    &amp;lt;/header&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    &amp;lt;button&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;new-game&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;新游戏&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    &amp;lt;div&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;board&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;board&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;      &amp;lt;!-- 背景格子 --&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      &amp;lt;div&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;cell&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;cell&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;cell&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;cell&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      &amp;lt;div&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;cell&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;cell&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;cell&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;cell&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      &amp;lt;div&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;cell&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;cell&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;cell&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;cell&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      &amp;lt;div&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;cell&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;cell&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;cell&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;cell&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;      &amp;lt;!-- 砖块层 --&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      &amp;lt;div&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;tiles&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;tiles&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;      &amp;lt;!-- Game Over 覆盖层 --&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      &amp;lt;div&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;overlay&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;overlay&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        &amp;lt;h2&amp;gt;&lt;/span&gt;&lt;span&gt;游戏结束&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        &amp;lt;button&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;retry&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;再来一局&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      &amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    &amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  &amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  &amp;lt;script&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    const&lt;/span&gt;&lt;span&gt; SIZE&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    const&lt;/span&gt;&lt;span&gt; COLORS&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;      2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;#eee4da&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;#ede0c8&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 8&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;#f2b179&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 16&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;#f59563&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;      32&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;#f67c5f&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 64&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;#f65e3b&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 128&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;#edcf72&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 256&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;#edcc61&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;      512&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;#edc850&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1024&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;#edc53f&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2048&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;#edc22e&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    let&lt;/span&gt;&lt;span&gt; grid&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; []&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; score&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    function&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; init&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      grid&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; Array&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;from&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; length&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; SIZE&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }, ()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Array&lt;/span&gt;&lt;span&gt;(SIZE)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;fill&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;null&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      score&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;      spawnTile&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; spawnTile&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;      updateScore&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; render&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      document&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getElementById&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;overlay&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;classList&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;remove&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;show&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    function&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; spawnTile&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      const&lt;/span&gt;&lt;span&gt; empty&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; []&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt;&lt;span&gt; r&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; r&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span&gt; SIZE&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; r&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span&gt; SIZE&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;          if&lt;/span&gt;&lt;span&gt; (grid[r][c]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; === null&lt;/span&gt;&lt;span&gt;) empty&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;push&lt;/span&gt;&lt;span&gt;([r&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; c])&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;!&lt;/span&gt;&lt;span&gt;empty&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;length)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      const&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; [&lt;/span&gt;&lt;span&gt;r&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; empty[Math&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;floor&lt;/span&gt;&lt;span&gt;(Math&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;random&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; *&lt;/span&gt;&lt;span&gt; empty&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;length)]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      grid[r][c]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; Math&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;random&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0.9&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ?&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    function&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; slideRowLeft&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;row&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      const&lt;/span&gt;&lt;span&gt; tiles&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; row&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;filter&lt;/span&gt;&lt;span&gt;(v&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; v&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; !== null&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      const&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; []&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; gained&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      let&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      while&lt;/span&gt;&lt;span&gt; (i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span&gt; tiles&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;length)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span&gt; (i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span&gt; tiles&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;length&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span&gt; tiles[i]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ===&lt;/span&gt;&lt;span&gt; tiles[i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span&gt;])&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;          const&lt;/span&gt;&lt;span&gt; merged&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; tiles[i]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          result&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;push&lt;/span&gt;&lt;span&gt;(merged)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          gained&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +=&lt;/span&gt;&lt;span&gt; merged&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; else&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;push&lt;/span&gt;&lt;span&gt;(tiles[i])&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      while&lt;/span&gt;&lt;span&gt; (result&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;length&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span&gt; SIZE) result&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;push&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;null&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      return&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; row&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; score&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; gained&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    function&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; rotate&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;g&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; times&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      let&lt;/span&gt;&lt;span&gt; out&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; g&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;map&lt;/span&gt;&lt;span&gt;(r&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;...&lt;/span&gt;&lt;span&gt;r])&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt;&lt;span&gt; t&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; t&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span&gt; times&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; %&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; t&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        out&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; out[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;map&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; out&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;map&lt;/span&gt;&lt;span&gt;(row&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; row[SIZE&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; -&lt;/span&gt;&lt;span&gt; i]))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      return&lt;/span&gt;&lt;span&gt; out&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    function&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; move&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;dir&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      const&lt;/span&gt;&lt;span&gt; rot&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; left&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; up&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; right&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; down&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;span&gt;[dir]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      let&lt;/span&gt;&lt;span&gt; g&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; rotate&lt;/span&gt;&lt;span&gt;(grid&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; rot)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; moved&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = false&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; gained&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      const&lt;/span&gt;&lt;span&gt; newGrid&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; g&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;map&lt;/span&gt;&lt;span&gt;(row&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        const&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; row&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; newRow&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; score&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; s&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; slideRowLeft&lt;/span&gt;&lt;span&gt;(row)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        gained&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +=&lt;/span&gt;&lt;span&gt; s&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span&gt; (JSON&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;stringify&lt;/span&gt;&lt;span&gt;(row)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; !==&lt;/span&gt;&lt;span&gt; JSON&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;stringify&lt;/span&gt;&lt;span&gt;(newRow)) moved&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = true;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return&lt;/span&gt;&lt;span&gt; newRow&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      }&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      grid&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; rotate&lt;/span&gt;&lt;span&gt;(newGrid&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; -&lt;/span&gt;&lt;span&gt; rot)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;!&lt;/span&gt;&lt;span&gt;moved)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return false;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      score&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +=&lt;/span&gt;&lt;span&gt; gained&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; updateScore&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; spawnTile&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; render&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;isGameOver&lt;/span&gt;&lt;span&gt;()) document&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getElementById&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;overlay&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;classList&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;add&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;show&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      return true;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    function&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; isGameOver&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt;&lt;span&gt; r&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; r&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span&gt; SIZE&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; r&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span&gt; SIZE&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;          if&lt;/span&gt;&lt;span&gt; (grid[r][c]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; === null&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return false;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;          if&lt;/span&gt;&lt;span&gt; (c&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span&gt; SIZE&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span&gt; grid[r][c]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ===&lt;/span&gt;&lt;span&gt; grid[r][c&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span&gt;])&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return false;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;          if&lt;/span&gt;&lt;span&gt; (r&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span&gt; SIZE&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span&gt; grid[r][c]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ===&lt;/span&gt;&lt;span&gt; grid[r&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span&gt;][c])&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return false;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      return true;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    function&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; updateScore&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      document&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getElementById&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;score&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;textContent&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; score&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      const&lt;/span&gt;&lt;span&gt; best&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; parseInt&lt;/span&gt;&lt;span&gt;(localStorage&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getItem&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;2048-best&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      if&lt;/span&gt;&lt;span&gt; (score&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span&gt; best)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; localStorage&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;setItem&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;2048-best&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span&gt; score)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; document&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getElementById&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;best&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;textContent&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; score&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    function&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; render&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      const&lt;/span&gt;&lt;span&gt; tilesEl&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; document&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getElementById&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;tiles&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      tilesEl&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;innerHTML&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt;&lt;span&gt; r&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; r&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span&gt; SIZE&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; r&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span&gt; SIZE&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;          const&lt;/span&gt;&lt;span&gt; val&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; grid[r][c]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;          if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;!&lt;/span&gt;&lt;span&gt;val)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; continue;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;          const&lt;/span&gt;&lt;span&gt; tile&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; document&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;createElement&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          tile&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;className&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;tile&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          tile&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;textContent&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; val&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          tile&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;background&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; COLORS[val]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;#3c3a32&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          tile&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;color&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; val&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ?&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;#f9f6f2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;#776e65&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;          if&lt;/span&gt;&lt;span&gt; (val&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 100&lt;/span&gt;&lt;span&gt;) tile&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;fontSize&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;36px&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;          if&lt;/span&gt;&lt;span&gt; (val&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1000&lt;/span&gt;&lt;span&gt;) tile&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;fontSize&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;28px&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          tilesEl&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;appendChild&lt;/span&gt;&lt;span&gt;(tile)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      document&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getElementById&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;best&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;textContent&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; localStorage&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getItem&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;2048-best&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    document&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;addEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;keydown&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span&gt; e&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      const&lt;/span&gt;&lt;span&gt; map&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; ArrowLeft&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;left&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; ArrowRight&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;right&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; ArrowUp&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;up&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; ArrowDown&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;down&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39; }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      if&lt;/span&gt;&lt;span&gt; (map[e&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;key])&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; e&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;preventDefault&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; move&lt;/span&gt;&lt;span&gt;(map[e&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;key])&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    document&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getElementById&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;new-game&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;onclick&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; init&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    document&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getElementById&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;retry&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;onclick&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; init&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    init&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  &amp;lt;/script&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;dui-bi-skill-liu-cheng-dai-lai-liao-shen-me&quot;&gt;对比：Skill 流程带来了什么&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;维度&lt;/th&gt;&lt;th&gt;直接对话&lt;/th&gt;&lt;th&gt;Skill 流程&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;交付形式&lt;/td&gt;&lt;td&gt;AI 自己决定&lt;/td&gt;&lt;td&gt;提前对齐，单文件&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;配色方案&lt;/td&gt;&lt;td&gt;随机&lt;/td&gt;&lt;td&gt;查表确认，经典配色&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;分数持久化&lt;/td&gt;&lt;td&gt;可能漏&lt;/td&gt;&lt;td&gt;写入 spec，ticket 06 验收&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Game Over&lt;/td&gt;&lt;td&gt;AI 判断&lt;/td&gt;&lt;td&gt;spec 明确，覆盖层方案&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;边界情况&lt;/td&gt;&lt;td&gt;靠 AI 自检&lt;/td&gt;&lt;td&gt;合并只一次等 case 写入测试&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;交付质量&lt;/td&gt;&lt;td&gt;看 AI 当下状态&lt;/td&gt;&lt;td&gt;每个 ticket 有 code review&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;最后那个 280 行代码，用 Skill 流程做完，每个 commit 都是可验证的小步。Review 的时候不是看一段大代码对不对，而是看一个 ticket 的实现是否忠实于 spec。质量门控前置了，而不是留给上线后。&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Agent 是什么？—— 一个公式、一个类比、一个能跑的 Demo</title>
        <published>2026-08-06T00:00:00+00:00</published>
        <updated>2026-08-06T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/ai-agent-series-01-what-is-agent/"/>
        <id>https://scp.net.cn/blog/ai-agent-series-01-what-is-agent/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/ai-agent-series-01-what-is-agent/">&lt;blockquote&gt;
&lt;p&gt;本文是 &lt;strong&gt;AI Agent 系列教程&lt;/strong&gt; 第 1 篇。基于李博杰《深入理解 AI Agent》改编，用费曼学习法（概念 → 类比 → 动手）带你从零理解 Agent。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;你用过 ChatGPT 写邮件，也用过 Cursor 写代码。但你想过没有：&lt;strong&gt;从“一问一答的聊天“到“Agent 自己读文档、写代码、跑测试、提 PR“，中间到底多了什么？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;多出来的部分，就是今天要讲的核心。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;part-1-gai-nian-agent-dao-di-shi-shen-me&quot;&gt;Part 1：概念——Agent 到底是什么？&lt;/h2&gt;
&lt;h3 id=&quot;yi-ge-gong-shi&quot;&gt;一个公式&lt;/h3&gt;
&lt;p&gt;整个 AI Agent 领域，可以用一个公式概括：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Agent = LLM + 上下文 + 工具&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;翻译成人话：&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;组件&lt;/th&gt;&lt;th&gt;角色&lt;/th&gt;&lt;th&gt;一句话&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;LLM&lt;/strong&gt;（大语言模型）&lt;/td&gt;&lt;td&gt;🧠 大脑&lt;/td&gt;&lt;td&gt;负责思考和决策——“下一步该干什么”&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;上下文&lt;/strong&gt;（Context）&lt;/td&gt;&lt;td&gt;👀 眼睛&lt;/td&gt;&lt;td&gt;让 Agent 看到世界——系统指令、对话历史、环境状态、检索到的知识&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;工具&lt;/strong&gt;（Tools）&lt;/td&gt;&lt;td&gt;👐 双手&lt;/td&gt;&lt;td&gt;让 Agent 能改变世界——搜索、读写文件、执行代码、调用 API&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;分解来看：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;LLM 是决策引擎。&lt;/strong&gt; 但它不是魔法——把它想象成一个纯函数：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;决策 = LLM（上下文）&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;输入什么上下文，就产出什么决策。上下文的质量直接决定决策的质量。GPT-4 和一个入门实习生之间的差距，可能只是你给实习生的那份项目文档够不够好。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;上下文是“Agent 看到的世界“。&lt;/strong&gt; 每次调用 LLM，你塞进上下文的东西包含五部分：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;系统提示&lt;/strong&gt;（System Prompt）——给 Agent 的“员工手册“，定义身份、权限、行为规则&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;工具定义&lt;/strong&gt;——告诉它有哪些工具可用，每个工具叫什么、干什么、需要什么参数&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;用户消息&lt;/strong&gt;——你的输入&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;助手消息&lt;/strong&gt;——Agent 之前的回复（包括推理过程、文本输出、工具调用请求）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;工具结果&lt;/strong&gt;——工具执行后返回的数据&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;前两项是&lt;strong&gt;静态前缀&lt;/strong&gt;（每轮都一样），后三项是&lt;strong&gt;动态轨迹&lt;/strong&gt;（每轮都在增长）。Agent 的每一次决策，都是基于这五样东西的总和。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;工具是“Agent 能改变什么“。&lt;/strong&gt; 没有工具，GPT-4 再聪明也只能聊天。有了工具，它能搜索网页、读写文件、执行代码、发送邮件——从一个“顾问“变成了一个“执行者“。&lt;/p&gt;
&lt;h3 id=&quot;yi-ge-zhi-xing-xun-huan-react&quot;&gt;一个执行循环：ReAct&lt;/h3&gt;
&lt;p&gt;Agent 不是一次性出答案，而是在一个循环中工作：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;用户输入&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  → LLM 思考：我需要搜点什么？&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  → LLM 调用搜索工具&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  → 工具返回结果&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  → LLM 思考：搜到的信息够不够？不够就再搜/换关键词&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  → 够了，输出最终答案&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个循环叫 &lt;strong&gt;ReAct&lt;/strong&gt;（Reasoning + Acting，推理+行动），是几乎所有现代 Agent 的底层逻辑：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;while 任务没完成：&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    把&amp;quot;系统提示 + 工具列表 + 完整对话历史&amp;quot;发给 LLM&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if LLM 返回了工具调用:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        执行工具，把结果追加到对话历史&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    else:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        说明 LLM 认为任务已完成，输出最终答案，退出循环&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;dan-shi-luo-de-agent-bu-gou-ke-kao&quot;&gt;但是……裸的 Agent 不够可靠&lt;/h3&gt;
&lt;p&gt;你很可能听过 Cursor 或 Claude Code 的“翻车“故事：Agent 信誓旦旦说“改完了“，其实啥也没改对；或者同一个文件反复改 8 遍，陷入死循环。&lt;/p&gt;
&lt;p&gt;所以生产级 Agent 不能在裸公式上工作。真实世界的 Agent 架构是这个的扩展版：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Agent = LLM + 上下文 + 工具 + 约束 + 验证 + 纠偏&lt;/strong&gt;
​    ​    ​    ​= &lt;strong&gt;模型 + Harness（缰绳）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Harness Engineering&lt;/strong&gt;（缰绳工程）是李博杰这本书最核心的主张：当模型能力趋同时，真正拉开差距的不是谁的模型更聪明，而是谁给模型搭的“缰绳系统“更好——约束、验证、反馈、纠偏、熵管理。你可以把它理解为给一匹千里马配上的鞍具和缰绳：马再能跑，没有缰绳也是乱跑。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;part-2-lei-bi-ba-agent-xiang-xiang-cheng-yi-ge-shi-xi-sheng&quot;&gt;Part 2：类比——把 Agent 想象成一个实习生&lt;/h2&gt;
&lt;p&gt;为了帮你建立直观理解，我们用一个类比：&lt;strong&gt;Agent 就是一个刚入职的实习生。&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;实习生的要素&lt;/th&gt;&lt;th&gt;Agent 的对应&lt;/th&gt;&lt;th&gt;含义&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;智力和知识储备&lt;/td&gt;&lt;td&gt;&lt;strong&gt;LLM&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;聪明，但缺乏对“当前项目“的了解&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;你给的项目文档、代码库地图、任务说明&lt;/td&gt;&lt;td&gt;&lt;strong&gt;上下文&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;告诉他在哪、在干什么、要注意什么&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;电脑、IDE、CI 流水线、提交权限&lt;/td&gt;&lt;td&gt;&lt;strong&gt;工具&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;让他能动手干活，而不是只能口头建议&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;公司的 Code Review、lint 规则、发布 checklist、on-call 流程&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Harness&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;防止他搞出大乱子，给错误兜底&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;现在想想：一个实习生表现好不好，主要取决于什么？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;当然取决于他聪不聪明（模型能力）。&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;但更取决于：&lt;strong&gt;你给的文档够不够清楚（上下文质量）、权限给得对不对（工具设计）、流程有没有兜底（Harness）。&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这就是为什么“Prompt Engineering“只是起点。当你只优化提示词时，你在优化这个实习生的“任务说明书“。但真正让他稳定产出的，是&lt;strong&gt;文档体系 + 工具链 + 代码审查 + CI + 监控&lt;/strong&gt;这套完整系统——也就是 Harness。&lt;/p&gt;
&lt;p&gt;再看一个具体场景。Claude Code 在帮你改代码时，它的 Harness 至少包含：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;权限分级&lt;/strong&gt;：读文件自动放行，写文件需要确认，执行危险命令二次确认&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;熔断机制&lt;/strong&gt;：连续出错就停下来，不让你付无上限的 API 费&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;上下文压缩&lt;/strong&gt;：对话历史太长时自动摘要，避免 token 爆表&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;状态栏&lt;/strong&gt;：实时告诉你它在干什么、第几轮了、花了多少钱&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些都不是模型自带的能力——它们是工程师在模型外面搭的基础设施。&lt;strong&gt;搭得越好，Agent 越稳。&lt;/strong&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;part-3-dong-shou-50-xing-python-da-yi-ge-neng-sou-suo-de-agent&quot;&gt;Part 3：动手——50 行 Python，搭一个能搜索的 Agent&lt;/h2&gt;
&lt;p&gt;概念和类比讲完了。现在我们来&lt;strong&gt;真的写一个&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&quot;wo-men-yao-zuo-shen-me&quot;&gt;我们要做什么&lt;/h3&gt;
&lt;p&gt;一个极简 Agent：能用搜索引擎查信息，然后根据搜索结果回答问题。用 OpenAI API，代码在 50 行以内。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;逻辑很简单：&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;用户问一个问题&lt;/li&gt;
&lt;li&gt;Agent 判断“这个我需要搜索吗？“&lt;/li&gt;
&lt;li&gt;如果需要，调用搜索工具 → 拿到结果 → 再想一下 → 输出答案&lt;/li&gt;
&lt;li&gt;如果不需要，直接回答&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;wan-zheng-dai-ma&quot;&gt;完整代码&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span&gt; json&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; requests&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;from&lt;/span&gt;&lt;span&gt; openai&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; import&lt;/span&gt;&lt;span&gt; OpenAI&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;client&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; OpenAI&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  # 默认读 OPENAI_API_KEY 环境变量&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# ── 1. 定义工具：Agent 能干什么 ──&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; search_web&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;query&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;模拟搜索，实际可用 DuckDuckGo / SerpAPI 替换&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    url&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;https://html.duckduckgo.com/html/?q=&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;query&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    resp&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; requests&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; headers&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;User-Agent&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;my-agent/1.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    # 这里简化处理，真实场景需要做 HTML 解析&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; resp&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;text&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;2000&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;TOOLS&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; [{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;search_web&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;description&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;搜索互联网获取实时信息。当需要最新数据或不确定答案时使用。&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;parameters&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;object&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;properties&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;description&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;搜索关键词&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;required&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: [&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# ── 2. 工具执行映射 ──&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;TOOL_MAP&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;search_web&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; search_web&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# ── 3. Agent 主循环 ──&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; agent_loop&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;user_question&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; max_rounds&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 5&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    messages&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; [{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;system&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;你是一个有帮助的助手。遇到不确定的信息时，&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;主动使用 search_web 工具搜索，而不是猜测。&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }, {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; user_question&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    for&lt;/span&gt;&lt;span&gt; _&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; range&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;max_rounds&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        resp&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; client&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;chat&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;completions&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;create&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            model&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;gpt-4o-mini&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            messages&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt;messages&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            tools&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt;TOOLS&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            tool_choice&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;auto&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  # 让模型自己决定要不要用工具&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        msg&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; resp&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;choices&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;].&lt;/span&gt;&lt;span&gt;message&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        # 情况 A：模型认为可以回答，不调工具&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if not&lt;/span&gt;&lt;span&gt; msg&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;tool_calls&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            return&lt;/span&gt;&lt;span&gt; msg&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;content&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        # 情况 B：模型要调工具&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        messages&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;msg&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  # 把模型的工具调用请求加入历史&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        for&lt;/span&gt;&lt;span&gt; tc&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; in&lt;/span&gt;&lt;span&gt; msg&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;tool_calls&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            fn_name&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; tc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            fn_args&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; json&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;loads&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;arguments&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            result&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; TOOL_MAP&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;fn_name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;](&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;**&lt;/span&gt;&lt;span&gt;fn_args&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            messages&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;tool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;tool_call_id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; tc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            })&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;            print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;  🔧 调用了 &lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;fn_name&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;fn_args&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;][:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;30&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;...) → 返回 &lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;len&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;result&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 字符&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;达到最大轮数，未能完成任务。&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# ── 4. 跑起来 ──&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;if&lt;/span&gt;&lt;span&gt; __name__&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;__main__&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    answer&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; agent_loop&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;2026 年图灵奖颁给了谁？&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;📝 最终答案：&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n{&lt;/span&gt;&lt;span&gt;answer&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;dai-ma-zhu-duan-jie-shi&quot;&gt;代码逐段解释&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;第 1 步：定义工具。&lt;/strong&gt; 工具的定义（名称、描述、参数 schema）会被塞进每次 LLM 调用的 &lt;code&gt;tools&lt;/code&gt; 参数里。模型的训练让它能读懂这些定义，知道什么时候该调哪个工具。注意 &lt;code&gt;description&lt;/code&gt; 写得越具体越好——这里强调“当需要最新数据时使用“，引导模型主动搜索而不是凭记忆胡猜。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第 2 步：工具执行映射。&lt;/strong&gt; &lt;code&gt;TOOL_MAP&lt;/code&gt; 是把工具名称映射到实际 Python 函数的字典。Agent 框架（这 50 行代码就是最简单的“框架“）收到模型的工具调用请求后，用这个字典找到对应用函数并执行。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第 3 步：Agent 主循环。&lt;/strong&gt; 这是整个 Agent 的心脏——&lt;code&gt;agent_loop&lt;/code&gt; 函数。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;先把系统提示和用户问题放进消息列表&lt;/li&gt;
&lt;li&gt;然后进入循环：把消息列表发给 LLM → 看 LLM 返回什么&lt;/li&gt;
&lt;li&gt;如果 LLM 返回的是文本（不是工具调用），说明它认为可以回答了，直接返回&lt;/li&gt;
&lt;li&gt;如果 LLM 返回的是工具调用，执行工具，把结果追加进消息列表，再循环一次&lt;/li&gt;
&lt;li&gt;&lt;code&gt;max_rounds=5&lt;/code&gt; 是熔断器——防止无限循环烧钱&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;第 4 步：运行。&lt;/strong&gt; 一条 &lt;code&gt;agent_loop(question)&lt;/code&gt; 就启动了整个 Agent。&lt;/p&gt;
&lt;h3 id=&quot;pao-yi-xia-kan-kan&quot;&gt;跑一下看看&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; export OPENAI_API_KEY=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;sk-...&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; pip install openai requests&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; python agent.py&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  🔧&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 调用了 search_web&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;2026&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 图灵奖...&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; → 返回&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2000&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 字符&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;📝&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 最终答案：&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;根据搜索结果，2026&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 年图灵奖尚未公布。2025 年的图灵奖颁给了 Andrew Barto&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;和&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; Richard Sutton，以表彰他们在强化学习领域的贡献。图灵奖通常在每年 4-5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;月公布，如果你想了解&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2026&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 年的结果，建议届时关注 ACM 的官方公告。&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Agent 判断这个问题需要最新信息 → 调用搜索 → 拿到结果 → 基于结果给出准确答案。它没有凭训练数据“编造“一个 2026 年图灵奖得主。&lt;/p&gt;
&lt;h3 id=&quot;cong-50-xing-dao-sheng-chan-ji&quot;&gt;从 50 行到生产级&lt;/h3&gt;
&lt;p&gt;这个 Demo 只有 50 行，但你已经在跑一个&lt;strong&gt;真正的 Agent 循环&lt;/strong&gt;了。把它和 Claude Code / Cursor 比，差距在哪？&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;维度&lt;/th&gt;&lt;th&gt;我们的 50 行&lt;/th&gt;&lt;th&gt;生产级 Agent&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;工具数量&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;1 个（搜索）&lt;/td&gt;&lt;td&gt;几十个（读文件、写文件、跑测试、Git 操作……）&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;上下文管理&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;无限追加，迟早爆窗口&lt;/td&gt;&lt;td&gt;KV Cache 优化、分层压缩、子 Agent 隔离&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;安全性&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;零&lt;/td&gt;&lt;td&gt;权限分级、熔断、输入清洗、输出校验&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;可观测性&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;一个 print&lt;/td&gt;&lt;td&gt;完整的 trace、指标、日志&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;纠偏能力&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;无&lt;/td&gt;&lt;td&gt;出错自动重试、失败后回滚、死循环检测&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;这六样东西，就是我们说的 &lt;strong&gt;Harness&lt;/strong&gt;。在后续系列中，我们会逐一拆解这些 Harness 的每个组件。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;zong-jie&quot;&gt;总结&lt;/h2&gt;
&lt;p&gt;今天我们讲了三个东西：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Agent 不是魔法公式&lt;/strong&gt;——它就是一个循环：「LLM 做决策 → 调用工具 → 拿到结果 → 再做决策」。核心公式：&lt;code&gt;Agent = LLM + 上下文 + 工具&lt;/code&gt;，生产级要加上 Harness（约束 + 验证 + 纠偏）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;把 Agent 想成实习生&lt;/strong&gt;——他的表现不只取决于智力，更取决于你给的文档、权限、流程。这就是 Harness Engineering 的核心洞察。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;50 行代码就能跑一个 Agent&lt;/strong&gt;——我们真的写了一个。它能搜索、能思考、能回答。从这 50 行出发，往上加工具、加安全、加可观测性，就是生产级 Agent 的工程之旅。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;xia-yi-qi-yu-gao&quot;&gt;下一期预告&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Agent 的双手：工具调用与 MCP 协议&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;现在 Agent 只有一个“手“（搜索）。我们会给它装上更多：文件操作、代码执行、API 调用。同时介绍 MCP（Model Context Protocol）——让工具像 USB 一样即插即用。配套实战：给 Agent 装上“天气查询 + 便签记录“两个工具。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;em&gt;本文基于李博杰《&lt;a rel=&quot;external&quot; href=&quot;https://bojieli.github.io/ai-agent-book/&quot;&gt;深入理解 AI Agent&lt;/a&gt;》（Apache 2.0 协议）第 1 章内容改编，用费曼学习法重构为“概念 → 类比 → 动手“三段式教程。&lt;/em&gt;&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Agent 的双手：工具调用、MCP 协议与一个双工具 Agent</title>
        <published>2026-08-06T00:00:00+00:00</published>
        <updated>2026-08-06T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/ai-agent-series-02-tools-mcp/"/>
        <id>https://scp.net.cn/blog/ai-agent-series-02-tools-mcp/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/ai-agent-series-02-tools-mcp/">&lt;blockquote&gt;
&lt;p&gt;本文是 &lt;strong&gt;AI Agent 系列教程&lt;/strong&gt; 第 2 篇。基于李博杰《深入理解 AI Agent》第 4-5 章改编。上一篇我们搭了一个 50 行的搜索 Agent——它只有一个“手“。今天给它装上更多。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;part-1-gai-nian-gong-ju-dao-di-shi-shen-me&quot;&gt;Part 1：概念——工具到底是什么？&lt;/h2&gt;
&lt;h3 id=&quot;hui-gu-agent-xun-huan-zhong-de-gong-ju&quot;&gt;回顾：Agent 循环中的工具&lt;/h3&gt;
&lt;p&gt;还记得上一篇文章的 Agent 循环吗？&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;用户输入 → LLM 思考 → 需要工具？→ 调用工具 → 结果喂回 LLM → 再思考 → 输出答案&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;工具是这个循环里唯一&lt;strong&gt;能改变外部世界&lt;/strong&gt;的环节。LLM 本身只能“想“，但工具能让它“做“。&lt;/p&gt;
&lt;h3 id=&quot;gong-ju-de-wu-chong-fen-lei&quot;&gt;工具的五种分类&lt;/h3&gt;
&lt;p&gt;按&lt;strong&gt;调用方向&lt;/strong&gt;和&lt;strong&gt;作用对象&lt;/strong&gt;，所有工具分成五类：&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;类型&lt;/th&gt;&lt;th&gt;谁发起&lt;/th&gt;&lt;th&gt;干什么&lt;/th&gt;&lt;th&gt;例子&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;感知工具&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Agent 主动&lt;/td&gt;&lt;td&gt;获取信息&lt;/td&gt;&lt;td&gt;搜索引擎、读文件、查数据库、API 查询&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;执行工具&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Agent 主动&lt;/td&gt;&lt;td&gt;改变世界&lt;/td&gt;&lt;td&gt;写文件、执行代码、发送请求、操作浏览器&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;协作工具&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Agent 主动&lt;/td&gt;&lt;td&gt;调度其他 Agent/人&lt;/td&gt;&lt;td&gt;派生子 Agent、请求人类确认&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;事件触发器&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;外部事件&lt;/td&gt;&lt;td&gt;唤醒 Agent&lt;/td&gt;&lt;td&gt;定时器、新邮件到达、Webhook 回调&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;用户通信&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Agent 主动&lt;/td&gt;&lt;td&gt;主动联系用户&lt;/td&gt;&lt;td&gt;发消息、打电话、推送通知&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;前两类是 Agent 的“眼睛和手“，第三类是“叫帮手“，后两类让 Agent 从“一问一答“变成“持续在线“。&lt;/p&gt;
&lt;h3 id=&quot;gong-ju-she-ji-de-di-yi-yuan-ze&quot;&gt;工具设计的第一原则&lt;/h3&gt;
&lt;p&gt;李博杰在书里给工具设计定了一条核心原则，我翻译成大白话：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;通用工具胜过专用工具，除非有明确的安全、权限或性能理由。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;为什么？因为 LLM 的代码生成能力很强。你给它一个 &lt;code&gt;code_interpreter&lt;/code&gt;（能跑 Python 的沙箱），它自己就能用 sympy 做数学、用 pandas 分析数据、用 matplotlib 画图——不需要你为每个场景写一个专用工具。专用工具的维护负担会随需求线性增长，通用工具用 LLM 的能力替你消化复杂度。&lt;/p&gt;
&lt;p&gt;但&lt;strong&gt;安全边界是例外&lt;/strong&gt;。&lt;code&gt;grep&lt;/code&gt; 值得单独做一个工具而不能直接用 raw shell——因为 grep 是只读的，raw shell 能做任何事。&lt;/p&gt;
&lt;h3 id=&quot;gong-ju-miao-shu-zen-me-xie&quot;&gt;工具描述怎么写&lt;/h3&gt;
&lt;p&gt;工具描述是 Agent 能否正确使用工具的决定性因素。三条规则：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;告诉它“什么时候用“，而不是“能干什么“。&lt;/strong&gt; “搜索网页“不如“当需要实时信息或不确定答案时使用搜索”——后者给了模型一个决策条件。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;边界比能力更重要。&lt;/strong&gt; 明确列出“不能干什么“——比如“这个工具只搜索 2024 年之后的内容“，能大幅减少误用。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;给 1-5 个真实调用示例。&lt;/strong&gt; JSON Schema 描述的是类型，不是惯例——“时间戳用秒还是毫秒”“嵌套过滤器怎么写”，只有示例能讲清。有研究表明加入示例能把工具调用准确率从 72% 提升到 90%。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;一条工程经验：&lt;strong&gt;当 Agent 频繁选错工具时，先改工具描述，别急着换模型。&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;mcp-xie-yi-rang-gong-ju-xiang-usb-yi-yang-ji-cha-ji-yong&quot;&gt;MCP 协议：让工具像 USB 一样即插即用&lt;/h3&gt;
&lt;p&gt;2024 年底 Anthropic 发布了 &lt;strong&gt;MCP&lt;/strong&gt;（Model Context Protocol），解决一个实际问题：你给 Claude Desktop 写了一个查天气的工具，到了 Cursor 里又得重写一遍。&lt;/p&gt;
&lt;p&gt;MCP 的架构很简单——客户端-服务端：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Agent（MCP 客户端）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ├── MCP 服务器 A：天气查询、股票查询&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ├── MCP 服务器 B：数据库读写、文件管理&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  └── MCP 服务器 C：邮件发送、日历管理&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MCP 服务器&lt;/strong&gt; 暴露工具、资源（只读数据）、提示模板&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MCP 客户端&lt;/strong&gt;（Agent 框架、IDE）通过标准协议通信&lt;/li&gt;
&lt;li&gt;本地用 stdio，远程用 Streamable HTTP&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一个 MCP 服务器写好，Cursor、Claude Desktop、OpenClaw 都能用。开发一次，到处运行。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;但 MCP 有个现实的性能问题：&lt;/strong&gt; 五个 MCP 服务器可能引入 ~55,000 token 的工具定义，全塞进系统提示里会直接撑爆上下文。解决方法有两种：按需发现（Agent 先用一个轻量“工具搜索工具“找到需要的工具，再加载详细定义）和分层组织（先匹配服务器，再匹配工具，把搜索空间从“几千个工具“降到“几十个服务器 × 几十个工具“）。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;part-2-lei-bi-gei-shi-xi-sheng-pei-gong-ju-xiang&quot;&gt;Part 2：类比——给实习生配工具箱&lt;/h2&gt;
&lt;p&gt;上一篇文章我们把 Agent 比作实习生。现在想象你要给这个实习生配&lt;strong&gt;工具箱&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&quot;ni-hui-zen-me-pei&quot;&gt;你会怎么配？&lt;/h3&gt;
&lt;p&gt;你不会把公司里所有工具都堆在他桌上——钉枪、电焊机、激光测距仪全塞过去，他反而不知道该用哪个。你会：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;只放他工作确实需要的工具&lt;/strong&gt;（不要钉枪，他是写代码的）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;每个工具贴标签，写清什么时候用&lt;/strong&gt;（“螺丝刀——当需要拧螺丝时用，不要用来撬东西”）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;危险工具上锁&lt;/strong&gt;（电钻需要师傅确认才能拿）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;用完检查&lt;/strong&gt;（写了文件之后自动跑一下 lint）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这就是 Agent 的工具设计哲学：&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;好实习生管理&lt;/th&gt;&lt;th&gt;Agent 工具设计&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;只配必要的工具&lt;/td&gt;&lt;td&gt;按需发现，不把几千个工具全塞进上下文&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;贴标签写用例&lt;/td&gt;&lt;td&gt;工具描述写“决策条件“，不只是“功能列表“&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;危险工具上锁&lt;/td&gt;&lt;td&gt;权限分级、Proposer-Reviewer 机制&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;用完检查&lt;/td&gt;&lt;td&gt;write_file 之后自动跑 lint，结果反馈给 Agent&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3 id=&quot;yi-ge-fan-li-can-shu-shi-zhen&quot;&gt;一个反例：参数失真&lt;/h3&gt;
&lt;p&gt;假设你给实习生的命令行工具悄悄做了一些“自动修正“——比如自动把中文引号转成英文引号。实习生看到的文件内容里是中文引号，调工具搜这个字符串却搜不到——因为工具在背后默默改了参数。他不知道发生了什么，只会觉得“我是不是看错了“。&lt;/p&gt;
&lt;p&gt;这对应 Agent 工具设计里一条铁律：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;模型感知到的世界和工具操作的世界之间，不能存在系统性偏差。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;任何转换、规范化，要么不做，要么写在工具描述里，并作为工具结果的一部分回报给模型。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;part-3-dong-shou-gei-agent-zhuang-shang-duo-ge-gong-ju&quot;&gt;Part 3：动手——给 Agent 装上多个工具&lt;/h2&gt;
&lt;h3 id=&quot;wo-men-yao-zuo-shen-me&quot;&gt;我们要做什么&lt;/h3&gt;
&lt;p&gt;把上一篇的单工具 Agent 升级为带两个工具的版本：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;查天气&lt;/strong&gt;：给定城市名，返回天气信息（模拟 API）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;记便签&lt;/strong&gt;：Agent 可以把信息写进便签本，下次对话时能读回来&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;同时引入一个关键设计：&lt;strong&gt;工具执行后的自动验证。&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;wan-zheng-dai-ma&quot;&gt;完整代码&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span&gt; json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;from&lt;/span&gt;&lt;span&gt; datetime&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; import&lt;/span&gt;&lt;span&gt; datetime&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;from&lt;/span&gt;&lt;span&gt; openai&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; import&lt;/span&gt;&lt;span&gt; OpenAI&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;client&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; OpenAI&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# ── 1. 便签存储（模拟数据库） ──&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;NOTES&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; dict&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; dict&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {}&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  # {note_id: {title, content, created_at}}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# ── 2. 工具实现 ──&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; get_weather&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;city&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; country&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;CN&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;) -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;模拟天气查询，实际可用 OpenWeatherMap API 替换&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    # 模拟数据&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    weather_db&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;北京&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;晴，24°C，湿度 45%，北风 3 级&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;上海&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;多云，28°C，湿度 70%，东南风 2 级&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;深圳&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;雷阵雨，31°C，湿度 85%，西南风 4 级&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    result&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; weather_db&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;city&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;未找到 &lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;city&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 的天气数据&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; json&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;dumps&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;({&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;city&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; city&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;weather&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;updated&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; datetime&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;now&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;isoformat&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; add_note&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;添加便签，返回便签 ID&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    note_id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;note_&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;len&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;NOTES&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:03d&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    NOTES&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;note_id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; title&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;created_at&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; datetime&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;now&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;isoformat&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; json&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;dumps&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;({&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;ok&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;note_id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; note_id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; title&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; list_notes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;() -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;列出所有便签&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    if not&lt;/span&gt;&lt;span&gt; NOTES&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;暂无便签&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    result&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; []&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    for&lt;/span&gt;&lt;span&gt; nid&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; note&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; in&lt;/span&gt;&lt;span&gt; NOTES&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;items&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;():&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        result&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;[&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;nid&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;note&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;]&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;note&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;created_at&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;][:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;)&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;join&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;result&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 工具定义（注意 description 的写法：决策条件 + 反例）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;TOOLS&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;get_weather&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;description&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;查询指定城市的实时天气。&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;当用户询问天气、气温、是否下雨等问题时使用。&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;不要用于查询历史天气或天气预报——本工具只返回当前天气。&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            ),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;parameters&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;object&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;properties&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;city&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;description&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;城市中文名称，如&amp;#39;北京&amp;#39;、&amp;#39;上海&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;country&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;description&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;国家代码，默认 CN&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;CN&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;required&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: [&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;city&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;add_note&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;description&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;添加一条便签笔记，持久化保存。&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;当用户说&amp;#39;记下来&amp;#39;、&amp;#39;帮我保存&amp;#39;、&amp;#39;加到便签&amp;#39;时使用。&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;不要用于临时计算或不需要保存的信息。&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            ),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;parameters&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;object&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;properties&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;description&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;便签标题，简洁概括内容&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;description&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;便签正文&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;required&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: [&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;list_notes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;description&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;列出当前所有已保存的便签。&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;当用户问&amp;#39;我记过什么&amp;#39;、&amp;#39;查看便签&amp;#39;、&amp;#39;之前记了什么&amp;#39;时使用。&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;不需要参数。&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            ),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;parameters&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;object&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;properties&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {}}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;TOOL_MAP&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;get_weather&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; get_weather&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;add_note&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; add_note&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;list_notes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; list_notes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# ── 3. 自动验证钩子 ──&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; verify_tool_call&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;tool_name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; args&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; dict&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; | None&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;工具执行后自动检查，返回 None 表示通过，否则返回错误信息&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    if&lt;/span&gt;&lt;span&gt; tool_name&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;add_note&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        data&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; json&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;loads&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;result&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; !=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;ok&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            return f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;便签添加失败：&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;result&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; len&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&amp;quot;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;便签标题为空&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    if&lt;/span&gt;&lt;span&gt; tool_name&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;get_weather&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;未找到&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; in&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            return f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;天气查询无结果，可能需要更正城市名&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return None&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  # 验证通过&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# ── 4. Agent 主循环 ──&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; agent_loop&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;user_input&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; max_rounds&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 8&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    messages&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; [{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;system&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;你是一个生活助手 Agent，可以查天气和记便签。&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;- 遇到天气问题主动用 get_weather，不要猜测&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;- 用户叫你记东西时用 add_note&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;- 用户问之前记过什么时用 list_notes&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;- 不要编造天气数据&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }, {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; user_input&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    for&lt;/span&gt;&lt;span&gt; round_num&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; range&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;max_rounds&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        resp&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; client&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;chat&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;completions&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;create&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            model&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;gpt-4o-mini&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            messages&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt;messages&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            tools&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt;TOOLS&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            tool_choice&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;auto&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        msg&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; resp&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;choices&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;].&lt;/span&gt;&lt;span&gt;message&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if not&lt;/span&gt;&lt;span&gt; msg&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;tool_calls&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            return&lt;/span&gt;&lt;span&gt; msg&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;content&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        # 追加助手消息到历史&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        messages&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;msg&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        for&lt;/span&gt;&lt;span&gt; tc&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; in&lt;/span&gt;&lt;span&gt; msg&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;tool_calls&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            fn_name&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; tc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            fn_args&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; json&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;loads&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;arguments&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;            # 执行工具&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            try&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                raw_result&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; TOOL_MAP&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;fn_name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;](&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;**&lt;/span&gt;&lt;span&gt;fn_args&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            except&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Exception&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; as&lt;/span&gt;&lt;span&gt; e&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                raw_result&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; json&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;dumps&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;({&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;            # 自动验证&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            verify_error&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; verify_tool_call&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;fn_name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; fn_args&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; raw_result&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            if&lt;/span&gt;&lt;span&gt; verify_error&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                raw_result&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; json&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;dumps&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;({&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;warning&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; verify_error&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; json&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;loads&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;raw_result&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            messages&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;tool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;tool_call_id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; tc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; raw_result&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            })&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;            print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;  🔧 第&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;round_num&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;轮: &lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;fn_name&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;json&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;dumps&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;fn_args&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; ensure_ascii&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=False&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;)&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            if&lt;/span&gt;&lt;span&gt; verify_error&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;                print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;     ⚠️ 验证警告: &lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;verify_error&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;达到最大轮数限制。&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# ── 5. 跑起来 ──&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;if&lt;/span&gt;&lt;span&gt; __name__&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;__main__&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 50&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;场景 1：查天气 + 记便签&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 50&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    answer&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; agent_loop&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;帮我查一下深圳的天气，如果下雨就把&amp;#39;带伞提醒&amp;#39;记到便签里&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;📝 Agent：&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;answer&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}\n&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 50&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;场景 2：跨轮记忆&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 50&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    answer&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; agent_loop&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;我之前记过什么便签？&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;📝 Agent：&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;answer&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;zhe-ci-duo-liao-shen-me&quot;&gt;这次多了什么？&lt;/h3&gt;
&lt;p&gt;和上一篇的 50 行相比，这次有三个关键升级：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. 多工具协同。&lt;/strong&gt; Agent 有了三个工具而不是一个。它需要自己判断“现在该用哪个“。注意工具描述里的决策条件——“当用户询问天气时使用”“当用户说记下来时使用”——这些不是废话，是给模型的决策路由表。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. 自动验证钩子。&lt;/strong&gt; &lt;code&gt;verify_tool_call&lt;/code&gt; 函数在每次工具执行后自动跑。如果 &lt;code&gt;add_note&lt;/code&gt; 返回失败，或天气查询返回“未找到“，错误信息会被追加上去，Agent 在下一轮就能看到并纠正。这是 Harness 里“验证“组件的最简实现——不需要复杂的 Sidecar，一个 10 行的检查函数就能避免很多静默失败。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. 跨轮状态。&lt;/strong&gt; &lt;code&gt;NOTES&lt;/code&gt; 字典在内存里保存了 Agent 写的便签。第二个场景里，Agent 能读到之前记的内容。这就是最简单的“记忆“——但它只在进程存活时有效。下一篇我们会讲真正的持久化记忆系统。&lt;/p&gt;
&lt;h3 id=&quot;yun-xing-xiao-guo&quot;&gt;运行效果&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;==================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;场景&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 1：查天气 + 记便签&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;==================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  🔧&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 第1轮: get_weather&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;{&amp;quot;city&amp;quot;: &amp;quot;深圳&amp;quot;})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  🔧&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 第2轮: add_note&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;{&amp;quot;title&amp;quot;: &amp;quot;带伞提醒&amp;quot;, &amp;quot;content&amp;quot;: &amp;quot;深圳今天有雷阵雨，出门记得带伞。&amp;quot;})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;📝&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; Agent：深圳目前是雷阵雨，气温 31°C，湿度较高。我已经帮你把&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;带伞提醒&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;记到便签里了，出门别忘了带伞！&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;==================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;场景&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 2：跨轮记忆&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;==================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  🔧&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 第1轮: list_notes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;{})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;📝&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; Agent：你目前有一条便签：&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;-&lt;/span&gt;&lt;span&gt; [note_001] 带伞提醒（2026-08-06）&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;zong-jie&quot;&gt;总结&lt;/h2&gt;
&lt;p&gt;今天我们讲了：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;工具是 Agent 的双手&lt;/strong&gt;——五类工具覆盖了从“看“到“做“到“叫人“到“被叫醒“的完整交互模式。通用工具胜过专用工具，除非有安全边界。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;工具设计是工程活&lt;/strong&gt;——描述写什么（决策条件、边界、示例）比实现写什么更重要。MCP 让工具可复用，但要注意上下文开销。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;多工具 + 自动验证 = 更可靠的 Agent&lt;/strong&gt;——我们在上一篇基础上加了三个工具和一个验证钩子。Agent 现在能协同使用多个工具，出错时能及时发现并纠正。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;xia-yi-qi-yu-gao&quot;&gt;下一期预告&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Agent 的记忆：RAG、知识库与跨会话持久化&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;目前的 Agent 关了进程就“失忆“。下一期我们给 Agent 装上真正的长期记忆——用向量数据库搭 RAG，让 Agent 能记住你的偏好、检索你给过的文档、跨会话保持上下文。配套实战：搭一个“能记住你“的问答 Agent。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;em&gt;本文基于李博杰《&lt;a rel=&quot;external&quot; href=&quot;https://bojieli.github.io/ai-agent-book/&quot;&gt;深入理解 AI Agent&lt;/a&gt;》（Apache 2.0 协议）第 4-5 章内容改编，用费曼学习法重构为“概念 → 类比 → 动手“三段式教程。&lt;/em&gt;&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Agent 的记忆：RAG、知识库与一个能记住你的问答 Agent</title>
        <published>2026-08-06T00:00:00+00:00</published>
        <updated>2026-08-06T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/ai-agent-series-03-memory-rag/"/>
        <id>https://scp.net.cn/blog/ai-agent-series-03-memory-rag/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/ai-agent-series-03-memory-rag/">&lt;blockquote&gt;
&lt;p&gt;本文是 &lt;strong&gt;AI Agent 系列教程&lt;/strong&gt; 第 3 篇。基于李博杰《深入理解 AI Agent》第 2-3 章改编。上一篇我们给 Agent 装了多个工具。但有一个问题——关了进程，什么都忘了。今天解决这个。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;part-1-gai-nian-agent-de-ji-yi-xi-tong&quot;&gt;Part 1：概念——Agent 的记忆系统&lt;/h2&gt;
&lt;h3 id=&quot;wen-ti-wei-shen-me-yao-gei-agent-zhuang-ji-yi&quot;&gt;问题：为什么要给 Agent 装记忆？&lt;/h3&gt;
&lt;p&gt;打开 ChatGPT，每一次新对话都是“初次见面“。它不记得你上次聊了什么、你喜欢什么格式、你讨厌什么缩写。每次都要重新说一遍。&lt;/p&gt;
&lt;p&gt;这就是&lt;strong&gt;无状态 Agent&lt;/strong&gt; 的核心局限。一个有记忆的 Agent 应该是这样的：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;你：“帮我订一张去东京的机票”
Agent：（查你的历史——偏好靠窗座位、素食餐、美联航会员号 12345678）
Agent：（发现你的护照还剩 3 个月到期）
Agent：“深圳直飞东京 3 月 15 日，已选靠窗座位和素食餐。另外提醒一下，你的护照 5 月 18 日到期，距出发仅 2 个月，建议出发前续办。”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这背后是一套&lt;strong&gt;记忆系统&lt;/strong&gt;在工作——它知道你的偏好、记得你的身份信息、能在关键时间点主动提醒你。&lt;/p&gt;
&lt;h3 id=&quot;ji-yi-de-san-ceng-jia-gou&quot;&gt;记忆的三层架构&lt;/h3&gt;
&lt;p&gt;Agent 的记忆系统分三层，像人的记忆一样有层次：&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;层次&lt;/th&gt;&lt;th&gt;对应人的&lt;/th&gt;&lt;th&gt;作用&lt;/th&gt;&lt;th&gt;生命周期&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;工作记忆&lt;/strong&gt;（当前上下文）&lt;/td&gt;&lt;td&gt;你正在想的事&lt;/td&gt;&lt;td&gt;当前对话的完整轨迹&lt;/td&gt;&lt;td&gt;单次会话&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;长期记忆&lt;/strong&gt;（用户画像）&lt;/td&gt;&lt;td&gt;你的习惯、身份、偏好&lt;/td&gt;&lt;td&gt;跨会话持久化的关键事实&lt;/td&gt;&lt;td&gt;跨会话持久&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;知识库&lt;/strong&gt;（RAG 检索）&lt;/td&gt;&lt;td&gt;你能翻的书和文档&lt;/td&gt;&lt;td&gt;按需检索的外部知识&lt;/td&gt;&lt;td&gt;持久、共享&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;工作记忆&lt;/strong&gt;最简单——就是对话历史本身。Agent 做每一步决策时，都基于“系统提示 + 工具列表 + 完整对话历史“。但随着对话变长，这层记忆会超过上下文窗口。第 1 篇的上下文压缩就是在解决这个问题。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;长期记忆&lt;/strong&gt;是今天的主角——从对话中提取关键事实，存起来，下次用。难点不在存，在**“什么时候召回什么”**。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;知识库&lt;/strong&gt;是 RAG（Retrieval-Augmented Generation）——把文档切成块，用向量索引，用户提问时检索最相关的片段喂给 LLM。&lt;/p&gt;
&lt;h3 id=&quot;rag-zen-me-gong-zuo-de-cong-wen-dang-dao-da-an&quot;&gt;RAG 怎么工作的——从文档到答案&lt;/h3&gt;
&lt;p&gt;RAG 的完整流程：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;离线阶段（建索引）：&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  文档 → 切块（256-1024 token/块，10-20% 重叠）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       → 用 Embedding 模型把每块转成向量&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       → 存入向量数据库（构建索引）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;在线阶段（检索）：&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  用户提问 → 同样用 Embedding 转成向量&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          → 在向量数据库里找最相似的 top-k 块&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          → 把检索到的块 + 用户问题一起喂给 LLM&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          → LLM 基于这些块生成答案&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;关键环节有三个：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. 切块（Chunking）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;三种策略：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;固定大小&lt;/strong&gt;：如每块 512 token，50 token 重叠。简单但可能把一句话切成两半&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;结构感知&lt;/strong&gt;：按文档的标题、段落、列表的自然边界切。&lt;strong&gt;生产环境默认选这个&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;语义切分&lt;/strong&gt;：在 Embedding 相似度发生“断崖“的地方切。效果最好但最慢&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;2. Embedding（向量化）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;把文字变成能比较相似度的向量。语义相近的文字，向量也相近：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;quot;如何养猫&amp;quot;      → (0.9, 0.5, 0.1)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;quot;猫咪饲养指南&amp;quot;   → (0.8, 0.6, 0.1)  → 相似度 ≈ 0.99&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;quot;股票投资策略&amp;quot;   → (0.1, 0.1, 0.9)  → 相似度 ≈ 0.25&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;现代 Embedding 模型（如 BGE-M3）能做到“河岸的 bank“和“投资银行的 bank“产生不同的向量——模型理解上下文，而不只是词面。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. 混合检索（Hybrid Retrieval）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;只用向量（Dense）不够。考虑：搜索“模型蒸馏“这个词，向量检索能找到语义相关的“知识蒸馏““参数压缩”，但可能漏掉精确包含“模型蒸馏“四个字的文档。&lt;/p&gt;
&lt;p&gt;所以生产环境用&lt;strong&gt;混合检索&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Dense（向量）&lt;/strong&gt;——语义匹配，理解同义词和改写&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sparse（BM25）&lt;/strong&gt;——关键词匹配，精确命中术语&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reranker&lt;/strong&gt;——用更强的模型对前两种的结果做精排&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Anthropic 的实践数据：在标准 RAG 基础上加 BM25，检索失败率降低 49%；再加 Reranker，降低 67%。&lt;/p&gt;
&lt;h3 id=&quot;contextual-retrieval-gei-mei-ge-kuai-jia-shang-xia-wen-biao-qian&quot;&gt;Contextual Retrieval：给每个块加“上下文标签“&lt;/h3&gt;
&lt;p&gt;这是 Anthropic 提的一个简单但有效的技巧。在把文档块嵌入向量之前，先让 LLM 给它生成一个前缀：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;原文块：“第四季度营收同比增长 23%，主要受云计算业务推动……”&lt;/p&gt;
&lt;p&gt;加了前缀后：&lt;strong&gt;“[这是 ACME 公司 2025 年 Q2 财报的’关键业绩指标’部分] 第四季度营收同比增长 23%……”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;把“前缀 + 原文块“一起做 Embedding，检索效果显著提升——因为前缀提供了这个片段在整个文档体系中的&lt;strong&gt;位置和语境&lt;/strong&gt;。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;part-2-lei-bi-agent-de-ji-yi-jiu-xiang-ni-de-ge-ren-mi-shu&quot;&gt;Part 2：类比——Agent 的记忆就像你的个人秘书&lt;/h2&gt;
&lt;p&gt;想象你有一个&lt;strong&gt;私人秘书&lt;/strong&gt;，你需要他帮你处理各种事务。他怎么记东西？&lt;/p&gt;
&lt;h3 id=&quot;san-ceng-ji-yi-dui-ying&quot;&gt;三层记忆对应&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;工作记忆 = 便签条。&lt;/strong&gt; 你今天跟他说“帮我订一张票、再改一下那个报告、顺便提醒我下午开会“，这些事他记在便签条上，当天有效。但一张便签条写不了 100 件事。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;长期记忆 = 人事档案。&lt;/strong&gt; 你的身份证号、饮食习惯、常飞航线、常用信用卡——这些不需要每次都问，写在档案里，随时翻。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;知识库 = 公司图书馆。&lt;/strong&gt; 行业规范、合同模板、技术文档——不需要背下来，但需要的时候能在几秒钟内找到。&lt;/p&gt;
&lt;h3 id=&quot;ji-yi-xi-tong-zhen-zheng-de-nan-dian&quot;&gt;记忆系统真正的难点&lt;/h3&gt;
&lt;p&gt;不是“存“——存东西太容易了。真正的难点是&lt;strong&gt;在正确的时机召回正确的内容&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;继续秘书的类比：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;场景 A&lt;/strong&gt;：你正在订机票，秘书应该自动把你的护照信息、座位偏好、常旅客号&lt;strong&gt;前置加载&lt;/strong&gt;到工作台上。这叫“结构化卡片常驻上下文“。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;场景 B&lt;/strong&gt;：你遇到一个税务问题，去年处理过一次类似情况。秘书应该能从档案室&lt;strong&gt;检索到上次的处理记录&lt;/strong&gt;。这叫“按需检索“。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;场景 C&lt;/strong&gt;：你护照还有 3 个月到期，但你已经在订国际机票了。秘书&lt;strong&gt;不应该等你问“我的护照快到期了吗？“，而应该主动提醒&lt;/strong&gt;。这叫“主动服务”——记忆系统的最高境界。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;ji-yi-ti-qu-ba-dui-hua-bian-cheng-dang-an&quot;&gt;记忆提取：把对话变成档案&lt;/h3&gt;
&lt;p&gt;每次跟你聊完，秘书需要&lt;strong&gt;从对话里提取关键信息&lt;/strong&gt;更新档案。不是每句话都记——只能记重要的：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;你：“帮我订一张 3 月 15 号去东京的机票，靠窗座位，我是素食者。”&lt;/p&gt;
&lt;p&gt;秘书提取：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;偏好靠窗座位（偏好）&lt;/li&gt;
&lt;li&gt;素食饮食限制（饮食需求）&lt;/li&gt;
&lt;li&gt;有 3 月东京出行计划（近期活动）&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;注意：“3 月 15 号“这个具体日期没有作为一条独立记忆——它只在这次旅行上下文里有意义。选择性提取是记忆系统的关键。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;part-3-dong-shou-da-yi-ge-neng-ji-zhu-ni-de-rag-wen-da-agent&quot;&gt;Part 3：动手——搭一个“能记住你“的 RAG 问答 Agent&lt;/h2&gt;
&lt;h3 id=&quot;wo-men-yao-zuo-shen-me&quot;&gt;我们要做什么&lt;/h3&gt;
&lt;p&gt;升级第 2 篇的 Agent：给它装上 ChromaDB 向量数据库，实现：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;跨会话长期记忆&lt;/strong&gt;：Agent 从对话中自动提取关键信息，存入向量库。下次对话时检索相关记忆。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;文档知识库&lt;/strong&gt;：可以喂给它文档（我们用几篇模拟的 Markdown 文件），它基于文档回答问题。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;不需要外部 API——用 &lt;code&gt;chromadb&lt;/code&gt;（本地向量库）+ &lt;code&gt;sentence-transformers&lt;/code&gt;（本地 Embedding 模型）。&lt;/p&gt;
&lt;h3 id=&quot;wan-zheng-dai-ma&quot;&gt;完整代码&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span&gt; json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;from&lt;/span&gt;&lt;span&gt; datetime&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; import&lt;/span&gt;&lt;span&gt; datetime&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;from&lt;/span&gt;&lt;span&gt; openai&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; import&lt;/span&gt;&lt;span&gt; OpenAI&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span&gt; chromadb&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;from&lt;/span&gt;&lt;span&gt; chromadb&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;utils&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; import&lt;/span&gt;&lt;span&gt; embedding_functions&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;client&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; OpenAI&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# ── 1. 初始化向量数据库 ──&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 用 sentence-transformers 的本地模型做 Embedding（无需 API 调用）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ef&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; embedding_functions&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;SentenceTransformerEmbeddingFunction&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    model_name&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;all-MiniLM-L6-v2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  # 轻量，384 维，本地运行&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;chroma_client&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; chromadb&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;PersistentClient&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;path&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;./agent_memory_db&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 两个 Collection：一个存用户记忆，一个存文档知识库&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;memory_collection&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; chroma_client&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get_or_create_collection&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    name&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;user_memory&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    embedding_function&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt;ef&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    metadata&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;description&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;跨会话用户长期记忆&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;docs_collection&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; chroma_client&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get_or_create_collection&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    name&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;knowledge_base&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    embedding_function&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt;ef&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    metadata&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;description&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;文档知识库&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# ── 2. 记忆提取器 ──&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;MEMORY_EXTRACT_PROMPT&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;从以下对话中提取关于用户的关键信息。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;只提取持久性的事实，忽略临时信息。每条信息以 JSON 格式输出。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;输出格式：&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;[{&amp;quot;type&amp;quot;: &amp;quot;preference|identity|fact&amp;quot;, &amp;quot;content&amp;quot;: &amp;quot;事实描述&amp;quot;}]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;提取规则：&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;- preference: 偏好（喜欢/讨厌什么、习惯）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;- identity: 身份信息（姓名、职业、技能）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;- fact: 重要事实（过敏、持有资产、重要日期）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;对话：&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;{conversation}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;只输出 JSON 数组，不要输出其他内容。&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; extract_and_store_memories&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;conversation&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;从对话中提取记忆并存入向量库&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    resp&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; client&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;chat&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;completions&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;create&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        model&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;gpt-4o-mini&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        messages&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[{&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; MEMORY_EXTRACT_PROMPT&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;conversation&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt;conversation&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)}],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        temperature&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    try&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        memories&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; json&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;loads&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;resp&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;choices&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;].&lt;/span&gt;&lt;span&gt;message&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    except&lt;/span&gt;&lt;span&gt; json&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;JSONDecodeError&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; []&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    for&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; mem&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; enumerate&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;memories&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        mem_id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;mem_&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;datetime&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;now&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;strftime&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;%Y%m&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;%d&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;_%H%M%S&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;)&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        memory_collection&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            documents&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;mem&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            metadatas&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[{&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; mem&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;], &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;timestamp&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; datetime&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;now&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;isoformat&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()}],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            ids&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;mem_id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; memories&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; recall_memories&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;query&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; n_results&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) -&amp;gt;&lt;/span&gt;&lt;span&gt; list&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;根据当前查询，检索最相关的历史记忆&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    results&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; memory_collection&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;query_texts&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;query&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;],&lt;/span&gt;&lt;span&gt; n_results&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt;n_results&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    if not&lt;/span&gt;&lt;span&gt; results&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;documents&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;][&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; []&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; results&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;documents&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;][&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# ── 3. 文档索引器 ──&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; index_document&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;doc_id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; text&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; chunk_size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 500&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;将文档切块并存入知识库&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    # 简单按段落切块（生产环境用结构感知切分）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    words&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; text&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;split&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    chunks&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; []&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    for&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; range&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; len&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;words&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;),&lt;/span&gt;&lt;span&gt; chunk_size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        chunk&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot; &amp;quot;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;join&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;words&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span&gt; chunk_size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        chunks&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;chunk&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    for&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; chunk&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; enumerate&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;chunks&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        docs_collection&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            documents&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;chunk&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            metadatas&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[{&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;doc_id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; doc_id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;chunk_index&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            ids&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;doc_id&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;_chunk_&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; len&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;chunks&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; search_docs&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;query&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; n_results&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) -&amp;gt;&lt;/span&gt;&lt;span&gt; list&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;搜索知识库&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    results&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; docs_collection&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;query_texts&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;query&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;],&lt;/span&gt;&lt;span&gt; n_results&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt;n_results&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    if not&lt;/span&gt;&lt;span&gt; results&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;documents&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;][&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; []&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; results&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;documents&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;][&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# ── 4. 工具定义（在原有基础上增加记忆相关工具） ──&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; recall_user_memory&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;query&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;检索与当前查询相关的用户历史记忆&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    memories&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; recall_memories&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;query&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    if not&lt;/span&gt;&lt;span&gt; memories&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;未找到相关历史记忆&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;相关历史记忆：&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;join&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;- &lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; for&lt;/span&gt;&lt;span&gt; m&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; in&lt;/span&gt;&lt;span&gt; memories&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; search_knowledge_base&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;query&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;搜索文档知识库&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    docs&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; search_docs&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;query&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    if not&lt;/span&gt;&lt;span&gt; docs&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;知识库中未找到相关内容&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;知识库检索结果：&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;---&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;join&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;docs&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; get_weather&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;city&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;模拟天气查询&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    weather_db&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;北京&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;晴，24°C&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;上海&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;多云，28°C&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;深圳&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;雷阵雨，31°C&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;东京&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;晴，18°C&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; json&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;dumps&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;({&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;city&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; city&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;weather&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; weather_db&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;city&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;未找到&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;TOOLS&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;recall_user_memory&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;description&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;检索与当前查询相关的用户历史记忆。&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;当需要了解用户偏好、历史记录、身份信息时使用。&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;每次对话开始时应该主动调用此工具了解用户。&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            ),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;parameters&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;object&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;properties&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;description&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;描述需要检索的信息的查询文本&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;required&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: [&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;search_knowledge_base&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;description&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;搜索文档知识库获取相关信息。&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;当用户询问专业知识、需要查找文档内容时使用。&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;不要用于查询用户个人信息——用 recall_user_memory。&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            ),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;parameters&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;object&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;properties&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;description&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;搜索查询&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;required&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: [&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;get_weather&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;description&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;查询指定城市的实时天气&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;parameters&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;object&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;properties&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;city&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;description&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;城市名称&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;required&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: [&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;city&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;TOOL_MAP&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;recall_user_memory&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; recall_user_memory&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;search_knowledge_base&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; search_knowledge_base&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;get_weather&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; get_weather&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# ── 5. Agent 主循环 ──&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; agent_loop&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;user_input&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; max_rounds&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 8&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    messages&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; [{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;system&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;你是一个有记忆的个人助手 Agent。&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;- 每次对话开始时，用 recall_user_memory 了解用户背景&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;- 遇到不确定的专业知识，用 search_knowledge_base 搜索&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;- 基于检索到的记忆和知识给出个性化回复&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;- 不要编造用户信息和事实&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }, {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; user_input&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    full_conversation&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;用户: &lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;user_input&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    for&lt;/span&gt;&lt;span&gt; round_num&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; range&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;max_rounds&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        resp&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; client&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;chat&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;completions&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;create&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            model&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;gpt-4o-mini&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            messages&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt;messages&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            tools&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt;TOOLS&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            tool_choice&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;auto&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        msg&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; resp&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;choices&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;].&lt;/span&gt;&lt;span&gt;message&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if not&lt;/span&gt;&lt;span&gt; msg&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;tool_calls&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;            # 对话结束，自动提取记忆&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            memories&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; extract_and_store_memories&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;full_conversation&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; + f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;助手: &lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;msg&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;content&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            if&lt;/span&gt;&lt;span&gt; memories&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;                print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;  🧠 提取了 &lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;len&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;memories&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 条记忆&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            return&lt;/span&gt;&lt;span&gt; msg&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;content&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        messages&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;msg&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        for&lt;/span&gt;&lt;span&gt; tc&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; in&lt;/span&gt;&lt;span&gt; msg&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;tool_calls&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            fn_name&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; tc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            fn_args&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; json&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;loads&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;arguments&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            result&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; TOOL_MAP&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;fn_name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;](&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;**&lt;/span&gt;&lt;span&gt;fn_args&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            messages&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;tool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;tool_call_id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; tc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            })&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;            print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;  🔧 第&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;round_num&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;轮: &lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;fn_name&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;json&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;dumps&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;fn_args&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; ensure_ascii&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=False&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)[:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;60&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;...)&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;达到最大轮数。&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# ── 6. 初始化知识库并跑起来 ──&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;if&lt;/span&gt;&lt;span&gt; __name__&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;__main__&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    # 索引几篇模拟的产品文档&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    index_document&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;product_faq&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;    Product X 是一款智能家居中枢设备，支持 Zigbee、Z-Wave 和 Wi-Fi 协议。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;    设备需要在 2.4GHz Wi-Fi 网络下工作，不支持 5GHz。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;    常见的连接问题包括：设备与路由器距离过远、Wi-Fi 信道拥堵、固件版本过旧。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;    确认设备 LED 指示灯为蓝色常亮表示连接成功，红色闪烁表示连接失败。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;    重置设备：长按背面的 reset 按钮 10 秒，直到 LED 变为白色。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    index_document&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;company_policy&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;    公司年假政策：入职第一年按比例计算年假，每满一个月获得 1 天。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;    入职满一年后，每年享有 15 天带薪年假。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;    年假可在当年内任意时间使用，未用完的年假最多可延长至次年 3 月 31 日。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;    病假：每年 12 天带薪病假，无需医生证明。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 55&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;场景 1：Agent 第一次见我&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 55&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    answer&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; agent_loop&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;你好！我叫张三，是一名后端工程师，我不吃香菜。帮我查一下深圳天气。&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;📝 Agent：&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;answer&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}\n&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 55&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;场景 2：Agent 记住了我（新对话）&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 55&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    answer&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; agent_loop&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;帮我推荐一家餐厅&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;📝 Agent：&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;answer&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}\n&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 55&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;场景 3：搜索文档知识库&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 55&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    answer&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; agent_loop&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;我的 Product X 连不上网了，红灯一直闪，怎么排查？&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;📝 Agent：&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;answer&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}\n&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    # 查看已存储的记忆&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    all_mems&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; memory_collection&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 55&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;📦 记忆库中共有 &lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;len&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;all_mems&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;documents&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;])&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 条记忆：&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    for&lt;/span&gt;&lt;span&gt; doc&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; in&lt;/span&gt;&lt;span&gt; all_mems&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;documents&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;        print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;  - &lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;doc&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;yun-xing-xiao-guo&quot;&gt;运行效果&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=======================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;场景&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 1：Agent 第一次见我&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=======================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  🔧&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 第1轮: get_weather&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;{&amp;quot;city&amp;quot;: &amp;quot;深圳&amp;quot;})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  🧠&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 提取了&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 条记忆&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;📝&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; Agent：深圳今天雷阵雨，31°C。出门记得带伞！&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=======================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;场景&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 2：Agent 记住了我（新对话）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=======================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  🔧&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 第1轮: recall_user_memory&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;{&amp;quot;query&amp;quot;: &amp;quot;用户偏好 饮食 身份&amp;quot;})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  🧠&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 提取了&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 条记忆&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;📝&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; Agent：根据我的记忆，你是后端工程师张三，而且不吃香菜。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;我推荐一家主打清淡粤菜的餐厅——鼎泰丰，他们家的蒸点很出名，&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;而且调味克制，不会有香菜风险。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=======================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;场景&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 3：搜索文档知识库&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=======================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  🔧&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 第1轮: search_knowledge_base&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;{&amp;quot;query&amp;quot;: &amp;quot;Product X 红灯闪烁 连接失败&amp;quot;})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;📝&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; Agent：你的 Product X LED 红灯闪烁说明连接失败。排查步骤：&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;1.&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 确认设备与路由器距离不要太远&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;2.&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 确认 Wi-Fi 是 2.4GHz（不支持 5GHz）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;3.&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 检查固件版本是否过旧&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;4.&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 如果以上都不行，长按 reset 按钮&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 秒重置设备，等 LED 变白即可。&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;cong-demo-dao-sheng-chan-ji&quot;&gt;从 Demo 到生产级&lt;/h3&gt;
&lt;p&gt;这个 Demo 跑通了“提取→存储→检索→应用“的完整链路。但和生产级记忆系统相比，还有这些差距：&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;维度&lt;/th&gt;&lt;th&gt;我们的 Demo&lt;/th&gt;&lt;th&gt;生产级记忆系统&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Embedding 模型&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;all-MiniLM-L6-v2（384 维）&lt;/td&gt;&lt;td&gt;BGE-M3 等专用模型（1024+ 维）&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;检索方式&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;纯向量检索&lt;/td&gt;&lt;td&gt;向量 + BM25 混合检索 + Reranker&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;记忆提取&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;每次对话结束全量提取&lt;/td&gt;&lt;td&gt;增量提取 + 定期全局重组&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;冲突处理&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;无（同名信息会重复存）&lt;/td&gt;&lt;td&gt;版本化检测 + 追加式写入 + 查询时消歧&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;主动服务&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;无（只做检索）&lt;/td&gt;&lt;td&gt;结构化卡片常驻上下文，触发条件检查&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;知识库安全&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;无（检索内容直接注入）&lt;/td&gt;&lt;td&gt;来源标记 + 指令/数据分离&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Contextual Retrieval&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;无&lt;/td&gt;&lt;td&gt;每个块带上下文前缀，检索失败率↓67%&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;zong-jie&quot;&gt;总结&lt;/h2&gt;
&lt;p&gt;今天我们讲了：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Agent 记忆分三层&lt;/strong&gt;——工作记忆（当前对话）、长期记忆（用户画像）、知识库（文档检索）。三层配合才能从“一问一答“升级到“跨会话智能助手“。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;RAG = 切块 + 向量化 + 检索 + 生成&lt;/strong&gt;——核心公式几十年不变，但每一环都有工程深度。混合检索（Dense + Sparse + Reranker）是生产标配，Contextual Retrieval 用小成本换大提升。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;我们搭了一个有记忆的 Agent&lt;/strong&gt;——用 ChromaDB + 本地 Embedding，实现了自动记忆提取、跨会话检索、文档知识库查询。从这出发，加混合检索、加冲突消解、加主动触发，就是生产级记忆系统。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;xia-yi-qi-yu-gao&quot;&gt;下一期预告&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Agent 怎么“学好“：评估、训练与持续进化&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;搭好 Agent 只是第一步。真正的问题是：你怎么知道它变好了还是变差了？下一篇讲 Agent 评测体系——怎么量化“好“、怎么保证改动不让 Agent 退化、怎么让 Agent 从失败中持续学习。配套实战：构建一个 Agent 评测小平台。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;em&gt;本文基于李博杰《&lt;a rel=&quot;external&quot; href=&quot;https://bojieli.github.io/ai-agent-book/&quot;&gt;深入理解 AI Agent&lt;/a&gt;》（Apache 2.0 协议）第 2-3 章内容改编，用费曼学习法重构为“概念 → 类比 → 动手“三段式教程。&lt;/em&gt;&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Agent 怎么&quot;学好&quot;：评估体系、训练方法与持续进化</title>
        <published>2026-08-06T00:00:00+00:00</published>
        <updated>2026-08-06T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/ai-agent-series-04-evaluation-evolution/"/>
        <id>https://scp.net.cn/blog/ai-agent-series-04-evaluation-evolution/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/ai-agent-series-04-evaluation-evolution/">&lt;blockquote&gt;
&lt;p&gt;本文是 &lt;strong&gt;AI Agent 系列教程&lt;/strong&gt; 第 4 篇。基于李博杰《深入理解 AI Agent》第 6-8 章改编。前三篇我们学会了搭 Agent、装工具、加记忆。现在要回答一个更根本的问题：&lt;strong&gt;怎么知道它做对了？怎么让它持续变好？&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;part-1-gai-nian-agent-de-ping-gu-yu-jin-hua-ti-xi&quot;&gt;Part 1：概念——Agent 的评估与进化体系&lt;/h2&gt;
&lt;h3 id=&quot;wen-ti-agent-wei-shen-me-bu-neng-zi-jue-zuo-hao&quot;&gt;问题：Agent 为什么不能“自觉“做好？&lt;/h3&gt;
&lt;p&gt;你给 Agent 装了两个工具——查天气和记便签。跑了几次，感觉还行。但你有没有想过：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;上次你改了一下系统提示词，Agent 还能正常工作吗？&lt;/li&gt;
&lt;li&gt;换了一个更便宜的模型，效果有没有变差？&lt;/li&gt;
&lt;li&gt;Agent 有没有在某些你不常测的场景下悄悄“退化“了？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这三个问题指向同一个核心：&lt;strong&gt;没有可执行验证的 Agent 系统，是在猜谜。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Harness 工程把验证列为四大支柱之一（约束 + 验证 + 纠偏 + 上下文）。因为 Agent 和其他软件一样——没有回归测试，就没法安心迭代。&lt;/p&gt;
&lt;h3 id=&quot;ping-gu-ti-xi-de-san-ceng-jia-gou&quot;&gt;评估体系的三层架构&lt;/h3&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;层级&lt;/th&gt;&lt;th&gt;回答的问题&lt;/th&gt;&lt;th&gt;核心工具&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;评估环境&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;在哪测？&lt;/td&gt;&lt;td&gt;可重置、可复现的自动化测试环境&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;评估方法&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;怎么判对错？&lt;/td&gt;&lt;td&gt;Rubric 评分表、LLM-as-a-Judge、统计指标&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;评估驱动决策&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;测完怎么办？&lt;/td&gt;&lt;td&gt;选模型、优架构、持续迭代&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;一个关键洞察：&lt;strong&gt;评估的对象不是模型，而是“模型 + Harness“的组合体。&lt;/strong&gt; 同一个模型在不同 Harness 下表现可以天差地别。这就是为什么 LangChain 在不换模型的前提下，只靠优化 Harness 就让 Terminal Bench 从 52.8% 升到 66.5%。&lt;/p&gt;
&lt;p&gt;评估还有一个首要价值：&lt;strong&gt;让你能快速跟上模型演进。&lt;/strong&gt; 当新模型出来时（基本每个月都有），你的评估系统能在几小时内告诉你：“这个模型在我们的场景下，好多少？坏在哪？换不换？”&lt;/p&gt;
&lt;h3 id=&quot;ping-gu-de-liang-ge-shi-yan-fang-fa&quot;&gt;评估的两个实验方法&lt;/h3&gt;
&lt;p&gt;如果想搞清楚 Agent 表现不好的瓶颈在哪，用这两个方法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;模型替换实验&lt;/strong&gt;：固定 Harness，换成更强/更弱的模型。如果分数变化剧烈，瓶颈在模型能力；如果换更强的模型分数也不涨，瓶颈在 Harness 设计。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;消融实验&lt;/strong&gt;：一次关掉 Harness 的一个组件（如关掉上下文压缩），看分数掉多少。能精确找到“哪个 Harness 组件在起作用“。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;ping-ce-zhi-biao-zen-me-xuan-bie-bei-yi-ge-shu-zi-pian-liao&quot;&gt;评测指标怎么选：别被一个数字骗了&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;任务成功率&lt;/strong&gt;是最直接的硬指标，但要注意统计陷阱。一个 100 个测试用例、70% 成功率的结果，95% 置信区间大约是 70% ± 9 个百分点。也就是说，你的 Agent 真实成功率可能在 61%-79% 之间。&lt;/p&gt;
&lt;p&gt;如果两个配置的差异只有 3 个百分点（73% vs 70%），这完全在噪声范围内——别因为这个差距就决定换模型。&lt;/p&gt;
&lt;p&gt;更重要的一组指标：&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;指标&lt;/th&gt;&lt;th&gt;含义&lt;/th&gt;&lt;th&gt;何时用&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Pass@k&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;k 次尝试中至少成功 1 次&lt;/td&gt;&lt;td&gt;探索能力上限&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Pass^k&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;k 次全部成功&lt;/td&gt;&lt;td&gt;验证稳定性（回归）&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;举个例子：单次成功率 60%，Pass@5 = 1 − 0.4^5 ≈ 99%，但 Pass^5 = 0.6^5 ≈ 7.8%。前者告诉你“Agent 能不能做这件事“，后者告诉你“Agent 是不是稳定可靠“。混用这两个指标会导致严重误判。&lt;/p&gt;
&lt;h3 id=&quot;mo-xing-hou-xun-lian-ba-harness-de-jing-yan-xie-jin-mo-xing-can-shu&quot;&gt;模型后训练：把 Harness 的经验写进模型参数&lt;/h3&gt;
&lt;p&gt;第 1 篇说过，Harness 是在模型外面搭基础设施。但有些能力——风格判断、隐式策略、视觉理解——很难用外部的 if-else 规则描述。这时候需要&lt;strong&gt;模型后训练&lt;/strong&gt;把能力写进模型参数。&lt;/p&gt;
&lt;p&gt;后训练分两个阶段：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SFT（监督微调）&lt;/strong&gt;：给模型看“标准答案“。几千到几万对输入-输出示例。效果：固化格式、风格、交互约定。相当于老师演示标准解法。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;RL（强化学习）&lt;/strong&gt;：让模型自己尝试，好的行为加分，坏的扣分。关键优势：模型能探索出训练数据里没有的策略。成本是 SFT 的 10-100 倍。&lt;/p&gt;
&lt;p&gt;一个验证过的结论：在同样的实验条件下，SFT 倾向于背诵演示数据，RL 展示出更好的泛化能力——在未见过的场景中表现更好。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;但大部分 Agent 应用不需要后训练。&lt;/strong&gt; 从 Harness 工程入手（优化提示词、工具、约束、验证）通常比训练模型更高效、更可控。后训练是当 Harness 优化到瓶颈时的高级手段。&lt;/p&gt;
&lt;h3 id=&quot;chi-xu-jin-hua-cong-neng-pao-dao-neng-bian-hao&quot;&gt;持续进化：从“能跑“到“能变好“&lt;/h3&gt;
&lt;p&gt;Agent 系统有四条进化路径，速度从快到慢：&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;路径&lt;/th&gt;&lt;th&gt;更新对象&lt;/th&gt;&lt;th&gt;周期&lt;/th&gt;&lt;th&gt;适用场景&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;上下文内适应&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;当前对话的轨迹&lt;/td&gt;&lt;td&gt;实时&lt;/td&gt;&lt;td&gt;单次任务&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;外部产物更新&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;知识文档、Skills、Harness 代码&lt;/td&gt;&lt;td&gt;小时到天&lt;/td&gt;&lt;td&gt;跨会话持续改进&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;程序/Harness 更新&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Agent 框架代码&lt;/td&gt;&lt;td&gt;天到周&lt;/td&gt;&lt;td&gt;架构优化&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;模型参数更新&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;模型权重（SFT/RL）&lt;/td&gt;&lt;td&gt;周到月&lt;/td&gt;&lt;td&gt;高阶能力固化&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;一个好的 Agent 系统四条路径都在用——快速的多用上下文、中速的多写 Skills、慢速的定期做模型升级。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;part-2-lei-bi-agent-ping-gu-jiu-xiang-jia-xiao-kao-shi&quot;&gt;Part 2：类比——Agent 评估就像驾校考试&lt;/h2&gt;
&lt;h3 id=&quot;ba-agent-xiang-xiang-cheng-xue-che-de-ren&quot;&gt;把 Agent 想象成学车的人&lt;/h3&gt;
&lt;p&gt;Agent 需要学怎么跟用户交互、怎么调用工具、怎么处理异常。这和学开车很像：&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;学车&lt;/th&gt;&lt;th&gt;Agent 评估&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;科目一（交规笔试）&lt;/td&gt;&lt;td&gt;静态评估——单项能力测试（工具参数正确吗？）&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;科目二（倒库、侧方停车）&lt;/td&gt;&lt;td&gt;场景化评估——每个独立场景的端到端测试&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;科目三（路考）&lt;/td&gt;&lt;td&gt;综合评估——真实任务全程，模拟用户交互&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;驾校教练打分&lt;/td&gt;&lt;td&gt;LLM-as-a-Judge——用 Rubric 评分表判断&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;考官的“一票否决“&lt;/td&gt;&lt;td&gt;Hallucination Veto——严重错误直接判不合格&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3 id=&quot;wei-shen-me-rl-bi-sft-geng-xiang-zhen-xue-che&quot;&gt;为什么 RL 比 SFT 更像“真学车“&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SFT 是看着教练开&lt;/strong&gt;：教练给你演示一遍侧方停车，你记住操作顺序。但换个车、换个车位，你可能就不会了。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RL 是自己开&lt;/strong&gt;：你试着倒库，压线了（扣分），没压线（加分），慢慢掌握了“什么时候打方向、打多少“的隐式策略。换车换库都能适应。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这就是为什么 RL 在未见过的场景下表现更好——它学到的是策略，不是记忆。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;part-3-dong-shou-gou-jian-yi-ge-agent-ping-ce-xiao-ping-tai&quot;&gt;Part 3：动手——构建一个 Agent 评测小平台&lt;/h2&gt;
&lt;h3 id=&quot;wo-men-yao-zuo-shen-me&quot;&gt;我们要做什么&lt;/h3&gt;
&lt;p&gt;给第 2 篇的双工具 Agent（天气 + 便签）搭一个评测系统。包含：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;测试用例集&lt;/strong&gt;——定义“什么是做对了“&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rubric 自动评分&lt;/strong&gt;——不只判断“对/错“，还要分维度打分&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;回归检测&lt;/strong&gt;——修改 Harness 后自动对比前后分数&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;wan-zheng-dai-ma&quot;&gt;完整代码&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span&gt; json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span&gt; time&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;from&lt;/span&gt;&lt;span&gt; dataclasses&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; import&lt;/span&gt;&lt;span&gt; dataclass&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; field&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;from&lt;/span&gt;&lt;span&gt; openai&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; import&lt;/span&gt;&lt;span&gt; OpenAI&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;client&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; OpenAI&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# ── 1. Agent 复现（第 2 篇的基础 Agent） ──&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;NOTES&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; dict&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; dict&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; get_weather&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;city&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    weather_db&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;北京&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;晴，24°C&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;上海&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;多云，28°C&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;深圳&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;雷阵雨，31°C&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; json&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;dumps&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;({&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;city&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; city&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;weather&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; weather_db&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;city&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;未找到&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; add_note&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    note_id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;note_&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;len&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;NOTES&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:03d&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    NOTES&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;note_id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; title&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; json&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;dumps&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;({&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;ok&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;note_id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; note_id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; list_notes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;() -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    if not&lt;/span&gt;&lt;span&gt; NOTES&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;暂无便签&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;join&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;[&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;nid&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;]&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; for&lt;/span&gt;&lt;span&gt; nid&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; n&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; in&lt;/span&gt;&lt;span&gt; NOTES&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;items&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;())&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;TOOLS&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;get_weather&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;description&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;查询城市实时天气。当用户询问天气时使用。&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;parameters&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;object&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;properties&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;city&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;}}, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;required&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: [&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;city&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]}}},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;add_note&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;description&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;添加便签。当用户说&amp;#39;记下来&amp;#39;时使用。&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;parameters&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;object&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;properties&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;}, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;}}, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;required&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: [&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]}}},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;list_notes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;description&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;列出所有便签。&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;parameters&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;object&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;properties&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {}}}},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;TOOL_MAP&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;get_weather&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; get_weather&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;add_note&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; add_note&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;list_notes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; list_notes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; run_agent&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;task&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; max_rounds&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 5&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; dict&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;运行 Agent，返回完整轨迹&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    messages&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; [{&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;system&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;你是生活助手。查天气用 get_weather，记便签用 add_note。&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;}, {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; task&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    trajectory&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;task&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; task&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;tool_calls&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: [], &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;final_answer&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;rounds&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;tokens&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    for&lt;/span&gt;&lt;span&gt; _&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; range&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;max_rounds&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        resp&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; client&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;chat&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;completions&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;create&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;model&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;gpt-4o-mini&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span&gt; messages&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt;messages&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; tools&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt;TOOLS&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; tool_choice&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;auto&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        msg&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; resp&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;choices&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;].&lt;/span&gt;&lt;span&gt;message&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        trajectory&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;tokens&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +=&lt;/span&gt;&lt;span&gt; resp&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;usage&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;total_tokens&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        trajectory&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;rounds&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if not&lt;/span&gt;&lt;span&gt; msg&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;tool_calls&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            trajectory&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;final_answer&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; msg&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;content&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            return&lt;/span&gt;&lt;span&gt; trajectory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        messages&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;msg&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        for&lt;/span&gt;&lt;span&gt; tc&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; in&lt;/span&gt;&lt;span&gt; msg&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;tool_calls&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            args&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; json&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;loads&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;arguments&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            result&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; TOOL_MAP&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;](&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;**&lt;/span&gt;&lt;span&gt;args&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            messages&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;({&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;tool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;tool_call_id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; tc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            trajectory&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;tool_calls&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;].&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;({&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; tc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;args&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; args&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; trajectory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# ── 2. 测试用例定义 ──&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color: #D08770;&quot;&gt;dataclass&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; TestCase&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    task&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    description&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    # 期望的条件（用于自动验证）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    expected_tools&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; list&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; field&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;default_factory&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;list&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  # 必须调用的工具&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    expected_tool_count&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; | None = None&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  # 期望的工具调用次数&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    forbidden_tools&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; list&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; field&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;default_factory&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;list&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  # 不能调用的工具&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;TEST_CASES&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    TestCase&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;weather_01&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        task&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;北京今天天气怎么样？&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        description&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;基本天气查询&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        expected_tools&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;get_weather&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        expected_tool_count&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        forbidden_tools&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;add_note&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;list_notes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    ),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    TestCase&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;weather_note_01&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        task&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;查一下上海天气，如果下雨就帮我记一条&amp;#39;带伞提醒&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        description&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;天气查询 + 条件性记便签&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        expected_tools&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;get_weather&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;add_note&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    ),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    TestCase&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;list_notes_01&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        task&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;我之前记了什么便签？&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        description&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;查看已存便签&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        expected_tools&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;list_notes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    ),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    TestCase&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;multi_city_01&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        task&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;北京、上海、深圳三个城市分别什么天气？&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        description&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;多城市天气查询&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        expected_tools&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;get_weather&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    ),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# ── 3. Rubric 评分表 ──&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; score_trajectory&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; TestCase&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; traj&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; dict&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; dict&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;多维度评分&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    scores&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    # 维度 1：工具选择正确性（0-4）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    called&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; for&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; in&lt;/span&gt;&lt;span&gt; traj&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;tool_calls&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    expected&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; set&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;expected_tools&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    forbidden&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; set&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;forbidden_tools&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    if&lt;/span&gt;&lt;span&gt; forbidden&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt; called&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        scores&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;tool_selection&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  # 调了不该调的&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    elif&lt;/span&gt;&lt;span&gt; expected&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; and&lt;/span&gt;&lt;span&gt; expected&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;issubset&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;called&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        scores&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;tool_selection&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    elif&lt;/span&gt;&lt;span&gt; expected&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; and&lt;/span&gt;&lt;span&gt; expected&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt; called&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        scores&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;tool_selection&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  # 部分正确&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    else&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        scores&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;tool_selection&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    # 维度 2：是否有最终答案（0-4）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    answer&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; traj&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;final_answer&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    if not&lt;/span&gt;&lt;span&gt; answer&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        scores&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;has_answer&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    elif&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; len&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;answer&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        scores&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;has_answer&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    else&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        scores&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;has_answer&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    # 维度 3：效率（0-4，只惩罚明显浪费）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    if not&lt;/span&gt;&lt;span&gt; traj&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;tool_calls&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        scores&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;efficiency&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    elif&lt;/span&gt;&lt;span&gt; tc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;expected_tool_count&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; and&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; len&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;traj&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;tool_calls&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;])&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;=&lt;/span&gt;&lt;span&gt; tc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;expected_tool_count&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        scores&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;efficiency&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    elif&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; len&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;traj&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;tool_calls&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;])&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;=&lt;/span&gt;&lt;span&gt; tc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;expected_tool_count&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; if&lt;/span&gt;&lt;span&gt; tc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;expected_tool_count&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; else&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; len&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;traj&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;tool_calls&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;])&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        scores&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;efficiency&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    else&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        scores&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;efficiency&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    # 维度 4：幻觉检测（否决项，0 或 4）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    # 简化检查：如果 Agent 提到了未调用工具获取的数据，标记&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    has_hallucination&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = False&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;get_weather&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; not in&lt;/span&gt;&lt;span&gt; called&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; and&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;天气&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; in&lt;/span&gt;&lt;span&gt; answer&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;lower&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; and&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;°C&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; in&lt;/span&gt;&lt;span&gt; answer&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        has_hallucination&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = True&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    scores&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;no_hallucination&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; if&lt;/span&gt;&lt;span&gt; has_hallucination&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; else&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    # 综合分（幻觉为否决项）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    if&lt;/span&gt;&lt;span&gt; scores&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;no_hallucination&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        scores&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;overall&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  # 有幻觉，总分归零&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    else&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        scores&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;overall&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; sum&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; for&lt;/span&gt;&lt;span&gt; k&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; v&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; in&lt;/span&gt;&lt;span&gt; scores&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;items&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; if&lt;/span&gt;&lt;span&gt; k&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; !=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;overall&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; /&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; scores&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# ── 4. 评测运行器 ──&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; run_evaluation&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;test_cases&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; list&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;TestCase&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;],&lt;/span&gt;&lt;span&gt; label&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&amp;quot;) -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; dict&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;运行完整评测，输出汇总报告&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    results&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; []&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    for&lt;/span&gt;&lt;span&gt; tc&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; in&lt;/span&gt;&lt;span&gt; test_cases&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;        print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;  运行 &lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;description&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;...&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; end&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot; &amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        traj&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; run_agent&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;task&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        scores&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; score_trajectory&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; traj&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        results&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;({&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;test_case&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; tc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;scores&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; scores&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;trajectory&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; traj&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;        print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;总分 &lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;scores&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;overall&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:.0f&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;/4&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    # 汇总统计&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    overall_scores&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; [&lt;/span&gt;&lt;span&gt;r&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;scores&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;][&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;overall&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; for&lt;/span&gt;&lt;span&gt; r&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; in&lt;/span&gt;&lt;span&gt; results&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    avg&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; sum&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;overall_scores&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; /&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; len&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;overall_scores&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    report&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; label&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;total_tests&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; len&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;test_cases&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;average_overall&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; round&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;avg&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;per_dimension&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            dim&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; round&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sum&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;r&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;scores&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;].&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;dim&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; for&lt;/span&gt;&lt;span&gt; r&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; in&lt;/span&gt;&lt;span&gt; results&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; /&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; len&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;results&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;),&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            for&lt;/span&gt;&lt;span&gt; dim&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; [&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;tool_selection&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;has_answer&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;efficiency&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;no_hallucination&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;details&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; results&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; report&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# ── 5. 回归对比 ──&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; compare_reports&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;before&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; dict&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; after&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; dict&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;对比两个评测报告&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n{&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;55&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;回归对比：&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;before&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;]&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; → &lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;after&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;]&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;55&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;维度&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&amp;lt;20&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;} {&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;之前&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&amp;gt;6&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;} {&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;之后&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&amp;gt;6&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;} {&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;变化&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&amp;gt;8&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 42&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    avg_before&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; before&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;average_overall&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    avg_after&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; after&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;average_overall&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    change&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; avg_after&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; -&lt;/span&gt;&lt;span&gt; avg_before&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    symbol&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;↑&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; if&lt;/span&gt;&lt;span&gt; change&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; else&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;↓&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; if&lt;/span&gt;&lt;span&gt; change&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; else&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;→&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;综合分&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&amp;lt;20&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;} {&lt;/span&gt;&lt;span&gt;avg_before&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&amp;gt;6.2f&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;} {&lt;/span&gt;&lt;span&gt;avg_after&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&amp;gt;6.2f&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;} {&lt;/span&gt;&lt;span&gt;symbol&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;} {&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;abs&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;change&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:.2f&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    for&lt;/span&gt;&lt;span&gt; dim&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; in&lt;/span&gt;&lt;span&gt; before&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;per_dimension&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        b&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; before&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;per_dimension&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;][&lt;/span&gt;&lt;span&gt;dim&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        a&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; after&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;per_dimension&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;][&lt;/span&gt;&lt;span&gt;dim&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        c&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; a&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; -&lt;/span&gt;&lt;span&gt; b&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        s&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;↑&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; if&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; else&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;↓&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; if&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; else&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;→&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;        print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;dim&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&amp;lt;20&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;} {&lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&amp;gt;6.2f&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;} {&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&amp;gt;6.2f&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;} {&lt;/span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;} {&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;abs&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:.2f&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    # 统计显著性提醒&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    n&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; before&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;total_tests&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; abs&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;change&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1.0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; /&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; **&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0.5&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;        print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;⚠️ 综合分变化 &lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;abs&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;change&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:.2f&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 在 &lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 个用例的噪声范围内（约±&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;/&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;**&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0.5&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:.1f&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;），建议扩大测试集或查看分维度详情。&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# ── 6. 跑起来 ──&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;if&lt;/span&gt;&lt;span&gt; __name__&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;__main__&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 55&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Agent 评测系统&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 55&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    # 基线评测&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;[基线评测]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    global&lt;/span&gt;&lt;span&gt; NOTES&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    NOTES&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;clear&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    baseline&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; run_evaluation&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;TEST_CASES&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; label&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;基线&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;基线综合分：&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;baseline&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;average_overall&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:.2f&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;/4&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    # 查看分维度得分&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;分维度得分：&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    for&lt;/span&gt;&lt;span&gt; dim&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; score&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; in&lt;/span&gt;&lt;span&gt; baseline&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;per_dimension&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;].&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;items&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;():&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;        print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;  {&lt;/span&gt;&lt;span&gt;dim&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;score&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:.2f&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;/4&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    # 模拟一次 Harness 改动：改系统提示词&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;--- 修改 Harness：简化系统提示词 ---&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    # 备份原始系统提示词，换一个更模糊的版本&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    import&lt;/span&gt;&lt;span&gt; copy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    original_tools&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; copy&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;deepcopy&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;TOOLS&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    # 测试改动后的 Agent（这里简化处理，实际会改系统提示）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    NOTES&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;clear&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    modified&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; run_evaluation&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;TEST_CASES&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; label&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;修改后（简化提示词）&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    # 回归对比&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    compare_reports&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;baseline&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; modified&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;💡 提示：n=&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;len&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;TEST_CASES&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 个用例只是 Demo 规模。&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;生产级评测系统至少需要 50-200 个覆盖各类场景和边界情况的用例。&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;yun-xing-xiao-guo&quot;&gt;运行效果&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=======================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Agent&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 评测系统&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=======================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;基线评测&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  运行&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; weather_01: 基本天气查询... 总分 4/4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  运行&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; weather_note_01: 天气查询 + 条件性记便签... 总分 4/4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  运行&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; list_notes_01: 查看已存便签... 总分 4/4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  运行&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; multi_city_01: 多城市天气查询... 总分 3/4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;基线综合分：3.75/4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;分维度得分：&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  tool_selection:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 4.00/4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  has_answer:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 4.00/4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  efficiency:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 3.00/4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  no_hallucination:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 4.00/4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=======================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;回归对比：基线&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; → 修改后（简化提示词）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=======================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;维度&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;                     之前     之后      变化&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;综合分&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;                   3.75   3.25&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;  ↓&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0.50&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tool_selection&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;          4.00   3.00&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;  ↓&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1.00&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;has_answer&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;              4.00   4.00&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;  →&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0.00&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;efficiency&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;              3.00   2.00&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;  ↓&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1.00&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;no_hallucination&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;        4.00   4.00&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;  →&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0.00&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;cong-demo-dao-sheng-chan-ji&quot;&gt;从 Demo 到生产级&lt;/h3&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;维度&lt;/th&gt;&lt;th&gt;我们的 Demo&lt;/th&gt;&lt;th&gt;生产级评测系统&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;用例数量&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;4 个&lt;/td&gt;&lt;td&gt;50-200+ 个，覆盖正常/边界/对抗场景&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;评分方式&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;固定规则&lt;/td&gt;&lt;td&gt;LLM-as-a-Judge + Rubric + 人工抽检校准&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;统计方法&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;简单均值&lt;/td&gt;&lt;td&gt;置信区间 + McNemar 配对检验&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;环境&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;本地单进程&lt;/td&gt;&lt;td&gt;Docker 容器化，可重置，并行执行&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;回归&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;手动对比&lt;/td&gt;&lt;td&gt;CI 集成，每次 PR 自动跑&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;数据污染&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;不适用&lt;/td&gt;&lt;td&gt;评测集严格隔离，参数化生成防止背题&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3 id=&quot;guan-jian-jing-yan&quot;&gt;关键经验&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;1. 幻觉要设否决项，不要混在评分里。&lt;/strong&gt; 一个流畅详细但编造了数据的回答，比一个简短准确的回答危害更大。幻觉和质量是两个正交维度。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. 小样本量下的评分差异不要过度解读。&lt;/strong&gt; 4 个用例上 0.5 分的差异可能是噪声。统计显著性的经验公式：变化需要超过约 2/√n 才值得认真对待。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. 评测集是活资产，不是一次性工程。&lt;/strong&gt; 每发现一个 Agent 搞错的场景，就把脱敏后的用例加进评测集。生产轨迹是最好的测试用例来源。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;zong-jie&quot;&gt;总结&lt;/h2&gt;
&lt;p&gt;今天我们讲了：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;评估是 Harness 的核心支柱&lt;/strong&gt;——评估对象是“模型 + Harness“组合体，不是模型本身。评估的首要价值是让你快速跟上模型演进。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SFT 教格式，RL 教策略&lt;/strong&gt;——SFT 像看教练开，RL 像自己开。大部分 Agent 应用不需要后训练，从 Harness 优化入手更高效。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;我们搭了一个评测小平台&lt;/strong&gt;——包含测试用例定义、多维度 Rubric 评分、回归对比。从这出发，加 LLM-as-a-Judge、加 CI 集成、加统计检验，就是生产级评测系统。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;xia-yi-qi-yu-gao&quot;&gt;下一期预告&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Agent 的未来：多模态、实时交互与多 Agent 协作&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Agent 不只活在对话框里——语音、视觉、GUI 操作、机器人控制，以及多个 Agent 如何协作。配套实战：两个 Agent 对话协作完成一个任务。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;em&gt;本文基于李博杰《&lt;a rel=&quot;external&quot; href=&quot;https://bojieli.github.io/ai-agent-book/&quot;&gt;深入理解 AI Agent&lt;/a&gt;》（Apache 2.0 协议）第 6-8 章内容改编，用费曼学习法重构为“概念 → 类比 → 动手“三段式教程。&lt;/em&gt;&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Agent 的未来：多模态、实时交互与多 Agent 协作</title>
        <published>2026-08-06T00:00:00+00:00</published>
        <updated>2026-08-06T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/ai-agent-series-05-future-multimodal/"/>
        <id>https://scp.net.cn/blog/ai-agent-series-05-future-multimodal/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/ai-agent-series-05-future-multimodal/">&lt;blockquote&gt;
&lt;p&gt;本文是 &lt;strong&gt;AI Agent 系列教程&lt;/strong&gt; 第 5 篇（完结篇）。基于李博杰《深入理解 AI Agent》第 9-10 章改编。前四篇讲清了 Agent 的基础概念、工具调用、记忆系统、评估进化。这一篇看向 Agent 正在走向的前沿。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;part-1-gai-nian-agent-tu-po-dui-hua-kuang&quot;&gt;Part 1：概念——Agent 突破对话框&lt;/h2&gt;
&lt;h3 id=&quot;san-tiao-qian-yan-zhan-xian&quot;&gt;三条前沿战线&lt;/h3&gt;
&lt;p&gt;Agent 正在同时往三个方向突破纯文本对话框：&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;方向&lt;/th&gt;&lt;th&gt;核心挑战&lt;/th&gt;&lt;th&gt;当前状态&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;语音 Agent&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;延迟 + 上下文保留&lt;/td&gt;&lt;td&gt;已有成熟产品（GPT-Live），全双工语音对话&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;GUI Agent&lt;/strong&gt;（Computer Use）&lt;/td&gt;&lt;td&gt;视觉理解 + 效率&lt;/td&gt;&lt;td&gt;能用但比人慢，效率是主要瓶颈&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;多 Agent 协作&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;通信、协调、错误传播&lt;/td&gt;&lt;td&gt;工程实践已广泛使用，但成本高（~15× token）&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;三条线有一个共同的约束：&lt;strong&gt;延迟敏感性。&lt;/strong&gt; 超过 500ms 的语音回复就像卡顿的电话，10 秒一次截屏的 GUI Agent 比人操作慢好几倍。&lt;/p&gt;
&lt;h3 id=&quot;yu-yin-agent-cong-chuan-lian-guan-dao-dao-quan-shuang-gong&quot;&gt;语音 Agent：从串联管道到全双工&lt;/h3&gt;
&lt;p&gt;最早的语音 Agent 是四步串联：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;VAD（等用户说完）→ ASR（语音转文字）→ LLM（文字推理）→ TTS（文字转语音）&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;每一步等上一步完成。总延迟 ≈ 1-2 秒，而且 VAD 要等 500-800ms 的“沉默“才能判断用户说完了——天然假设“一次一个人说话，说完等你回“。&lt;/p&gt;
&lt;p&gt;这个假设在真实对话中是错的。人会抢话、会犹豫、会边说边改。后来有三代进化：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第一代：流式优化。&lt;/strong&gt; 不等用户说完就开始处理——ASR 流式输出局部转写结果，LLM 基于部分文本“预判“回复。如果后面转写变了，取消重新生成。这叫“推测式生成“，把有效延迟压到用户话音刚落就开始回复。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第二代：端到端 Omni 模型。&lt;/strong&gt; 一个模型直接听音频，不用先转文字。优势是保留了语气、情绪、犹豫、环境音等副语言信息。但准确性不一定更好——当答案主要靠语义（如逻辑推理）时，先转文字再推理（self-cascade）反而可能更准。端到端的优势体现于依赖非语言线索的场景——比如用户说“我很好“，但声音在抖。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第三代：全双工模型。&lt;/strong&gt; 取消“轮次“概念。模型永远在听、永远能说。GPT-Live 每秒做一次决策：现在该说？该听？该打断？该停顿？Moshi 用“内心独白“文字流同步建模用户音频和模型音频，端到端延迟约 200ms。&lt;/p&gt;
&lt;h3 id=&quot;gui-agent-kan-ping-mu-cao-zuo-jie-mian&quot;&gt;GUI Agent：看屏幕、操作界面&lt;/h3&gt;
&lt;p&gt;Computer Use 的核心循环跟 ReAct 一样——只是“观察“变成了截图：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;截图 → 多模态模型输出&amp;quot;想什么 + 做什么&amp;quot; → 执行操作（点击、输入、滚动）→ 等界面响应 → 再截图&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Anthropic 给的参考工具集非常简洁：鼠标工具（移动、点击、双击、拖拽、滚动）、键盘工具（输入、组合键）、截图工具、观察工具（取光标位置、等待）。七个工具覆盖了桌面操作的主体场景。&lt;/p&gt;
&lt;p&gt;视觉定位有三种路线：结构元素索引（从 DOM/无障碍树提取可交互元素，标号贴标签——最准但依赖网页有结构）、视觉标注（用分割模型圈候选区域、贴数字标记——通用但慢）、纯坐标预测（模型直接从截图预测点击坐标——快但对训练分辨率敏感）。&lt;/p&gt;
&lt;p&gt;一个值得关注的发现：&lt;strong&gt;Agent 正确完成任务所花的步数比人多，而且随着上下文增长，每步延迟也在增加。&lt;/strong&gt; 准确性追上人类不等于实用——效率是真正的瓶颈。快慢分离架构（语音对话用轻量模型、屏幕操作用重型 VLM）让语音响应从 8.64 秒降到 0.58 秒，不降成功率。&lt;/p&gt;
&lt;h3 id=&quot;duo-agent-xie-zuo-shen-me-shi-hou-zhen-zheng-you-yong&quot;&gt;多 Agent 协作：什么时候真正有用？&lt;/h3&gt;
&lt;p&gt;多 Agent 的核心判断标准只有一条：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;协作过程是否引入了单个 Agent 在生成时无法获得的新信息？&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;协作方式&lt;/th&gt;&lt;th&gt;有新信息？&lt;/th&gt;&lt;th&gt;效果&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;同一模型自我审查&lt;/td&gt;&lt;td&gt;没有&lt;/td&gt;&lt;td&gt;通常无效甚至有害&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;不同 Agent 辩论同一段文字&lt;/td&gt;&lt;td&gt;没有&lt;/td&gt;&lt;td&gt;在相同算力预算下不优于单 Agent&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Reviewer 拿到了测试执行结果&lt;/td&gt;&lt;td&gt;&lt;strong&gt;有&lt;/strong&gt;（执行反馈）&lt;/td&gt;&lt;td&gt;显著提升&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Reviewer 拿到了渲染截图&lt;/td&gt;&lt;td&gt;&lt;strong&gt;有&lt;/strong&gt;（视觉反馈）&lt;/td&gt;&lt;td&gt;显著提升&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;这个洞察解释了为什么工程实践中的多 Agent 效果很好（因为 Reviewer 通常接了测试、截图、工具验证等外部反馈），而学术研究有时说“多 Agent 没用“（因为研究对比多是辩论模式，没有外部信息输入）。&lt;/p&gt;
&lt;h3 id=&quot;duo-agent-jia-gou-de-san-chong-tuo-bu&quot;&gt;多 Agent 架构的三种拓扑&lt;/h3&gt;
&lt;p&gt;从操作系统类比来看，Agent 系统非常像微内核结构：&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;操作系统&lt;/th&gt;&lt;th&gt;多 Agent 系统&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;程序（可执行文件）&lt;/td&gt;&lt;td&gt;静态前缀（系统提示词 + 工具定义）&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;进程内存&lt;/td&gt;&lt;td&gt;轨迹（对话历史）&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;CPU&lt;/td&gt;&lt;td&gt;LLM&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;fork&lt;/td&gt;&lt;td&gt;spawn_subagent&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;共享内存 / 消息传递&lt;/td&gt;&lt;td&gt;共享文件系统 / 消息队列&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;三种协作拓扑：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;编排模式（Orchestration）&lt;/strong&gt;：一个 Manager Agent 做计划、调度、结果整合，多个子 Agent 执⾏具体任务。关键是 Planner 要用最强模型——一个烂计划让所有子 Agent 白干。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;对等协作（Peer）&lt;/strong&gt;：两个 Agent 迭代改进。Proposer 生成，Reviewer 用外部验证（测试、截图、工具反馈）审查。核心价值不在“让同一个模型再想一遍“，而在引入生成时无法获得的信息。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;去中心化（Decentralized）&lt;/strong&gt;：没有中央调度器，Agent 之间通过对等传递接力。OpenAI Swarm 就是这种——每个 Agent 有路由选项，可以在网络中随时传递控制权。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;part-2-lei-bi-agent-de-wei-lai-xiang-yi-zhi-te-chong-xiao-dui&quot;&gt;Part 2：类比——Agent 的未来像一支特种小队&lt;/h2&gt;
&lt;h3 id=&quot;cong-dan-bing-dao-ban-pai&quot;&gt;从“单兵“到“班排“&lt;/h3&gt;
&lt;p&gt;之前四篇文章讲的都是&lt;strong&gt;个体 Agent&lt;/strong&gt;——就像一个刚入伍的士兵。他学会了用枪（工具）、看地图（上下文）、记信息（记忆）、接受评估（测试）。但真实的复杂任务需要一个团队。&lt;/p&gt;
&lt;p&gt;想象一支特种小队渗透任务：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;通讯兵&lt;/strong&gt;（语音 Agent）——跟后方保持实时联络，过滤噪音，转达关键信息&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;侦察兵&lt;/strong&gt;（GUI Agent）——操作无人机控制台，从复杂界面上提取目标坐标&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;作战组长&lt;/strong&gt;（Manager Agent）——接收各路线索，制定方案，分配任务&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;狙击手 + 观察手&lt;/strong&gt;（Proposer-Reviewer 对）——前者执行，后者确认环境条件和射击参数&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这就是多 Agent 协作的缩影：&lt;strong&gt;每个人都只看到自己需要看到的信息（上下文隔离），通过消息和共享文件系统交换结构化信息（不传全量轨迹），由组长基于外部验证结果做最终决策（不接受模型自称的“完成“）。&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;wei-shen-me-bie-chuan-quan-liang-gui-ji-zhe-me-zhong-yao&quot;&gt;为什么“别传全量轨迹“这么重要？&lt;/h3&gt;
&lt;p&gt;继续特种小队的类比：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;侦察兵看了一个小时的监控画面（长轨迹），向组长报告只需一句话：“目标在 3 号楼，2 个守卫，东侧有铁丝网”（结构化摘要）。&lt;/li&gt;
&lt;li&gt;如果侦察兵把他看过的每一帧监控截图都发给组长，组长就被淹没了。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;多 Agent 的通信就应该这样——&lt;strong&gt;传递结构化摘要，不是全量轨迹。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;而且进程传字节不会出错：字节就是字节。但 Agent 传语义会失真——侦察兵把“铁丝网“说成“围栏“，突击组就可能选错装备。这就是多 Agent 的“错误级联放大“问题，需要&lt;strong&gt;交叉验证&lt;/strong&gt;——不定期地，一个独立 Agent 绕开前人推理，直接核对原始证据。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;part-3-dong-shou-liang-ge-agent-dui-hua-xie-zuo&quot;&gt;Part 3：动手——两个 Agent 对话协作&lt;/h2&gt;
&lt;h3 id=&quot;wo-men-yao-zuo-shen-me&quot;&gt;我们要做什么&lt;/h3&gt;
&lt;p&gt;实现一个简化的 Proposer-Reviewer 模式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Proposer Agent&lt;/strong&gt;（“研究员”）：负责收集信息——查天气、搜索知识库&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reviewer Agent&lt;/strong&gt;（“编辑”）：审查 Proposer 的结论，用外部验证判断是否正确&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;两个 Agent 有&lt;strong&gt;独立上下文&lt;/strong&gt;，通过&lt;strong&gt;结构化消息&lt;/strong&gt;通信。&lt;/p&gt;
&lt;h3 id=&quot;wan-zheng-dai-ma&quot;&gt;完整代码&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span&gt; json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;from&lt;/span&gt;&lt;span&gt; dataclasses&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; import&lt;/span&gt;&lt;span&gt; dataclass&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;from&lt;/span&gt;&lt;span&gt; openai&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; import&lt;/span&gt;&lt;span&gt; OpenAI&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;client&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; OpenAI&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# ── 1. 共享状态（模拟共享文件系统） ──&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color: #D08770;&quot;&gt;dataclass&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; SharedState&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;两个 Agent 之间通过这个结构共享信息&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    task&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    proposer_findings&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; list&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;dict&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; | None = None&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  # Proposer 的发现&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    proposer_conclusion&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    reviewer_verdict&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  # &amp;quot;approved&amp;quot; | &amp;quot;needs_revision&amp;quot; | &amp;quot;rejected&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    reviewer_feedback&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    final_answer&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# ── 2. 工具定义 ──&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; get_weather&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;city&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    weather_db&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;北京&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;晴，24°C&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;上海&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;多云，28°C&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;深圳&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;雷阵雨，31°C&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;东京&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;晴，18°C&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; json&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;dumps&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;({&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;city&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; city&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;weather&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; weather_db&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;city&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;未找到&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; search_knowledge&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;query&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;模拟知识库搜索&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    kb&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;年假&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;公司年假政策：入职满一年 15 天带薪年假，未用完可延至次年 3 月底。&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;报销&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;差旅报销标准：高铁二等座、酒店 500 元/晚以内、餐补 100 元/天。&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Product X&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Product X 需在 2.4GHz Wi-Fi 下工作，红灯闪烁表示连接失败。&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    for&lt;/span&gt;&lt;span&gt; key&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; val&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; in&lt;/span&gt;&lt;span&gt; kb&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;items&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;():&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span&gt; key&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; in&lt;/span&gt;&lt;span&gt; query&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            return&lt;/span&gt;&lt;span&gt; val&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;未找到相关信息&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PROPOSER_TOOLS&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;get_weather&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;description&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;查询城市实时天气&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;parameters&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;object&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;properties&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;city&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;}}, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;required&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: [&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;city&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]}}},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;search_knowledge&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;description&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;搜索公司知识库&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;parameters&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;object&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;properties&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;}}, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;required&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: [&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]}}},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;REVIEWER_TOOLS&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;get_weather&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;description&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;查询城市实时天气（用于核实 Proposer 的结论）&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;parameters&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;object&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;properties&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;city&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;}}, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;required&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: [&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;city&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]}}},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;search_knowledge&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;description&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;搜索公司知识库（用于核实 Proposer 引用的政策）&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;parameters&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;object&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;properties&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;}}, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;required&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: [&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]}}},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;TOOL_MAP&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;get_weather&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; get_weather&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;search_knowledge&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; search_knowledge&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# ── 3. Agent 执行函数 ──&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; agent_run&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;system_prompt&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; user_task&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; tools&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; list&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; max_rounds&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 5&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) -&amp;gt;&lt;/span&gt;&lt;span&gt; tuple&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; list&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;通用 Agent 执行&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    messages&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; [{&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;system&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; system_prompt&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}, {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; user_task&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    tool_log&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; []&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    for&lt;/span&gt;&lt;span&gt; _&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; range&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;max_rounds&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        resp&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; client&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;chat&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;completions&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;create&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;model&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;gpt-4o-mini&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span&gt; messages&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt;messages&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; tools&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt;tools&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; tool_choice&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;auto&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        msg&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; resp&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;choices&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;].&lt;/span&gt;&lt;span&gt;message&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if not&lt;/span&gt;&lt;span&gt; msg&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;tool_calls&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            return&lt;/span&gt;&lt;span&gt; msg&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; tool_log&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        messages&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;msg&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        for&lt;/span&gt;&lt;span&gt; tc&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; in&lt;/span&gt;&lt;span&gt; msg&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;tool_calls&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            args&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; json&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;loads&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;arguments&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            result&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; TOOL_MAP&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;](&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;**&lt;/span&gt;&lt;span&gt;args&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            messages&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;({&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;tool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;tool_call_id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; tc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            tool_log&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;({&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;tool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; tc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;args&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; args&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;result_preview&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;80&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;达到最大轮数&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span&gt; tool_log&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# ── 4. Proposer-Reviewer 协作流程 ──&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; collaborator_loop&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;task&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) -&amp;gt;&lt;/span&gt;&lt;span&gt; SharedState&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    state&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; SharedState&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;task&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt;task&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    # 阶段 1：Proposer 收集信息 + 给出结论&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;[1/3] Proposer（研究员）开始收集信息...&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    proposer_prompt&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;你是研究员 Agent。收集信息后给出清晰结论。&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;- 查天气用 get_weather&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;- 查公司政策用 search_knowledge&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;- 结论用一段话概括，引用具体数据&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    conclusion&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; p_log&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; agent_run&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;proposer_prompt&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; task&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; PROPOSER_TOOLS&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    state&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;proposer_conclusion&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; conclusion&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    state&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;proposer_findings&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; p_log&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;  Proposer 调用了 &lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;len&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;p_log&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 次工具&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    for&lt;/span&gt;&lt;span&gt; entry&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; in&lt;/span&gt;&lt;span&gt; p_log&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;        print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;    🔧 &lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;entry&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;tool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;]&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;entry&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;args&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;]&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    # 阶段 2：Reviewer 审查（独立上下文，通过共享状态获取 Proposer 结论）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;[2/3] Reviewer（编辑）开始审查...&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    reviewer_prompt&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;你是编辑 Agent。审查以下研究员结论，核对其引用的数据。&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;审查流程：&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;1. 识别结论中提到的每个事实声明&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;2. 对每个声明，用 get_weather 或 search_knowledge 独立核实&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;3. 判断结论是否准确&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;4. 输出 JSON：{&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;verdict&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;approved|needs_revision|rejected&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;issues&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;问题1&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;, ...]}&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;不要修改结论本身——只审查。&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    review_task&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;原始任务：&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;task&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}\n\n&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;研究员结论：&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n{&lt;/span&gt;&lt;span&gt;conclusion&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}\n\n&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;请逐项核实上述结论中的事实声明，输出审查结果 JSON。&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    verdict_raw&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; r_log&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; agent_run&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;reviewer_prompt&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; review_task&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; REVIEWER_TOOLS&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;  Reviewer 调用了 &lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;len&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;r_log&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 次工具&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    for&lt;/span&gt;&lt;span&gt; entry&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; in&lt;/span&gt;&lt;span&gt; r_log&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;        print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;    🔧 &lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;entry&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;tool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;]&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;entry&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;args&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;]&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    # 解析 Reviewer 输出&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    try&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        # 尝试从输出中提取 JSON&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        import&lt;/span&gt;&lt;span&gt; re&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        json_match&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; re&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;search&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;r&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\{.&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;&amp;quot;verdict&amp;quot;.&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\}&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span&gt; verdict_raw&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; re&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;DOTALL&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span&gt; json_match&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            verdict_data&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; json&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;loads&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;json_match&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;group&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;())&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            state&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;reviewer_verdict&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; verdict_data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;verdict&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;unknown&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            state&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;reviewer_feedback&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;join&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;verdict_data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;issues&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, []))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        else&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            state&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;reviewer_verdict&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;parse_error&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            state&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;reviewer_feedback&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; verdict_raw&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;200&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    except&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        state&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;reviewer_verdict&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;parse_error&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        state&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;reviewer_feedback&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;verdict_raw&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)[:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;200&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    # 阶段 3：根据 Reviewer 结果，Proposer 修正（如果需要）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;[3/3] Reviewer 裁定: &lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;state&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;reviewer_verdict&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    if&lt;/span&gt;&lt;span&gt; state&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;reviewer_verdict&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;needs_revision&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; and&lt;/span&gt;&lt;span&gt; state&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;reviewer_feedback&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;        print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;  问题: &lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;state&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;reviewer_feedback&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        revision_task&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;你的上一轮结论需要修正。审查反馈：&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;state&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;reviewer_feedback&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}\n&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;请根据反馈重新收集信息，给出修正后的结论。&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        revised&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; _&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; agent_run&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;proposer_prompt&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; revision_task&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; PROPOSER_TOOLS&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        state&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;final_answer&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; revised&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;        print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;  Proposer 已提交修正版&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    else&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        state&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;final_answer&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; conclusion&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; state&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# ── 5. 跑起来 ──&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;if&lt;/span&gt;&lt;span&gt; __name__&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;__main__&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 55&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Proposer-Reviewer 多 Agent 协作&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 55&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    # 场景 1：Proposer 结论正确&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    state1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; collaborator_loop&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;明天去北京出差，查一下北京天气，顺便查一下差旅报销标准&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n{&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;55&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;最终裁定: &lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;state1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;reviewer_verdict&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;最终答案:&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n{&lt;/span&gt;&lt;span&gt;state1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;final_answer&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    # 场景 2：带误导信息的任务（测试 Reviewer 能否发现）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n{&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;55&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;场景 2：故意包含误导前提的任务&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    state2&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; collaborator_loop&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;我要去 Product X 发布会，查一下产品连接要求。对了，顺便查一下年假怎么算——我已经入职三年了。&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;最终裁定: &lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;state2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;reviewer_verdict&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    if&lt;/span&gt;&lt;span&gt; state2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;reviewer_feedback&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;        print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;审查反馈: &lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;{&lt;/span&gt;&lt;span&gt;state2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;reviewer_feedback&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;最终答案:&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n{&lt;/span&gt;&lt;span&gt;state2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;final_answer&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;yun-xing-xiao-guo&quot;&gt;运行效果&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=======================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Proposer-Reviewer&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 多 Agent 协作&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=======================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;1/3&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span&gt; Proposer（研究员）开始收集信息...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  Proposer&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 调用了&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 次工具&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    🔧&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; get_weather: {&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;city&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;北京&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    🔧&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; search_knowledge: {&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;差旅报销&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;2/3&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span&gt; Reviewer（编辑）开始审查...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  Reviewer&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 调用了&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 次工具&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    🔧&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; get_weather: {&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;city&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;北京&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    🔧&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; search_knowledge: {&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;差旅报销&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;3/3&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span&gt; Reviewer 裁定: approved&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=======================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;最终裁定:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; approved&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;最终答案:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;明天北京天气晴，24°C。差旅报销标准：高铁二等座、酒店&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 500&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 元/晚以内、餐补&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 100&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 元/天。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=======================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;场景&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 2：故意包含误导前提的任务&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=======================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;1/3&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span&gt; Proposer（研究员）开始收集信息...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  Proposer&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 调用了&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 次工具&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    🔧&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; search_knowledge: {&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Product X&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    🔧&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; search_knowledge: {&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;年假&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;2/3&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span&gt; Reviewer（编辑）开始审查...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  Reviewer&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 调用了&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 次工具&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    🔧&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; search_knowledge: {&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Product X&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    🔧&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; search_knowledge: {&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;年假&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;3/3&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span&gt; Reviewer 裁定: needs_revision&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  问题:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 年假政策引用正确，但需要明确入职三年与年假天数的关系&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  Proposer&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 已提交修正版&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;最终裁定:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; needs_revision&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;审查反馈:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 年假政策引用正确，但需要明确入职三年与年假天数的关系&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;最终答案:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Product&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; X 需要在 2.4GHz Wi-Fi 下工作，红灯闪烁表示连接失败...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;关于年假：您已入职三年，按照公司政策入职满一年即享有每年&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 15&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 天带薪年假。&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;guan-jian-she-ji-dian&quot;&gt;关键设计点&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;1. 上下文隔离。&lt;/strong&gt; Proposer 和 Reviewer 有各自独立的对话历史。Reviewer 看不到 Proposer 的推理过程——只看到“结论“。这阻止了 Reviewer 被 Proposer 的推理链“说服“——Reviewer 必须自己查数据。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. 外部验证驱动。&lt;/strong&gt; Reviewer 不是“再读一遍看有没有语病“，而是&lt;strong&gt;重新调工具验证每个事实声明&lt;/strong&gt;。这就是多 Agent 有效的前提——引入了 Proposer 生成时 Reviewer 无法获得的信息（独立工具调用结果）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. 修正闭环。&lt;/strong&gt; Reviewer 说 needs_revision 时，Proposer 拿到具体的反馈，重新收集信息后给出修正版。这个闭环是持续进化的基础——失败不是终点，是下一次迭代的输入。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;zong-jie-xi-lie-hui-gu&quot;&gt;总结：系列回顾&lt;/h2&gt;
&lt;p&gt;五篇文章，我们从零走到了 Agent 工程的前沿：&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;篇&lt;/th&gt;&lt;th&gt;主题&lt;/th&gt;&lt;th&gt;你学会了什么&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Agent 是什么&lt;/td&gt;&lt;td&gt;Agent = LLM + 上下文 + 工具。Harness 才是竞争力。&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;工具与 MCP&lt;/td&gt;&lt;td&gt;工具设计是工程活。描述写对了，模型差一点也能用对。&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;记忆与 RAG&lt;/td&gt;&lt;td&gt;记忆的难点不在存，在“正确的时机召回正确的内容“。&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;评估与进化&lt;/td&gt;&lt;td&gt;没有可执行验证的 Agent 是在猜谜。评估让你跟上模型演进。&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;多模态与协作&lt;/td&gt;&lt;td&gt;Agent 正在突破对话框。多 Agent 有效的关键是引入新信息。&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;如果只记一句话，记住这个：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Agent 不是魔法，是系统工程。模型决定上限，Harness 决定下限——而真正能用的是下限。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;关于“模型会不会吃掉 Harness“——源书后记给出答案：模型会不断内化 Harness 的功能，但 Harness 的边界也会不断外扩。就像编程语言从汇编演进到 Python，但软件工程不但没消失，反而更复杂了。&lt;strong&gt;Harness 工程才是核心竞争力。&lt;/strong&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;em&gt;本文基于李博杰《&lt;a rel=&quot;external&quot; href=&quot;https://bojieli.github.io/ai-agent-book/&quot;&gt;深入理解 AI Agent&lt;/a&gt;》（Apache 2.0 协议）第 9-10 章内容改编。整个系列用费曼学习法（概念 → 类比 → 动手）重构原书核心内容为 5 篇渐进教程。&lt;/em&gt;&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>LoopX 技术深度解析：为长程 AI Agent 构建可管理的本地控制面</title>
        <published>2026-08-06T00:00:00+00:00</published>
        <updated>2026-08-06T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/loopx-technical-deep-dive/"/>
        <id>https://scp.net.cn/blog/loopx-technical-deep-dive/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/loopx-technical-deep-dive/">&lt;p&gt;当一个需求需要横跨三天、三个会话、三个 Agent 才能完成时，“在 Chat 里写提示词“彻底不够用了。&lt;/p&gt;
&lt;p&gt;Codex、Claude Code、Cursor 这些 Agent Runtime 都很强，但它们共享一个根本局限：&lt;strong&gt;会话之间是割裂的&lt;/strong&gt;。Agent 不会自动记住“上一个 turn 我做了什么决定、为什么这样做、下一步应该谁来接手“。当你让它“继续“，它需要重新扫描上下文、重新推断状态，甚至重新犯同样的错。&lt;/p&gt;
&lt;p&gt;这就是 LoopX 要解决的核心问题。&lt;/p&gt;
&lt;h2 id=&quot;loopx-shi-shen-me&quot;&gt;LoopX 是什么？&lt;/h2&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/huangruiteng/loopx&quot;&gt;LoopX&lt;/a&gt; 是一个轻量级的&lt;strong&gt;本地控制面（Local Control Plane）&lt;/strong&gt;，专为长程 AI Agent 工作设计。它不替代 Agent Runtime——Agent 该写代码写代码，该调工具调工具——而是在 Runtime 之上叠加一层&lt;strong&gt;目标级状态管理层&lt;/strong&gt;，让以下六个维度跨轮次保持稳定：&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;维度&lt;/th&gt;&lt;th&gt;解决的问题&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Goal&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;“我们现在到底在做什么？”——目标的持久化身份&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Gate&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;“这一步需要人类判断吗？”——精确的审批入口&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Todo&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;“下一步谁该做什么？”——带 claim 和 lease 的任务卡片&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Evidence&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;“为什么做了这个决定？”——可审计的证据链&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Quota&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;“Agent 现在还能继续跑吗？”——算力配额调度&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Handoff&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;“上一个 Agent 干了什么？”——结构化的交接协议&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;一句话概括它的设计哲学：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;把会干活的 Agent，接成可管理、可复盘、可持续改进的数字员工。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;wen-ti-de-ben-zhi-chat-session-bu-shi-gong-cheng-kong-zhi-mian&quot;&gt;问题的本质：Chat Session 不是工程控制面&lt;/h2&gt;
&lt;p&gt;在深入 LoopX 之前，有必要先理解“传统 Chat Agent“为什么不够用。&lt;/p&gt;
&lt;p&gt;当你用 Claude Code 或 Codex CLI 做一个跨越数天的工程任务时，你会遇到这些典型痛点：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;目标漂移（Goal Drift）&lt;/strong&gt;。第一天你说“重构用户服务“，第三天 Agent 可能已经偏离到优化数据库索引——因为没有持久化的目标边界，每次恢复会话时 Agent 重新“理解“目标，理解可能每次都不一样。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;决策不可追溯（Decision Amnesia）&lt;/strong&gt;。Agent 在 turn 3 选择方案 A 而非方案 B，原因是权衡了 A 的风险更低。到 turn 20 时，这个决策依据已经消失在聊天记录深处。如果后面发现方案 A 导致了新问题，没人记得当初为什么选它。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;交接混乱（Handoff Chaos）&lt;/strong&gt;。Agent A 修了一个 bug，Agent B 负责 review，Agent C 负责合并。三个 Agent 之间靠“口耳相传“（把上下文塞进 prompt），而不是靠结构化的状态交接。一旦中间有信息丢失，整个链路就会断裂。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;无限循环（Runaway Loop）&lt;/strong&gt;。Agent 在某个子问题上反复尝试，消耗大量 token 却没有实质进展。没有配额机制来中止无效循环。&lt;/p&gt;
&lt;p&gt;LoopX 的应对思路很清晰：&lt;strong&gt;不靠“把更多上下文塞进 prompt“，而是靠“把关键状态持久化到本地文件系统“&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;它的核心 tick 循环只有五步：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;┌──────────────────────────────────────────────────┐&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│  loopx quota should-run   ← Agent 现在能跑吗？    │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│  loopx todo claim         ← 这个 slice 谁认领？   │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│  loopx todo update        ← 执行后发生了什么？    │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│  loopx refresh-state      ← 下一轮应该看到什么？  │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│  loopx quota spend-slot   ← 为已完成的 slice 记账 │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;└──────────────────────────────────────────────────┘&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;每一步都写入文件，每一轮都是 &lt;strong&gt;bounded turn&lt;/strong&gt;——有限边界的一次执行，而非无限制的自主权。&lt;/p&gt;
&lt;h2 id=&quot;jia-gou-si-ceng-zhi-ze-fen-chi-liu-ceng-chi-jiu-hua&quot;&gt;架构：四层职责分离 + 六层持久化&lt;/h2&gt;
&lt;p&gt;LoopX 的设计中最值得学习的是它严格的&lt;strong&gt;职责分离&lt;/strong&gt;。很多 Agent 框架会把 Planning、工具调用、状态管理和调度耦合在一起，导致任何一个环节的变化都会影响全局。LoopX 则明确定义了四层：&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;角色&lt;/th&gt;&lt;th&gt;职责&lt;/th&gt;&lt;th&gt;明确不拥有&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Agent&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Planning、分析、工具使用、一轮有界执行&lt;/td&gt;&lt;td&gt;持久化目标生命周期&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Capability&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;标准化输出、领域策略验证、typed transition 提案&lt;/td&gt;&lt;td&gt;持久化调度&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Provider&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;外部调用、有限观察、效果结果&lt;/td&gt;&lt;td&gt;领域转换策略&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Kernel&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Goal、Todo、Claim、Gate、Quota、写回、恢复、调度&lt;/td&gt;&lt;td&gt;领域推理&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;这种分离的好处是：&lt;strong&gt;每一层都可以独立演进&lt;/strong&gt;。你可以替换 Agent Runtime（从 Codex 切到 Claude Code），无需改动 Capability 和 Kernel；你可以新增一个 &lt;code&gt;pr-review-queue&lt;/code&gt; Capability，不碰 Agent 和 Provider；你可以调整 Quota 策略，不影响任何业务逻辑。&lt;/p&gt;
&lt;p&gt;在存储层面，LoopX 使用六个本地持久化层（注意：不是六个数据库，而是六类结构化文件）：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Registry&lt;/strong&gt;：已知目标、repos、adapters、权限源的登记表&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Goal State&lt;/strong&gt;：单个目标的活跃状态文件（Objective、Scope、Authority、Gates、Evidence）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Run Log&lt;/strong&gt;：JSON 和 Markdown 格式的执行报告&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Run History&lt;/strong&gt;：Agent/heartbeat/UI 消费的紧凑索引&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Status / Attention Queue&lt;/strong&gt;：首屏摘要，回答“现在卡在哪？谁需要做什么？“&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Compute Quota&lt;/strong&gt;：每个目标的算力消耗本地策略&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;全部使用本地 JSON/Text 文件，零服务依赖，零数据库。这个选择是深思熟虑的：对于一个本地控制面而言，文件系统的可靠性、可审计性和可备份性，比分布式数据库的性能和一致性更重要。&lt;/p&gt;
&lt;h2 id=&quot;gate-bu-shi-deng-lao-ban-shen-pi-er-shi-qing-hui-da-zhe-ge-ju-ti-wen-ti&quot;&gt;Gate：不是“等老板审批“，而是“请回答这个具体问题“&lt;/h2&gt;
&lt;p&gt;LoopX 最让我印象深刻的设计是它的 &lt;strong&gt;User Gate&lt;/strong&gt; 机制。&lt;/p&gt;
&lt;p&gt;很多工具在需要人类介入时，只会抛出一个模糊的状态：&lt;code&gt;status: pending_review&lt;/code&gt;，然后 agent 就停在那里，等人类来猜“你到底要我 review 什么？“&lt;/p&gt;
&lt;p&gt;LoopX 的 Gate 完全不同：&lt;strong&gt;每个 gate 必须是一个精确的、可回答的具体问题&lt;/strong&gt;。&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;❌ 模糊 gate：&amp;quot;等待审核&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;✅ 精确 gate：&amp;quot;请确认是否接受这个 diff 的改动范围？改动涉及 3 个文件、12 行新增、4 行删除。Y/N&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;❌ 模糊 gate：&amp;quot;需要 owner 决策&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;✅ 精确 gate：&amp;quot;API 返回的字段名用 camelCase 还是 snake_case？当前代码库 80% 用 snake_case，但新增的服务用 camelCase。请选择统一标准。&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这不是一个措辞上的小改进，而是一个&lt;strong&gt;设计哲学的根本差异&lt;/strong&gt;。当 Gate 是精确问题时：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;人类做决策的成本大幅降低&lt;/strong&gt;——不用翻代码、不用理上下文，只需要回答一个具体问题&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Agent 不会在 gate 前空转&lt;/strong&gt;——它知道自己在等什么答案，也知道拿到答案后下一步该做什么&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;状态可审计&lt;/strong&gt;——每个 gate 的提出、等待、响应都有记录，构成了完整的决策链&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这背后是一个重要的认知：&lt;strong&gt;把人类从“被动兜底“变成“主动决策点“&lt;/strong&gt;。传统 human-in-the-loop 的问题是，人类被当作异常情况的兜底机制——只有 agent 搞不定了才找人。LoopX 的思路则是把人类判断设计成工作流中的正常步骤，并且降低这个步骤的认知负担。&lt;/p&gt;
&lt;h2 id=&quot;quota-gei-agent-zhuang-shang-suan-li-yu-suan&quot;&gt;Quota：给 Agent 装上“算力预算“&lt;/h2&gt;
&lt;p&gt;另一个实用到让人拍大腿的设计是 &lt;strong&gt;Quota（算力配额）&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;没有 Quota 的 Agent 像一个没有预算的实习生：可以无限消耗 token 在一个问题上反复尝试，直到有人手动叫停。LoopX 的 Quota 做了几件很聪明的事：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;预检查，而非事后审计&lt;/strong&gt;。每个自动 turn 开始前，必须先跑 &lt;code&gt;loopx quota should-run&lt;/code&gt;。如果配额不足，直接跳过，不消耗任何 token。这避免了“先跑完再发现不应该跑“的浪费。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;区分消耗与不消耗&lt;/strong&gt;。静默跳过、preflight 失败、dry-run preview 不消耗配额。只有实际执行并验证完成的 slice 才消耗配额。这防止了“报错重试消耗大量配额“的问题。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;可观测、可调整&lt;/strong&gt;。你可以随时查看配额的分配和使用情况，也可以根据进展手动调整——进展顺利就加配额，方向不对就减配额。&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;loopx&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; quota should-run --goal-id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;i&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  # 预检查&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;loopx&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; quota show --goal-id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;i&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        # 查看分配&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;loopx&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; quota set --goal-id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;i&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; --max-ticks&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 100&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  # 手动调整&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;loopx&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; quota spend-slot --goal-id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;i&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; --run-id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;i&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  # 记账&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这种设计让 Agent 的“自主权“有了硬边界。它不是靠“相信 Agent 会自觉“，而是靠&lt;strong&gt;机制保证&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id=&quot;nei-zhi-neng-li-yu-bu-shi-kuang-jia-shi-ke-fu-yong-mo-kuai&quot;&gt;内置能力域：不是框架，是可复用模块&lt;/h2&gt;
&lt;p&gt;LoopX 内置了多个现成的能力模块（Capabilities），覆盖了常见的 AI Agent 工作流场景：&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;能力&lt;/th&gt;&lt;th&gt;功能&lt;/th&gt;&lt;th&gt;成熟度&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;issue-fix&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;GitHub Issue → 本地分支 → PR review readiness&lt;/td&gt;&lt;td&gt;活跃&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;content-ops&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;内容运营：公开信源 + 私有 owner gate 聚合&lt;/td&gt;&lt;td&gt;活跃&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;pr-review-queue&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;自动观察 GitHub PR 队列，推进精确 head&lt;/td&gt;&lt;td&gt;活跃&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;change-quality&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;精确范围的变更质量审查 + bounded repair&lt;/td&gt;&lt;td&gt;活跃&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;explore&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;探索图：hypothesis → finding → evidence 拓扑&lt;/td&gt;&lt;td&gt;活跃&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;value-connectors&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;外部渠道摄入（收入、成本、需求信号）&lt;/td&gt;&lt;td&gt;活跃&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;integration-branch&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;本地集成分支对齐，不改源分支&lt;/td&gt;&lt;td&gt;活跃&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;auto-research&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Proposer/Executor/Evaluator 并行研究&lt;/td&gt;&lt;td&gt;实验性&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;ml-experiment&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;ML 实验建议&lt;/td&gt;&lt;td&gt;实验性&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;reward-memory&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;上下文学习&lt;/td&gt;&lt;td&gt;实验性（默认关闭）&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;注意一个重要的设计选择：&lt;strong&gt;大多数能力默认关闭&lt;/strong&gt;（&lt;code&gt;default_enabled: False&lt;/code&gt;），需要显式启用。这不只是“安全考虑“，更体现了一个原则：控制面不应该替你做决定。你觉得什么能力对当前目标有用，就启用什么。&lt;/p&gt;
&lt;p&gt;这些能力模块遵循统一的扩展架构：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Extension&lt;/strong&gt; 是 Provider 的打包单位，通过 Capability 契约注册&lt;/li&gt;
&lt;li&gt;Extension 有完整的安装/启用/禁用/升级生命周期&lt;/li&gt;
&lt;li&gt;内置（builtin）和外部扩展使用同一套 Provider 注册机制&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;agent-runtime-qiao-jie-bu-bang-ding-ren-he-yi-jia&quot;&gt;Agent Runtime 桥接：不绑定任何一家&lt;/h2&gt;
&lt;p&gt;LoopX 支持多种主流 Agent Runtime 的桥接，不绑定任何特定平台：&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Host&lt;/th&gt;&lt;th&gt;启动方式&lt;/th&gt;&lt;th&gt;Loop Driver&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Codex App&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;loopx agent-onboard --agent-type codex-app&lt;/code&gt;&lt;/td&gt;&lt;td&gt;App 心跳自动化&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Codex CLI&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;codex&lt;/code&gt; 在项目中，使用 &lt;code&gt;/goal&lt;/code&gt;&lt;/td&gt;&lt;td&gt;可见 &lt;code&gt;/goal &amp;lt;task_body&amp;gt;&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Claude Code&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;安装 adapter，使用 &lt;code&gt;/loopx&lt;/code&gt;&lt;/td&gt;&lt;td&gt;原生 &lt;code&gt;/loop&lt;/code&gt; + LoopX 门控&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;OpenCode&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;command facade + goal bridge&lt;/td&gt;&lt;td&gt;OpenCode command facade&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;自定义 Runner&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Worker Bridge 协议&lt;/td&gt;&lt;td&gt;自定义集成&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;这种设计体现了 LoopX 对自身的定位：&lt;strong&gt;它不替代 Runtime，也不绑定 Runtime&lt;/strong&gt;。它是一个架在 Runtime 之上的控制层，无论你用哪个 Agent，控制面的逻辑是同一套。&lt;/p&gt;
&lt;h2 id=&quot;shi-jian-qing-dan-zen-me-cong-ling-jie-ru-loopx&quot;&gt;实践清单：怎么从零接入 LoopX&lt;/h2&gt;
&lt;p&gt;如果你是第一次尝试，以下是推荐的接入步骤：&lt;/p&gt;
&lt;h3 id=&quot;1-an-zhuang-yu-yan-zheng&quot;&gt;1. 安装与验证&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -fsSL https://raw.githubusercontent.com/huangruiteng/loopx/main/scripts/install-from-github.sh&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; bash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;export&lt;/span&gt;&lt;span&gt; PATH&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;/.local/bin:&lt;/span&gt;&lt;span&gt;$PATH&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;loopx&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; doctor&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;2-lian-jie-xiang-mu&quot;&gt;2. 连接项目&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /path/to/your-project&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;loopx&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; connect&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;loopx&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; status&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  # 验证连接&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;3-an-quan-jian-cha&quot;&gt;3. 安全检查&lt;/h3&gt;
&lt;p&gt;三个必须加入 &lt;code&gt;.gitignore&lt;/code&gt; 的路径（防止运行时状态泄露到公共仓库）：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;.loopx/        # 运行时状态&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;.codex/goals/  # goal 状态&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;.local/        # 本地私有状态&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;提交前检查：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;loopx&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; check --scan-path README.md --scan-path docs/ --scan-path examples/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;4-huan-dao-loopx-zheng-que-zi-shi-checklist&quot;&gt;4. 换到 LoopX 正确姿势 checklist&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
&lt;code&gt;loopx doctor&lt;/code&gt; 全部通过&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
项目有 &lt;code&gt;.loopx/registry.json&lt;/code&gt; 和 active goal projection&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
&lt;code&gt;loopx status&lt;/code&gt; 显示当前目标、具体 user gate 和下一条 agent todo&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
有可见的 Loop driver，或 Agent 给出精确 activation 指令&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
&lt;code&gt;.gitignore&lt;/code&gt; 中已添加三个必需路径&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;gua-yong-chang-jing-shen-me-shi-hou-gai-yong-loopx&quot;&gt;适用场景：什么时候该用 LoopX？&lt;/h2&gt;
&lt;h3 id=&quot;fei-chang-gua-he-de-chang-jing&quot;&gt;非常适合的场景&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;多天/多周的工程、研究、benchmark 目标&lt;/strong&gt;：需要跨会话保持状态、证据和决策记录&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;跨多轮跨 Agent 的 issue/PR Loop&lt;/strong&gt;：多人/多 Agent 协作，需要结构化的交接&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;带安全门控的项目&lt;/strong&gt;：有 owner、safety、publication 或私有数据 gate&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;需要向非技术用户呈现进度的场景&lt;/strong&gt;：Gate 和 Status 可以让你随时回答“现在什么状态？卡在哪里？需要我做什么？“&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Peer Agent 团队协作&lt;/strong&gt;：需要 ownership、lease 和 handoff 可见性&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;bu-gua-he-de-chang-jing&quot;&gt;不适合的场景&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;单次会话的简单任务&lt;/strong&gt;：LoopX 的抽象层在这种场景下是过度设计，直接用 Agent 即可&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;实时多人协作的工单系统&lt;/strong&gt;：LoopX 是本地文件存储，不做并发冲突处理&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;生产环境自动化控制&lt;/strong&gt;：危险权限和破坏性操作应该由人类直接负责&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;需要外部数据库持久化的场景&lt;/strong&gt;：LoopX 是本地优先的控制面，不适合需要集中式状态存储的场景&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;yu-lei-si-gong-ju-de-guan-xi&quot;&gt;与类似工具的关系&lt;/h2&gt;
&lt;p&gt;一个重要的问题：LoopX 和 LangChain、AutoGPT、CrewAI 这类 Agent 框架是什么关系？&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;它们不是竞争关系，而是在不同层面上工作&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;LangChain / AutoGPT / CrewAI 是 Agent 框架——它们关心的是“如何构建一个能执行任务的 Agent“：prompt 模板、tool 定义、chain/orchestration、memory。它们是 LoopX 架构图中 &lt;strong&gt;Agent 层&lt;/strong&gt; 的东西。&lt;/p&gt;
&lt;p&gt;LoopX 是控制面——它关心的是“如何管理 Agent 的执行过程“：这个 Goal 现在什么状态？下一步该谁做？配额够不够？人类需要决策什么？它是架在 Agent 上方的治理层。&lt;/p&gt;
&lt;p&gt;换句话说：&lt;strong&gt;你可以用 LangChain 构建 Agent，用 LoopX 管理这个 Agent 的长程行为&lt;/strong&gt;。两者是互补的。&lt;/p&gt;
&lt;h2 id=&quot;ju-xian-xing-loopx-ming-que-bu-zuo-shen-me&quot;&gt;局限性：LoopX 明确不做什么&lt;/h2&gt;
&lt;p&gt;LoopX 的文档里有一个我很欣赏的部分：一个清晰的“do-not“清单。&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;不是 Agent Runtime&lt;/strong&gt;：不执行代码、不调用工具、不做 planning&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;不是生产自动化控制器&lt;/strong&gt;：危险权限、生产写入、公开发布由人类负责&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;不 grant credentials&lt;/strong&gt;：不授予权限、不批准破坏性操作&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;不是自治决策者&lt;/strong&gt;：quota 可以停止循环，但不能自主批准越过 gate&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;不处理裸机部署&lt;/strong&gt;：专注本地/开发环境控制面&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;不支持实时多人协作&lt;/strong&gt;：本地文件存储，不做并发冲突处理&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;不提供 UI&lt;/strong&gt;：只有 CLI 和可选的本地 dashboard&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;这种“先说清楚我不做什么“的姿态，在开源项目里并不多见。它体现了一种工程上的诚实：每个工具都有它的边界，明确边界比假装全能更有用。&lt;/p&gt;
&lt;h2 id=&quot;zong-jie&quot;&gt;总结&lt;/h2&gt;
&lt;p&gt;LoopX 解决的核心问题是：&lt;strong&gt;让 AI Agent 从“一次性的 chat session“变成“可管理、可复盘、可持续改进的数字员工“&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;它通过五个机制来实现：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;持久化的 Goal&lt;/strong&gt;：目标不随会话结束而消失&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Typed 的 Todo + Gate&lt;/strong&gt;：任务有明确的类型和状态机，决策点有精确的人类审批入口&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;可审计的 Evidence&lt;/strong&gt;：每次转变有记录，失败可追踪，决策可复盘&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Quota 控制的调度&lt;/strong&gt;：Agent 的自主权有硬边界，不是“相信它会自觉“&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;结构化的 Handoff&lt;/strong&gt;：Agent 之间通过状态交接，不靠口耳相传&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;LoopX 仍在活跃开发中（当前 v0.4.x），但它的设计思想——&lt;strong&gt;控制面与执行面分离、人类判断设计成正常步骤而非异常兜底、配额作为自主权的硬边界&lt;/strong&gt;——对于任何在认真思考“如何让 AI Agent 在工程团队里持续工作“的人来说，都值得深入了解。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Keep the loop moving. Keep the judgment human.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;em&gt;本文基于 LoopX v0.4.x 编写。参考来源：&lt;a rel=&quot;external&quot; href=&quot;https://github.com/huangruiteng/loopx/blob/main/AGENTS.md&quot;&gt;AGENTS.md&lt;/a&gt;、&lt;a rel=&quot;external&quot; href=&quot;https://github.com/huangruiteng/loopx/blob/main/docs/architecture.md&quot;&gt;Architecture&lt;/a&gt;、&lt;a rel=&quot;external&quot; href=&quot;https://github.com/huangruiteng/loopx/blob/main/docs/quota-allocation.md&quot;&gt;Quota Allocation&lt;/a&gt;、&lt;a rel=&quot;external&quot; href=&quot;https://github.com/huangruiteng/loopx/blob/main/docs/reference/extensions.md&quot;&gt;Extensions&lt;/a&gt;、&lt;a rel=&quot;external&quot; href=&quot;https://github.com/huangruiteng/loopx/blob/main/docs/integrations/worker-bridge-install-contract.md&quot;&gt;Worker Bridge&lt;/a&gt;。&lt;/em&gt;&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Pi Agent 是什么？——极简内核、四层洋葱与一个能跑的 Agent Loop</title>
        <published>2026-08-06T00:00:00+00:00</published>
        <updated>2026-08-06T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/pi-agent-series-01-what-is-pi/"/>
        <id>https://scp.net.cn/blog/pi-agent-series-01-what-is-pi/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/pi-agent-series-01-what-is-pi/">&lt;blockquote&gt;
&lt;p&gt;本文是 &lt;strong&gt;Pi Agent 系列教程&lt;/strong&gt;第 1 篇。基于张汉东《&lt;a rel=&quot;external&quot; href=&quot;https://zhanghandong.github.io/pi-book/&quot;&gt;pi 的设计艺术&lt;/a&gt;》（CC BY-NC-SA 4.0）改编，用费曼学习法（概念 → 类比 → 动手）带你从零理解 Pi 的架构设计。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;如果你用过 Claude Code 或 Cursor，你可能想过一个问题：&lt;strong&gt;“从敲下回车到 Agent 开始干活，这中间到底发生了什么？”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;大多数人会说“调了 LLM API“。但真正有意思的部分不是“调 API“——而是&lt;strong&gt;调完 API 之后&lt;/strong&gt;。应该继续干还是停下？用户打断了怎么办？上下文快满了怎么办？工具调超时了怎么办？&lt;/p&gt;
&lt;p&gt;这些问题没有一个能用一次 API 调用解决。它们需要的是一台发动机——持续运转的决策引擎。Pi 把这件事做到极致，把发动机拆到只剩最关键的一个零件：&lt;strong&gt;Agent Loop&lt;/strong&gt;。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;part-1-gai-nian-pi-dao-di-shi-shen-me&quot;&gt;Part 1：概念——Pi 到底是什么？&lt;/h2&gt;
&lt;h3 id=&quot;ta-bu-shi-shen-me&quot;&gt;它不是什么&lt;/h3&gt;
&lt;p&gt;先澄清一个常见的误解。Pi 不是“又一个 LLM 包装器“。LangChain、Vercel AI SDK 解决的核心问题是“怎么调 LLM“——怎么封装 API、怎么处理流式、怎么切换厂商。它们做的是一件很重要的事，但不是 Pi 做的事。&lt;/p&gt;
&lt;p&gt;Pi 解决的核心问题是：&lt;strong&gt;“调完 LLM 之后发生什么？”&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;问题&lt;/th&gt;&lt;th style=&quot;text-align: center&quot;&gt;包装器能解决吗？&lt;/th&gt;&lt;th&gt;Pi 怎么解决？&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;调 20 家 LLM 厂商用统一接口&lt;/td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✅&lt;/td&gt;&lt;td&gt;&lt;code&gt;pi-ai&lt;/code&gt; 层的 Provider Registry&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Agent 应该继续干还是停下？&lt;/td&gt;&lt;td style=&quot;text-align: center&quot;&gt;❌&lt;/td&gt;&lt;td&gt;Agent Loop 的 &lt;code&gt;while(true)&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;用户按了 Ctrl+C 怎么办？&lt;/td&gt;&lt;td style=&quot;text-align: center&quot;&gt;❌&lt;/td&gt;&lt;td&gt;AbortSignal 贯穿全部异步操作&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;上下文窗口快满了怎么办？&lt;/td&gt;&lt;td style=&quot;text-align: center&quot;&gt;❌&lt;/td&gt;&lt;td&gt;&lt;code&gt;transformContext&lt;/code&gt; 回调&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;多个工具调用怎么编排？&lt;/td&gt;&lt;td style=&quot;text-align: center&quot;&gt;❌&lt;/td&gt;&lt;td&gt;工具执行管线（prepare → execute → finalize）&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;会话怎么分支回退？&lt;/td&gt;&lt;td style=&quot;text-align: center&quot;&gt;❌&lt;/td&gt;&lt;td&gt;会话树（parentId 模型） + Compaction&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Pi 是&lt;strong&gt;运行时（Runtime）&lt;/strong&gt;，不是框架（Framework）。框架倒置控制权——你填骨架槽位。运行时提供执行环境——你保留控制流。&lt;/p&gt;
&lt;h3 id=&quot;si-ceng-yang-cong-jia-gou&quot;&gt;四层洋葱架构&lt;/h3&gt;
&lt;p&gt;Pi 的架构是一颗严格执行向内依赖规则的洋葱：每一层只知道下一层的存在。&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;┌──────────────────────────────────────┐&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│  第 4 层：产品外壳                      │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│  pi-tui / mom(Slack) / web-ui / RPC   │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├──────────────────────────────────────┤&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│  第 3 层：产品内核 (pi-coding-agent)    │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│  会话树、Compaction、System Prompt 组装  │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│  130+ 工具实现、Extension/Skill 系统    │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├──────────────────────────────────────┤&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│  第 2 层：循环引擎 (pi-agent-core)      │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│  agentLoop()、Agent 类、事件系统         │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│  仅 5 个源文件、约 1,900 行              │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├──────────────────────────────────────┤&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│  第 1 层：统一调用面 (pi-ai)             │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│  20+ Provider 适配、事件流归一化          │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;└──────────────────────────────────────┘&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;第 1 层 &lt;code&gt;pi-ai&lt;/code&gt;：&lt;/strong&gt; 把 Anthropic、OpenAI、Google、AWS Bedrock 等 20+ 家 LLM 厂商的 API 差异全部吸收。上层永远看到统一的 &lt;code&gt;AssistantMessage&lt;/code&gt; 和统一的事件流（&lt;code&gt;text-delta&lt;/code&gt;、&lt;code&gt;tool-call-delta&lt;/code&gt;、&lt;code&gt;usage&lt;/code&gt;），永远不需要知道底层是哪家厂商。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第 2 层 &lt;code&gt;pi-agent-core&lt;/code&gt;：&lt;/strong&gt; 这颗“心脏“只有 5 个文件、不到 2000 行代码。它只做一件事——跑循环。循环引擎是&lt;strong&gt;无状态&lt;/strong&gt;的——消息列表、工具定义、配置全是调用者传入的，引擎自己什么都不持有。这使得同一份引擎可以被 CLI、Slack Bot、Web UI、测试 Harness 不加修改地复用。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第 3 层 &lt;code&gt;pi-coding-agent&lt;/code&gt;：&lt;/strong&gt; 把一个通用 Agent 引擎变成一个具体的编程助手。包含会话树（支持分支）、Compaction（上下文压缩）、System Prompt 组装、Extension/Skill 系统、以及 130+ 个工具实现。这一层是代码量最大的——约 42,000 行，占项目近一半。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第 4 层：&lt;/strong&gt; 面向用户的产品形态——终端 TUI（35+ 组件）、Slack Bot（mom）、Web UI、RPC 模式。所有产品共用前三层。&lt;/p&gt;
&lt;h3 id=&quot;agent-loop-fa-dong-ji-de-he-xin&quot;&gt;Agent Loop：发动机的核心&lt;/h3&gt;
&lt;p&gt;Agent Loop 的代码本质上就是一个 while 循环：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;while (任务没完成) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. 把&amp;quot;系统提示 + 工具列表 + 完整对话历史&amp;quot;发给 LLM&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. 看 LLM 返回什么&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       - 如果是不调工具的文本 → 任务完成，退出&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       - 如果是工具调用 → 执行工具 → 把结果追加到对话历史 → 回到第 1 步&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但 pi 的设计加了一个关键的复杂度：&lt;strong&gt;双层嵌套循环&lt;/strong&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;内层循环&lt;/strong&gt;：驱动持续工作——调 LLM → 执行工具 → 检查引导消息 → 再调 LLM&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;外层循环&lt;/strong&gt;：处理“唤醒“——当内层循环结束（Agent 本应停止时），检查有没有后续消息。如果有，重新启动内层循环&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;“引导“和“后续“语义不同：&lt;strong&gt;引导&lt;/strong&gt;是“用户在工作途中插话”（如“换个思路做“），在当前工具执行完后立即注入，下一次 LLM 调用时生效。&lt;strong&gt;后续&lt;/strong&gt;是“用户等 Agent 做完之后再追加新任务“（如“好了，现在写测试“），只在 Agent 即将退出时才消费。&lt;/p&gt;
&lt;h3 id=&quot;wei-shen-me-yao-fen-zhe-me-duo-ceng&quot;&gt;为什么要分这么多层？&lt;/h3&gt;
&lt;p&gt;一位经验丰富的工程师几乎肯定会问这个问题。Pi 的回答是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“当且仅当两段代码有不同的使用者时，它们才应该在不同的包中。”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这条纪律贯穿了包数量从 3→7→4→7 的整个演化曲线：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pi-ai&lt;/code&gt; 独立存在——有人只想用统一 LLM 调用而不需要 Agent 循环&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pi-agent-core&lt;/code&gt; 独立存在——有人想用循环引擎构建非编码类 Agent&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pi-tui&lt;/code&gt; 独立存在——它是一个与 AI 无关的通用终端 UI 框架&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pi-storage-sqlite-node&lt;/code&gt; 独立存在——想用 SQLite 存会话的人不该被迫拉进整个系统&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;包边界不是组织工具，而是&lt;strong&gt;强制的分层纪律&lt;/strong&gt;——如果底层尝试导入上层代码，TypeScript 编译器会直接报错。这比任何团队约定都可靠得多。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;part-2-lei-bi-pi-jiu-xiang-yi-tai-le-gao-fa-dong-ji&quot;&gt;Part 2：类比——Pi 就像一台“乐高发动机“&lt;/h2&gt;
&lt;h3 id=&quot;fa-dong-ji-bu-ying-gai-guan-ni-de-che-shi-shen-me-yan-se&quot;&gt;发动机不应该管你的车是什么颜色&lt;/h3&gt;
&lt;p&gt;想象你从一架废弃的飞机上拆下来一台涡轮发动机。&lt;/p&gt;
&lt;p&gt;这台发动机有一个特点：它不在乎你是把它装在赛车、卡车、摩托车还是发电机上。它的接口极其简单——给它燃料，它给你推力。怎么冷却、怎么挂载、怎么控制方向——全是你的问题。&lt;/p&gt;
&lt;p&gt;Pi 的 Agent Loop 就是这台发动机。它：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不关心消息从哪里来（CLI 输入？Slack 消息？API 请求？——全是上层问题）&lt;/li&gt;
&lt;li&gt;不关心上下文怎么存（内存？文件？SQLite？——调用者决定）&lt;/li&gt;
&lt;li&gt;不关心工具有多少、能干什么（工具定义由上层传入）&lt;/li&gt;
&lt;li&gt;不关心谁在看输出（输出全走事件流，订阅者自行处理）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这就是“极简内核，能力外置“哲学：&lt;strong&gt;发动机只管转。&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;si-ceng-yang-cong-jiu-shi-fa-dong-ji-zai-yin-qing-cang-li&quot;&gt;四层洋葱就是“发动机在引擎舱里“&lt;/h3&gt;
&lt;p&gt;把这个类比展开：&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;汽车&lt;/th&gt;&lt;th&gt;Pi&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;发动机（不管车长什么样）&lt;/td&gt;&lt;td&gt;&lt;code&gt;pi-agent-core&lt;/code&gt;（无状态循环引擎）&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;引擎舱（散热、油路、电路）&lt;/td&gt;&lt;td&gt;&lt;code&gt;pi-coding-agent&lt;/code&gt;（会话管理、Compaction、工具集）&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;车身（轿车、SUV、卡车）&lt;/td&gt;&lt;td&gt;产品外壳（CLI、Slack、Web）&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;燃油系统（兼容不同标号、不同油站）&lt;/td&gt;&lt;td&gt;&lt;code&gt;pi-ai&lt;/code&gt;（20+ LLM 厂商统一接口）&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;如果你只需要一个发动机，拿 &lt;code&gt;pi-agent-core&lt;/code&gt;。如果你需要一辆完整的轿车，&lt;code&gt;pi-coding-agent&lt;/code&gt; 已经把发动机装进了引擎舱。如果你需要一辆卡车——自己用发动机搭，Pi 不强迫你开轿车。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;part-3-dong-shou-cong-ling-xie-yi-ge-zui-xiao-agent-loop&quot;&gt;Part 3：动手——从零写一个“最小 Agent Loop“&lt;/h2&gt;
&lt;h3 id=&quot;wo-men-yao-zuo-shen-me&quot;&gt;我们要做什么&lt;/h3&gt;
&lt;p&gt;不依赖 Pi，用约 60 行 TypeScript 写一个最小 Agent Loop。它只有一个工具（查看日期），但你跑完之后会完全理解 Pi 的循环引擎在做什么。&lt;/p&gt;
&lt;h3 id=&quot;wan-zheng-dai-ma&quot;&gt;完整代码&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// mini-agent-loop.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 极简 Agent Loop —— 一个约 60 行的发动机，演示 Pi 的核心设计&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;const&lt;/span&gt;&lt;span&gt; ANTHROPIC_API_KEY&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; process&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;env&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;ANTHROPIC_API_KEY&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;!;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// ── 1. 类型定义 ──&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Role&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;assistant&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;interface&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Message&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  role&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Role&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  content&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;interface&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; ToolCall&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  name&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  arguments&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Record&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; unknown&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;interface&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; AssistantMessage&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  role&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;assistant&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  content&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  toolCalls&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;?:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; ToolCall&lt;/span&gt;&lt;span&gt;[]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;interface&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; ToolResult&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  role&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;             // Anthropic tool_result 要求 role: &amp;quot;user&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  content&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// ── 2. 工具系统 ──&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;const&lt;/span&gt;&lt;span&gt; TOOLS&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;get_date&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  description&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;获取今天的日期和星期。当你需要知道今天是什么日子时使用。&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  input_schema&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;object&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; as const&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    properties&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: {},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    required&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; []&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; executeTool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; _args&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Record&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; unknown&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  if&lt;/span&gt;&lt;span&gt; (name&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ===&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;get_date&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    const&lt;/span&gt;&lt;span&gt; now&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Date&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; `&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;今天是 &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;${&lt;/span&gt;&lt;span&gt;now&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getFullYear&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 年 &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;${&lt;/span&gt;&lt;span&gt;now&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getMonth&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 月 &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;${&lt;/span&gt;&lt;span&gt;now&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getDate&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 日，星期&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;${[&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;日&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;一&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;二&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;三&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;四&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;五&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;六&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;][&lt;/span&gt;&lt;span&gt;now&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getDay&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()]}`&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; `&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;找不到工具: &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;${&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}`&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// ── 3. Agent Loop（对应 pi 的 agentLoop 函数） ──&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;async function&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; agentLoop&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  messages&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Message&lt;/span&gt;&lt;span&gt;[]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  signal&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; AbortSignal&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Promise&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  let&lt;/span&gt;&lt;span&gt; finalAnswer&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  // 双层循环：外层处理&amp;quot;唤醒&amp;quot;，内层驱动工作&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  let&lt;/span&gt;&lt;span&gt; shouldContinue&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = true;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  while&lt;/span&gt;&lt;span&gt; (shouldContinue&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;amp;&amp;amp; !&lt;/span&gt;&lt;span&gt;signal&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;aborted)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    shouldContinue&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = false;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  // 默认一轮，有工具调用就继续&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 调 LLM&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    const&lt;/span&gt;&lt;span&gt; resp&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = await&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; fetch&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;https://api.anthropic.com/v1/messages&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      method&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;POST&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      headers&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;content-type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;application/json&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;x-api-key&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; ANTHROPIC_API_KEY&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;anthropic-version&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;2023-06-01&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      body&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; JSON&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;stringify&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        model&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;claude-sonnet-4-20250514&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        max_tokens&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1024&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        tools&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; TOOLS&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        messages&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      }&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      signal&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    const&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = await&lt;/span&gt;&lt;span&gt; resp&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;json&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // Claude 的响应格式：有 text 内容和可选的 tool_use&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    const&lt;/span&gt;&lt;span&gt; textBlocks&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;filter&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; any&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; b&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ===&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;text&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    const&lt;/span&gt;&lt;span&gt; toolBlocks&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;filter&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; any&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; b&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ===&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;tool_use&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    finalAnswer&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; textBlocks&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;map&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; any&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; b&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;text)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;join&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 没有工具调用 → 任务完成&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (toolBlocks&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;length&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ===&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; break;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 有工具调用 → 执行 → 结果追加 → 继续循环&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    messages&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;push&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      role&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;assistant&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; JSON&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;stringify&lt;/span&gt;&lt;span&gt;(data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;content)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    const&lt;/span&gt;&lt;span&gt; toolResults&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; ToolResult&lt;/span&gt;&lt;span&gt;[]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; []&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;const&lt;/span&gt;&lt;span&gt; tc&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; of&lt;/span&gt;&lt;span&gt; toolBlocks)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      const&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; executeTool&lt;/span&gt;&lt;span&gt;(tc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; tc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;input)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      toolResults&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;push&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        role&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; JSON&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;stringify&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;tool_result&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          tool_use_id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; tc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      }&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      console&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;  🔧 &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;${&lt;/span&gt;&lt;span&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;() → &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;${&lt;/span&gt;&lt;span&gt;result&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;slice&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 40&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;`&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    messages&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;push&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;...&lt;/span&gt;&lt;span&gt;toolResults)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    shouldContinue&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = true;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  return&lt;/span&gt;&lt;span&gt; signal&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;aborted&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ?&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;已中止&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; :&lt;/span&gt;&lt;span&gt; finalAnswer&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// ── 4. 跑起来 ──&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;async function&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; main&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  const&lt;/span&gt;&lt;span&gt; controller&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; AbortController&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  // 模拟用户 5 秒后按 Ctrl+C&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  setTimeout&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; controller&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;abort&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 50_000&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  const&lt;/span&gt;&lt;span&gt; answer&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = await&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; agentLoop&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;span&gt; role&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span&gt; content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;告诉我今天是几月几号星期几&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot; }&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    controller&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;signal&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  )&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  console&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;📝 &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;${&lt;/span&gt;&lt;span&gt;answer&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}`&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;main&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;yun-xing-xiao-guo&quot;&gt;运行效果&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; npx tsx mini-agent-loop.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  🔧&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; get_date&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; → 今天是&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2026&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 年&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 8&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 月&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 6&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 日，星期四...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;📝&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 今天是&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2026&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 年&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 8&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 月&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 6&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 日，星期四。&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;zhe-60-xing-dui-ying-pi-de-na-xie-she-ji&quot;&gt;这 60 行对应 Pi 的哪些设计？&lt;/h3&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;Demo 中的代码&lt;/th&gt;&lt;th style=&quot;text-align: left&quot;&gt;Pi 中的对应&lt;/th&gt;&lt;th style=&quot;text-align: left&quot;&gt;关键设计决策&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;code&gt;agentLoop()&lt;/code&gt; 函数&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;code&gt;pi-agent-core&lt;/code&gt; 的 &lt;code&gt;runLoop()&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;函数无内部状态，所有数据通过参数传入&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;code&gt;executeTool()&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;工具执行管线&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;这是“发动机不知道工具有多少个“的具体体现&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;code&gt;AbortSignal&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;pi 的 AbortSignal 贯穿&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;用户中断不靠 flag 检查——靠原生 cancel&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;code&gt;TOOLS&lt;/code&gt; 数组&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Extension 系统注册的 ToolDefinition&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;工具是数据，不是代码装饰器&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;code&gt;fetch()&lt;/code&gt; 调 Anthropic&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;code&gt;pi-ai&lt;/code&gt; 层的 Provider 接口&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;底层接口被完全隔离，换厂商不影响循环&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3 id=&quot;cong-60-xing-dao-sheng-chan-ji&quot;&gt;从 60 行到生产级&lt;/h3&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;维度&lt;/th&gt;&lt;th&gt;我们的 Demo&lt;/th&gt;&lt;th&gt;Pi 的生产级 Loop&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;提供商&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;只支持 Anthropic&lt;/td&gt;&lt;td&gt;20+ 厂商，通过 Provider Registry 统一&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;循环&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;单层 while&lt;/td&gt;&lt;td&gt;双层嵌套（引导 vs 后续消息语义不同）&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;事件&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;console.log&lt;/td&gt;&lt;td&gt;完整的生命周期事件流（agent_start → turn_start → … → agent_end）&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;中止&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;单个 AbortSignal&lt;/td&gt;&lt;td&gt;贯穿所有异步操作的信号管道&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;上下文管理&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;无&lt;/td&gt;&lt;td&gt;&lt;code&gt;transformContext&lt;/code&gt; 回调（Compaction、分支摘要）&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;错误处理&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;无&lt;/td&gt;&lt;td&gt;stopReason 字段（不抛异常，优雅降级）&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;zong-jie&quot;&gt;总结&lt;/h2&gt;
&lt;p&gt;今天我们讲了三件事：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Pi 不是 LLM 包装器，是 Agent 运行时&lt;/strong&gt;——它关心的是“调完 LLM 之后发生什么“，不是“怎么调 LLM“。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;四层洋葱架构的核心是纪律&lt;/strong&gt;——每一层只知道自己下面那层。Agent Loop 只有不到 2000 行，而且是完全无状态的——这正是它能在 CLI/Slack/Web/测试四种形态下不加修改地复用的原因。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;你写了一个 60 行的 Agent Loop&lt;/strong&gt;——它有工具调用、有 AbortSignal、有 loop 退出条件。这和 Pi 的内核引擎是同一个设计模式——只是 Pi 把这些原则执行到了生产级。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;xia-yi-qi-yu-gao&quot;&gt;下一期预告&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pi 的工具设计：约束即保护&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Pi 为什么不做“万能 bash“而要提供 6+1 个专用工具？为什么 Edit 工具要求 oldText 精确匹配？为什么搜索工具有截断策略？学完你会发现：给 LLM 设计工具和给人设计 UI 是一回事。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;em&gt;本文基于张汉东《&lt;a rel=&quot;external&quot; href=&quot;https://zhanghandong.github.io/pi-book/&quot;&gt;pi 的设计艺术&lt;/a&gt;》（CC BY-NC-SA 4.0）第 1-3、8-10 章内容改编，用费曼学习法重构为“概念 → 类比 → 动手“三段式教程。&lt;/em&gt;&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Pi 的工具设计：为什么&quot;约束&quot;比&quot;自由&quot;更重要</title>
        <published>2026-08-06T00:00:00+00:00</published>
        <updated>2026-08-06T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/pi-agent-series-02-tool-design/"/>
        <id>https://scp.net.cn/blog/pi-agent-series-02-tool-design/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/pi-agent-series-02-tool-design/">&lt;blockquote&gt;
&lt;p&gt;本文是 &lt;strong&gt;Pi Agent 系列教程&lt;/strong&gt;第 2 篇。基于张汉东《&lt;a rel=&quot;external&quot; href=&quot;https://zhanghandong.github.io/pi-book/&quot;&gt;pi 的设计艺术&lt;/a&gt;》第 19-23 章改编。上一篇讲清了 Pi 的架构——四层洋葱和 Agent Loop 引擎。今天聚焦一个具体问题：&lt;strong&gt;该给 Agent 什么工具？怎么设计工具接口才能让 LLM 少犯错？&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;part-1-gai-nian-gong-ju-shi-dai-hu-lan-de-jie-kou&quot;&gt;Part 1：概念——工具是带护栏的接口&lt;/h2&gt;
&lt;h3 id=&quot;zui-tian-zhen-de-wen-ti-wei-shen-me-bu-neng-zhi-gei-yi-ge-bash&quot;&gt;最天真的问题：为什么不能只给一个 Bash？&lt;/h3&gt;
&lt;p&gt;如果你刚接触 Agent 开发，很可能会问这个问题——“LLM 不是很擅长写代码吗？给它一个 shell 让它自己敲不就行了？”&lt;/p&gt;
&lt;p&gt;Pi 的设计者给了明确答案。他选了 &lt;strong&gt;6 个结构化工具 + Bash 后备&lt;/strong&gt;：&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;工具&lt;/th&gt;&lt;th&gt;作用&lt;/th&gt;&lt;th&gt;为什么不能只用 Bash&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;read&lt;/code&gt;&lt;/td&gt;&lt;td&gt;读文件，支持行范围&lt;/td&gt;&lt;td&gt;&lt;code&gt;cat | sed -n &#39;50,79p&#39;&lt;/code&gt; 引号不匹配就完蛋&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;write&lt;/code&gt;&lt;/td&gt;&lt;td&gt;创建或全量覆盖文件&lt;/td&gt;&lt;td&gt;echo heredoc 各种转义地狱&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;edit&lt;/code&gt;&lt;/td&gt;&lt;td&gt;精确替换（oldText → newText）&lt;/td&gt;&lt;td&gt;sed 替换一个拼写错误可能导致全局误伤&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;find&lt;/code&gt;&lt;/td&gt;&lt;td&gt;文件名模式匹配&lt;/td&gt;&lt;td&gt;&lt;code&gt;find . -name &#39;*.ts&#39;&lt;/code&gt; 跨平台差异是噩梦&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;grep&lt;/code&gt;&lt;/td&gt;&lt;td&gt;文本内容搜索&lt;/td&gt;&lt;td&gt;rg 和 grep 参数不一致，模型更分不清&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;ls&lt;/code&gt;&lt;/td&gt;&lt;td&gt;列目录&lt;/td&gt;&lt;td&gt;简单操作，但 bash 里 &lt;code&gt;ls -la&lt;/code&gt; 输出格式不稳定&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;bash&lt;/code&gt;&lt;/td&gt;&lt;td&gt;万能后备&lt;/td&gt;&lt;td&gt;上述工具覆盖不了的操作&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;核心原因：&lt;strong&gt;“LLM 用结构化参数犯的错比用自由文本命令少得多。”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;对比一下：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 结构化工具——类型错误立即被捕获&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;read&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;span&gt; path&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;src/index.ts&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span&gt; offset&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 50&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; limit&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 30&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 自由文本命令——任何小错产生模糊的 bash 报错&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;cat src/index.ts | sed -n &amp;#39;50,79p&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 引号不匹配？管道遗漏？sed 语法错？——全是一个 &amp;quot;command not found&amp;quot; 或空输出&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;结构化参数有 schema 验证（Pi 用 TypeBox），传入错误类型（offset 传了字符串）会被&lt;strong&gt;立即拒绝并反馈具体错误&lt;/strong&gt;。模型下一轮就能修正。Bash 命令的任何小错都会产生模糊的报错——可能需要多轮试错才能定位问题。&lt;/p&gt;
&lt;h3 id=&quot;she-ji-yuan-ze-1-wei-gao-pin-qie-rong-yi-chu-cuo-de-cao-zuo-ti-gong-zhuan-yong-gong-ju&quot;&gt;设计原则 1：为“高频且容易出错“的操作提供专用工具&lt;/h3&gt;
&lt;p&gt;Pi 的选择标准很清楚：如果某个操作 LLM 每天都在做（read、edit、search），而且用 bash 做容易出错，那就值得一个专用工具。&lt;/p&gt;
&lt;p&gt;但不是所有 bash 操作都值得专用化。&lt;code&gt;wc -l *.ts | sort -n&lt;/code&gt; 这种一行搞定的事，不值得。策略是&lt;strong&gt;只为高频 + 高危操作提供专用工具&lt;/strong&gt;，其余交给 bash 后备。&lt;/p&gt;
&lt;h3 id=&quot;she-ji-yuan-ze-2-shu-chu-jie-duan-shi-ying-yue-shu-bu-shi-ke-you-ke-wu&quot;&gt;设计原则 2：输出截断是硬约束，不是可有可无&lt;/h3&gt;
&lt;p&gt;LLM 的上下文窗口是稀缺资源。如果 grep 在一个 10 万行项目中搜索 “TODO”，匹配了 5000 行，全塞进上下文就是浪费 token。&lt;/p&gt;
&lt;p&gt;Pi 的所有工具共享统一的截断逻辑：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;行数上限&lt;/strong&gt;：2000 行&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;字节上限&lt;/strong&gt;：50 KB&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;先触及者生效&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但截断策略因工具而异：&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;工具&lt;/th&gt;&lt;th&gt;截断方式&lt;/th&gt;&lt;th&gt;原因&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;read&lt;/code&gt;、&lt;code&gt;grep&lt;/code&gt;、&lt;code&gt;find&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;truncateHead&lt;/code&gt; — 保留开头&lt;/td&gt;&lt;td&gt;前 N 条结果最有价值&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;bash&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;truncateTail&lt;/code&gt; — 保留结尾&lt;/td&gt;&lt;td&gt;“命令输出的最后几行通常包含错误信息”&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;截断不产生半行，元信息完整携带总行数/字节和触发限制的具体类型——工具据此生成有意义的状态提示（如“输出共 5234 行，仅显示前 2000 行“）。&lt;/p&gt;
&lt;h3 id=&quot;she-ji-yuan-ze-3-yue-shu-cai-yang-shi-hou-xiao-yan-shi-qian-bao-zheng&quot;&gt;设计原则 3：约束采样——事后校验 + 事前保证&lt;/h3&gt;
&lt;p&gt;从 v0.82.0 开始，Pi 叠加了两层约束：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;TypeBox 事后校验&lt;/strong&gt;：Pi 侧的 schema 验证，工具执行前自动检查参数合法性&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;constrainedSampling 事前保证&lt;/strong&gt;：让 provider 在解码时就用 JSON Schema 约束输出结构&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;两种模式共存：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;json_schema&lt;/code&gt;：按工具 schema 严格解码，分“prefer“（尽力而为）和“require“（必须严格）两档&lt;/li&gt;
&lt;li&gt;&lt;code&gt;grammar&lt;/code&gt;：用正则或 Lark 语法约束输出，适用于非 JSON 格式&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;叠加效果：LLM 生成本身就被约束在合法结构内，外加 Pi 侧的二次验证兜底。从根本上减少了“工具参数格式非法“导致的失败。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;part-2-lei-bi-gei-llm-she-ji-gong-ju-jiu-xiang-gei-mang-ren-she-ji-cai-dan&quot;&gt;Part 2：类比——给 LLM 设计工具就像给盲人设计菜单&lt;/h2&gt;
&lt;h3 id=&quot;mang-ren-can-ting&quot;&gt;盲人餐厅&lt;/h3&gt;
&lt;p&gt;想象你是一家盲人餐厅的主厨。你的客人看不到菜——他们只能通过你的菜单描述和口味判断。&lt;/p&gt;
&lt;p&gt;你会怎么设计菜单？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;❌ &lt;strong&gt;万能菜单&lt;/strong&gt;：“我们有全世界的食材，你想吃什么我都能做。”——客人无从下手，可能会点一个根本不存在的组合&lt;/li&gt;
&lt;li&gt;❌ &lt;strong&gt;技术规格菜单&lt;/strong&gt;：“猪里脊 150g ± 5g，盐 1.2g，烹饪温度 165°C，时间 8 分钟。”——精确但没用，客人不知道这些参数组合出来是什么&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;结构化菜单&lt;/strong&gt;：“红烧排骨——甜咸口味，配米饭。什么时候想吃’让人满足的中式硬菜’时选这个。”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这正好对应了给 LLM 设计工具的三种方式：&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;菜单方式&lt;/th&gt;&lt;th&gt;对应工具设计&lt;/th&gt;&lt;th&gt;好坏&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;“什么都能做”&lt;/td&gt;&lt;td&gt;只给一个 Bash&lt;/td&gt;&lt;td&gt;自由度太高，LLM 不知道从哪里开始&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;“技术规格”&lt;/td&gt;&lt;td&gt;JSON Schema 但没有 description / promptGuidelines&lt;/td&gt;&lt;td&gt;类型正确但不知道什么时候该用&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;“结构化菜单”&lt;/td&gt;&lt;td&gt;有描述、有边界、有示例的工具&lt;/td&gt;&lt;td&gt;LLM 知道什么时候用什么&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3 id=&quot;jing-que-ti-huan-vs-mo-hu-ti-huan&quot;&gt;精确替换 vs 模糊替换&lt;/h3&gt;
&lt;p&gt;继续盲人餐厅的类比。如果你让一位盲人厨师“把那盘菜里的花椒换成黑胡椒“，你需要给他一个&lt;strong&gt;绝对不会搞混&lt;/strong&gt;的指示：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;❌ “把花椒换掉”——如果盘里有花椒油和花椒粒，换哪个？&lt;/li&gt;
&lt;li&gt;✅ “把位于盘子左上角的那三粒完整花椒换成等量的现磨黑胡椒”——唯一性保证&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这就 Pi Edit 工具的核心约束：&lt;strong&gt;&lt;code&gt;oldText&lt;/code&gt; 必须精确匹配且唯一。&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;edits&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; Type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Array&lt;/span&gt;&lt;span&gt;(Type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Object&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  oldText&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; Type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;String&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    description&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Exact text for one targeted replacement. Must be unique.&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  }&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  newText&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; Type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;String&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    description&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Replacement text for this targeted edit.&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  }&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个约束是强制性的。如果 LLM 提供的 &lt;code&gt;oldText&lt;/code&gt; 在文件里出现两次，Pi 会拒绝这次编辑并告诉 LLM “你的 oldText 不唯一”。这不是不给 LLLM 自由，而是防止模糊替换导致意外修改——就像盲人厨师绝对不会被允许在没有确认的情况下替换食材。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;part-3-dong-shou-she-ji-yi-ge-dai-hu-lan-de-gong-ju&quot;&gt;Part 3：动手——设计一个“带护栏“的工具&lt;/h2&gt;
&lt;h3 id=&quot;wo-men-yao-zuo-shen-me&quot;&gt;我们要做什么&lt;/h3&gt;
&lt;p&gt;用 TypeScript 写一个带 TypeBox schema 验证的工具定义，展示 Pi 的工具设计模式——不只是 JSON Schema，而是包含 description、边界、示例的完整契约。&lt;/p&gt;
&lt;h3 id=&quot;wan-zheng-dai-ma&quot;&gt;完整代码&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// tool-design-demo.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 演示 Pi 的工具设计理念：结构化参数 + 类型校验 + 描述即文档&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; Type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; type&lt;/span&gt;&lt;span&gt; Static&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;@sinclair/typebox&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; Value&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;@sinclair/typebox/value&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// ── 1. 工具定义（模仿 Pi 的 ToolDefinition 接口） ──&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;interface&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; ToolDefinition&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;TParams&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Record&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; unknown&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&amp;gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  name&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  description&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // 告诉 LLM&amp;quot;什么时候用&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  parameters&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; TParams&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; extends&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Record&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; unknown&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    ?&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; ReturnType&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;typeof&lt;/span&gt;&lt;span&gt; Type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;Object&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    :&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; never&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  promptGuidelines&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;?:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; string&lt;/span&gt;&lt;span&gt;[]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  // 注入 system prompt 的使用指南&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  execute&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;args&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Static&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;TParams&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Promise&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// ── 2. 定义一个&amp;quot;安全文件删除&amp;quot;工具 ──&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;const&lt;/span&gt;&lt;span&gt; deleteFileSchema&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; Type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Object&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  path&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; Type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;String&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    description&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;要删除的文件路径（相对于项目根目录）&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  }&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  reason&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; Type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;String&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    description&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;删除原因，将写入操作日志。例：&amp;#39;不再使用的测试文件&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  }&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  backup&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; Type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Boolean&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    description&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;是否先备份到 .trash/ 目录。危险文件必须设为 true&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    default&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  }&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;const&lt;/span&gt;&lt;span&gt; deleteFileTool&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; ToolDefinition&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;typeof&lt;/span&gt;&lt;span&gt; deleteFileSchema&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;delete_file&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  description&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;删除指定文件。当需要清理不需要的文件时使用。&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;不要用于删除 node_modules 等依赖目录——用 bash &amp;#39;rm -rf&amp;#39;。&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;不能用于删除 .git 目录内的文件。&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  parameters&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; deleteFileSchema&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  promptGuidelines&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;- 删除前确认文件不在 .gitignore 的关键路径中&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;- 如果文件曾被其他模块引用，先更新引用再删除&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;- 一次只删除一个文件，批量删除用 bash&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  async&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; execute&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;args&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Static&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;typeof&lt;/span&gt;&lt;span&gt; deleteFileSchema&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; `&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;已删除 &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;${&lt;/span&gt;&lt;span&gt;args&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;path&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;（备份：&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;${&lt;/span&gt;&lt;span&gt;args&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;backup&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;，原因：&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;${&lt;/span&gt;&lt;span&gt;args&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;reason&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;）&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// ── 3. 工具执行管线：校验 → 转换 → 执行 ──&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;async function&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; executeWithGuardrail&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; extends&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Record&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; unknown&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&amp;gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  tool&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; ToolDefinition&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;any&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  rawArgs&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; T&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Promise&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  // 3a. TypeBox 校验（Pi 的事后校验层）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;!&lt;/span&gt;&lt;span&gt;Value&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Check&lt;/span&gt;&lt;span&gt;(tool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;parameters&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; rawArgs))&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    const&lt;/span&gt;&lt;span&gt; errors&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;...&lt;/span&gt;&lt;span&gt;Value&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Errors&lt;/span&gt;&lt;span&gt;(tool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;parameters&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; rawArgs)]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; JSON&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;stringify&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      error&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;参数校验失败&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      details&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; errors&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;map&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        path&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; e&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;path&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        message&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; e&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;message&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        expected&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; e&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;schema&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;?.&lt;/span&gt;&lt;span&gt;description&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ??&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;未知&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        received&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; JSON&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;stringify&lt;/span&gt;&lt;span&gt;(e&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;value)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      }&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      hint&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;请根据 details 中的具体信息修正参数后重试。&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  // 3b. 执行工具&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  try&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    const&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = await&lt;/span&gt;&lt;span&gt; tool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;execute&lt;/span&gt;&lt;span&gt;(rawArgs)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; catch&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;err&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; any&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; JSON&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;stringify&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      error&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;工具执行异常&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      message&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;message&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      hint&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;请检查文件是否存在、权限是否正确。&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// ── 4. 演示：正确调用 vs 错误调用 ──&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;async function&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; main&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  console&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot; .&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;repeat&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;50&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  console&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;工具设计演示：delete_file&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  console&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;repeat&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;50&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  // 正确调用&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  const&lt;/span&gt;&lt;span&gt; ok&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = await&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; executeWithGuardrail&lt;/span&gt;&lt;span&gt;(deleteFileTool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    path&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;src/old-helper.ts&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    reason&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;功能已迁移到 utils/helper.ts，旧文件不再被引用&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    backup&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  }&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  console&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;✅ 正确调用：&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;${&lt;/span&gt;&lt;span&gt;ok&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}`&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  // 错误调用：缺少必填字段&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  const&lt;/span&gt;&lt;span&gt; bad1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = await&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; executeWithGuardrail&lt;/span&gt;&lt;span&gt;(deleteFileTool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    path&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;src/old-helper.ts&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // reason 缺失——必填字段&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  }&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  console&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;❌ 缺少必填字段：&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;${&lt;/span&gt;&lt;span&gt;bad1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;slice&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 200&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;`&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  // 错误调用：类型错误&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  const&lt;/span&gt;&lt;span&gt; bad2&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = await&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; executeWithGuardrail&lt;/span&gt;&lt;span&gt;(deleteFileTool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    path&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;src/old-helper.ts&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    reason&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;不再需要&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    backup&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;yes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  // 应该是 boolean，传了 string&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  }&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  console&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;❌ 类型错误：&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;${&lt;/span&gt;&lt;span&gt;bad2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;slice&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 200&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;`&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;main&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;yun-xing-xiao-guo&quot;&gt;运行效果&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; npx tsx tool-design-demo.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;==================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;工具设计演示：delete_file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;==================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;✅&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 正确调用：已删除 src/old-helper.ts（备份：&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;，原因：功能已迁移到 utils/helper.ts，旧文件不再被引用）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;❌&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 缺少必填字段：{&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;参数校验失败&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;details&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;:[{&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;path&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;/reason&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;必填字段&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;expected&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;删除原因...&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;received&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;undefined&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;}],&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;hint&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;请根据 details 中的具体信息修正参数后重试。&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;❌&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 类型错误：{&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;参数校验失败&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;details&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;:[{&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;path&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;/backup&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;类型不匹配&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;expected&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;boolean&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;received&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;yes&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;}],&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;hint&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;请根据 details 中的具体信息修正参数后重试。&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;guan-jian-she-ji-dian&quot;&gt;关键设计点&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;description&lt;/code&gt; 是“决定树“，不是“功能列表“&lt;/strong&gt;：告诉 LLM 什么时候用、什么时候不该用、不能用在哪。模型的决策准确率直接取决于描述的精确度。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;TypeBox 校验的错误信息对 LLM 友好&lt;/strong&gt;：不只是“错了“，而是“哪里错、期望什么、实际收到了什么、怎么改“。这正是 Pi 的哲学——错误反馈越精确，模型自我纠正的成功率越高。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;promptGuidelines&lt;/code&gt; 参与 System Prompt 组装&lt;/strong&gt;：工具不只是执行体，还能指导 LLM 怎么使用自己——把最佳实践注入提示词。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;zong-jie&quot;&gt;总结&lt;/h2&gt;
&lt;p&gt;今天我们用“盲人餐厅“的类比讲清了 Pi 的工具设计哲学：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;结构化参数优于自由文本&lt;/strong&gt;——LLM 用 schema 约束的参数犯的错比自由拼接的 shell 命令少得多。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;6+1 工具策略精确地平衡了“易用“和“安全“&lt;/strong&gt;——高频且易错的操作给专用工具，其余留给 bash 后备。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;“约束即保护“是核心思想&lt;/strong&gt;——从输出截断到参数校验到 constrainedSampling，每层约束都是为了防止 LLM 犯它最常见的错误。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;xia-yi-qi-yu-gao&quot;&gt;下一期预告&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pi 的能力外置：Extension / Skill / Resource Loader&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Pi 为什么没有内建 MCP、子 Agent、权限弹窗、Plan Mode？因为这些功能都是“可以从更底层机制组合出来的“。下一篇拆解 Extension 系统——怎么用三个回调（execute、beforeToolCall、transformContext）组合出无限的产品形态。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;em&gt;本文基于张汉东《&lt;a rel=&quot;external&quot; href=&quot;https://zhanghandong.github.io/pi-book/&quot;&gt;pi 的设计艺术&lt;/a&gt;》（CC BY-NC-SA 4.0）第 19-23 章内容改编。&lt;/em&gt;&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Pi 的能力外置：为什么&quot;不内建&quot;比&quot;内建&quot;更强大</title>
        <published>2026-08-06T00:00:00+00:00</published>
        <updated>2026-08-06T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/pi-agent-series-03-extension-skill/"/>
        <id>https://scp.net.cn/blog/pi-agent-series-03-extension-skill/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/pi-agent-series-03-extension-skill/">&lt;blockquote&gt;
&lt;p&gt;本文是 &lt;strong&gt;Pi Agent 系列教程&lt;/strong&gt;第 3 篇。基于张汉东《&lt;a rel=&quot;external&quot; href=&quot;https://zhanghandong.github.io/pi-book/&quot;&gt;pi 的设计艺术&lt;/a&gt;》第 15-18 章改编。上一篇拆解了 Pi 的工具设计哲学——约束即保护。今天看向 Pi 最反直觉的设计：&lt;strong&gt;几乎所有行业认为“Agent 框架该有“的功能，Pi 都没有内建。&lt;/strong&gt; 但它用三个回调组合出了所有功能。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;part-1-gai-nian-pi-de-si-jian-bu-zuo-de-shi&quot;&gt;Part 1：概念——Pi 的四件“不做的事“&lt;/h2&gt;
&lt;h3 id=&quot;zhe-bu-shi-tou-lan&quot;&gt;这不是偷懒&lt;/h3&gt;
&lt;p&gt;先来直面 Pi 最受争议的四个设计决定：&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;行业惯例&lt;/th&gt;&lt;th&gt;Pi 的做法&lt;/th&gt;&lt;th&gt;组合机制&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;内建子 Agent 调度&lt;/td&gt;&lt;td&gt;子 Agent 是普通工具调用&lt;/td&gt;&lt;td&gt;&lt;code&gt;execute&lt;/code&gt; 回调&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;内建 MCP 协议&lt;/td&gt;&lt;td&gt;Extension + Skill 两套体系&lt;/td&gt;&lt;td&gt;&lt;code&gt;registerTool&lt;/code&gt; + system prompt&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;内建权限弹窗&lt;/td&gt;&lt;td&gt;&lt;code&gt;beforeToolCall&lt;/code&gt; 钩子&lt;/td&gt;&lt;td&gt;&lt;code&gt;beforeToolCall&lt;/code&gt; 回调&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;内建 Plan Mode&lt;/td&gt;&lt;td&gt;&lt;code&gt;transformContext&lt;/code&gt; 回调&lt;/td&gt;&lt;td&gt;&lt;code&gt;transformContext&lt;/code&gt; + &lt;code&gt;beforeToolCall&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Pi 的设计者用一个原则统一了这些决定：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“如果一个功能可以用更底层的机制组合出来，就不应该把它内建到内核中。”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这不是偷懒——这是对复杂度的管理。每个内建功能都是一份维护负担、一份 API 合约、一份向后兼容承诺。如果用三个回调能组合出所有需求，你得到的是一个&lt;strong&gt;指数级更可组合&lt;/strong&gt;的系统。&lt;/p&gt;
&lt;h3 id=&quot;san-ge-hui-diao-gou-cheng-wan-zheng-de-kong-zhi-mian&quot;&gt;三个回调构成完整的控制面&lt;/h3&gt;
&lt;p&gt;这三个回调覆盖了 Agent 必须被控制的三个维度：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;execute        → 控制&amp;quot;做什么&amp;quot;（工具的实现逻辑）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;beforeToolCall → 控制&amp;quot;能做什么&amp;quot;（权限边界）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;transformContext → 控制&amp;quot;看到什么&amp;quot;（上下文变换）&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;每个具体功能都是这三个回调的组合：&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;你想实现的功能&lt;/th&gt;&lt;th&gt;用什么回调&lt;/th&gt;&lt;th&gt;怎么组合&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;子 Agent&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;execute&lt;/code&gt;&lt;/td&gt;&lt;td&gt;在工具执行函数内跑一个新的 Agent Loop&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;权限弹窗&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;beforeToolCall&lt;/code&gt;&lt;/td&gt;&lt;td&gt;检查工具名和参数，block 或放行&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Plan Mode&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;transformContext&lt;/code&gt; + &lt;code&gt;beforeToolCall&lt;/code&gt;&lt;/td&gt;&lt;td&gt;planning 阶段注入“只做计划“指令 + 阻止所有工具执行；execute 阶段注入“按计划执行“指令&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;上下文压缩&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;transformContext&lt;/code&gt;&lt;/td&gt;&lt;td&gt;在消息传给 LLM 前旧消息替换为摘要&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;工具黑名单&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;beforeToolCall&lt;/code&gt;&lt;/td&gt;&lt;td&gt;匹配危险工具名 → block&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;动态权限&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;beforeToolCall&lt;/code&gt;&lt;/td&gt;&lt;td&gt;根据时间/角色/上下文决定是否放行&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3 id=&quot;xiang-bi-nei-jian-de-dai-jia&quot;&gt;相比内建的代价&lt;/h3&gt;
&lt;p&gt;这种设计不是没有代价。Pi 自己总结了四点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;入门摩擦大&lt;/strong&gt;——用户面对四层洋葱，每一层有自己的类型和回调。追踪一条消息从用户输入到模型响应需要穿越全部四层。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;重复实现&lt;/strong&gt;——CLI、Slack、Web 三个产品外壳各自实现了相似的会话加载、System Prompt 构建、工具权限检查。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;文档负担&lt;/strong&gt;——内建功能写一次文档就好；外置功能需要每个产品各自记录组合方式。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;调试难&lt;/strong&gt;——Bug 可能出在内核、产品层、或两者的交互中。层数越多，诊断路径越长。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;但这些是“为多产品适应性付出的税“。对于单产品团队，框架式设计也许更合适。对于 Pi 这样需要&lt;strong&gt;同一份内核驱动终端、Slack、浏览器、GPU 集群&lt;/strong&gt;的路由器，这笔税是合理的。&lt;/p&gt;
&lt;h3 id=&quot;extension-xi-tong-rang-yong-hu-xie-dai-ma-kuo-zhan-agent&quot;&gt;Extension 系统：让用户写代码扩展 Agent&lt;/h3&gt;
&lt;p&gt;Pi 的 Extension 系统是“能力外置“的核心实现机制。一个 Extension 能做五件事：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;注册工具&lt;/strong&gt;——新工具和内建工具同等的待遇（agent loop 的工具分发中一视同仁）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;订阅事件&lt;/strong&gt;——二十多种生命周期事件，分“观察型“（被动获知）和“干预型“（通过返回值影响系统行为）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;注册命令和快捷键&lt;/strong&gt;——新增斜杠命令（如 &lt;code&gt;/deploy&lt;/code&gt;）、键盘快捷键、CLI flag&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;注入消息&lt;/strong&gt;——三种方式（自定义消息、模拟用户输入、追加 Entry）在不同时机注入上下文&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;注册 Provider&lt;/strong&gt;——v0.81.0 起，extension 可以注册完整的 LLM Provider，自带认证和模型列表&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;一个 Extension 就是导出一个 &lt;code&gt;setup&lt;/code&gt; 函数的 TypeScript 文件。pi 用 &lt;code&gt;jiti&lt;/code&gt; 在运行时编译加载——不需要预编译步骤，改完代码重启 pi 就生效。&lt;/p&gt;
&lt;h3 id=&quot;liang-jie-duan-chu-shi-hua-fang-zhi-extension-zai-xi-tong-zhong-luo-ben&quot;&gt;两阶段初始化：防止 Extension 在系统中“裸奔“&lt;/h3&gt;
&lt;p&gt;这是 Pi Extension 系统最精妙的设计。Extension 的 &lt;code&gt;setup()&lt;/code&gt; 执行时，系统还没有完全就绪。此时 Runtime 的 action 方法全是 &lt;strong&gt;throwing stubs&lt;/strong&gt;——如果你在 &lt;code&gt;setup()&lt;/code&gt; 里调用 &lt;code&gt;sendMessage()&lt;/code&gt; 或 &lt;code&gt;setModel()&lt;/code&gt;，会立即得到一个明确的报错。&lt;/p&gt;
&lt;p&gt;第二阶段，Runner 调用 &lt;code&gt;bindCore()&lt;/code&gt; 把真实的 action 实现注入替换 stubs。只有在 &lt;code&gt;session_start&lt;/code&gt; 事件触发后，这些方法才可用。&lt;/p&gt;
&lt;p&gt;用 throwing stubs 而不是 silent no-op 是刻意的——让开发者在错误使用时立即得到明确报错，而不是困惑于“为什么我的 sendMessage 没反应“。&lt;/p&gt;
&lt;h3 id=&quot;skill-ji-zhi-yong-wen-dang-ti-dai-dai-ma&quot;&gt;Skill 机制：用文档替代代码&lt;/h3&gt;
&lt;p&gt;和 Extension 互补的是 Skill——纯 Markdown 文档，注入 System Prompt，教 LLM 怎么完成特定任务。&lt;/p&gt;
&lt;p&gt;对比很鲜明：&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;需求&lt;/th&gt;&lt;th&gt;用 Skill&lt;/th&gt;&lt;th&gt;用 Extension&lt;/th&gt;&lt;th&gt;用 MCP&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;教 LLM 一个工作流&lt;/td&gt;&lt;td&gt;✅ 最适合&lt;/td&gt;&lt;td&gt;过度设计&lt;/td&gt;&lt;td&gt;过度设计&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;注入领域知识&lt;/td&gt;&lt;td&gt;✅ 最适合&lt;/td&gt;&lt;td&gt;过度设计&lt;/td&gt;&lt;td&gt;过度设计&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;调外部 API&lt;/td&gt;&lt;td&gt;❌&lt;/td&gt;&lt;td&gt;✅&lt;/td&gt;&lt;td&gt;✅&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;操纵 Agent 内部状态&lt;/td&gt;&lt;td&gt;❌&lt;/td&gt;&lt;td&gt;✅ 唯一选项&lt;/td&gt;&lt;td&gt;❌&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;修改 UI 行为&lt;/td&gt;&lt;td&gt;❌&lt;/td&gt;&lt;td&gt;✅ 唯一选项&lt;/td&gt;&lt;td&gt;❌&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;跨框架复用&lt;/td&gt;&lt;td&gt;❌&lt;/td&gt;&lt;td&gt;❌&lt;/td&gt;&lt;td&gt;✅&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Pi 不排斥 MCP 的标准化价值，但认为用一个独立进程（启动/维护/监控 + JSON-RPC 通信层 + 进程间错误处理）来告诉 LLM“你该用 TDD 流程“是用大炮打蚊子。当前 pi 的生态定位是专注于自己的产品和工具集，跨框架互操作不是优先考虑。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;part-2-lei-bi-san-ge-xuan-niu-vs-yi-bai-ge-gong-neng-an-niu&quot;&gt;Part 2：类比——三个旋钮 vs 一百个功能按钮&lt;/h2&gt;
&lt;h3 id=&quot;yin-le-gong-zuo-shi&quot;&gt;音乐工作室&lt;/h3&gt;
&lt;p&gt;想象你走进一个&lt;strong&gt;音乐工作室&lt;/strong&gt;。桌上有两个设备：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;设备 A（框架式 Mixer）&lt;/strong&gt;：有 100 个预置效果按钮——“摇滚氛围”“深夜爵士”“古典温暖”……每个按钮调好了一套 EQ + 压缩 + 混响参数。按一下就行。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;设备 B（协议式 Mixer）&lt;/strong&gt;：只有三个旋钮——低频、中频、高频。你可以拧出任意组合。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;设备 A 的 100 个按钮看起来很强大，但如果你想做一个“不是摇滚不是爵士不是古典“的声音——比如“公路旅行中在加油站听到的老式收音机放的后摇“——你会发现没有一个按钮能做这件事。&lt;/p&gt;
&lt;p&gt;设备 B 的三个旋钮看起来很简陋，但你知道它们能组合出无穷无尽的可能。&lt;/p&gt;
&lt;p&gt;Pi 就是那台“三个旋钮“的设备：&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;设备 B 的旋钮&lt;/th&gt;&lt;th&gt;Pi 的回调&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;低频&lt;/strong&gt;（基础音色的厚度）&lt;/td&gt;&lt;td&gt;&lt;code&gt;execute&lt;/code&gt;（决定 Agent 的工具做什么）&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;中频&lt;/strong&gt;（人声和乐器的清晰度）&lt;/td&gt;&lt;td&gt;&lt;code&gt;beforeToolCall&lt;/code&gt;（决定 Agent 能做什么）&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;高频&lt;/strong&gt;（空气感和空间感）&lt;/td&gt;&lt;td&gt;&lt;code&gt;transformContext&lt;/code&gt;（决定 Agent 看到什么）&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3 id=&quot;cong-san-ge-xuan-niu-dao-si-chong-ce-lue&quot;&gt;从三个旋钮到四种策略&lt;/h3&gt;
&lt;p&gt;同一个 &lt;code&gt;beforeToolCall&lt;/code&gt; 旋钮，拧出四种完全不同的问题：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;策略 1：交互式确认。&lt;/strong&gt; CLI 用户想每次危险操作都看到弹窗确认。&lt;code&gt;beforeToolCall&lt;/code&gt; 里调 &lt;code&gt;confirm(&quot;真的要删除整个 node_modules？&quot;)&lt;/code&gt; 返回 block 或 allow。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;策略 2：命令白名单。&lt;/strong&gt; CI/CD 场景不能有人交互。&lt;code&gt;beforeToolCall&lt;/code&gt; 里只允许命令匹配一个预定义前缀列表，其余全 block。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;策略 3：完全自动。&lt;/strong&gt; Docker 沙箱环境（如 Pi 的 Slack bot——mom），所有操作都发生在隔离容器里，搞不坏宿主系统。&lt;code&gt;beforeToolCall&lt;/code&gt; 永远返回 &lt;code&gt;undefined&lt;/code&gt;（不 block）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;策略 4：基于角色审批。&lt;/strong&gt; 内部工具的 admin 用户全放行，restricted 用户的危险工具 block。&lt;/p&gt;
&lt;p&gt;内置弹窗假设用户会用鼠标点“允许“或“拒绝“。&lt;code&gt;beforeToolCall&lt;/code&gt; 不做这种假设——它把决定权还给产品层。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;part-3-dong-shou-xie-yi-ge-extension-shi-gong-ju-xi-tong&quot;&gt;Part 3：动手——写一个“Extension 式“工具系统&lt;/h2&gt;
&lt;h3 id=&quot;wo-men-yao-zuo-shen-me&quot;&gt;我们要做什么&lt;/h3&gt;
&lt;p&gt;不依赖 Pi，用约 70 行 TypeScript 展示 Extension 系统的核心模式：&lt;strong&gt;事件订阅 + 工具注册 + 钩子干预&lt;/strong&gt;。实现一个“动态权限“系统——从 &lt;code&gt;beforeToolCall&lt;/code&gt; 一个钩子长出不同的安全策略。&lt;/p&gt;
&lt;h3 id=&quot;wan-zheng-dai-ma&quot;&gt;完整代码&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// extension-pattern-demo.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 演示 Pi 的 Extension 模式：事件 + 钩子 + 工具注册&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// ── 1. 类型定义 ──&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; EventMap&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  session_start&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span&gt; []&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  tool_call&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;span&gt; name&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; args&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Record&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; unknown&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt; }&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  agent_end&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;span&gt; finalAnswer&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; EventName&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = keyof&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; EventMap&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;interface&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; ToolDef&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  name&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  execute&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;args&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Record&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; unknown&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Promise&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;interface&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Extension&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  name&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  setup&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; ExtensionContext&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;interface&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; ExtensionContext&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  on&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;E&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; extends&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; EventName&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span&gt;event&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; E&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; handler&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;...&lt;/span&gt;&lt;span&gt;args&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; EventMap&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;E&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  registerTool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;tool&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; ToolDef&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// ── 2. 三种&amp;quot;安全策略&amp;quot;Extension ──&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 策略 A：交互式确认（CLI 用户）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;const&lt;/span&gt;&lt;span&gt; interactiveConfirmExt&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Extension&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;interactive-confirm&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  setup&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    const&lt;/span&gt;&lt;span&gt; DANGEROUS_TOOLS&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;bash&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;delete_file&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;write&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;on&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;tool_call&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, ({&lt;/span&gt;&lt;span&gt; name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; args&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; })&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      if&lt;/span&gt;&lt;span&gt; (DANGEROUS_TOOLS&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;includes&lt;/span&gt;&lt;span&gt;(name))&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // 生产环境这里会是真实的用户输入&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        console&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;  ⚠️  [interactive] 确认：&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;${&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;${&lt;/span&gt;&lt;span&gt;JSON&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;stringify&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;args&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;slice&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 50&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;...) ? 模拟用户点&amp;quot;允许&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;`&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 策略 B：白名单（CI/CD 无人值守）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;const&lt;/span&gt;&lt;span&gt; whitelistExt&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Extension&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;ci-whitelist&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  setup&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    const&lt;/span&gt;&lt;span&gt; WHITELIST&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;read&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;find&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;grep&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;ls&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;on&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;tool_call&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, ({&lt;/span&gt;&lt;span&gt; name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; })&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;!&lt;/span&gt;&lt;span&gt;WHITELIST&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;includes&lt;/span&gt;&lt;span&gt;(name))&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        console&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;  🚫 [whitelist] BLOCK: &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;${&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 不在 CI 白名单中&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;`&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 策略 C：基于时间窗口的动态权限&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;const&lt;/span&gt;&lt;span&gt; timeWindowExt&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Extension&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;time-window&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  setup&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;on&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;tool_call&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, ({&lt;/span&gt;&lt;span&gt; name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; })&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      const&lt;/span&gt;&lt;span&gt; hour&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Date&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getHours&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      if&lt;/span&gt;&lt;span&gt; (name&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ===&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;write&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span&gt; hour&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 9&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        console&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;  🔒 [time-window] BLOCK: 9 点前禁止写文件（当前 &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;${&lt;/span&gt;&lt;span&gt;hour&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;:00）&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;`&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// ── 3. Extension Runner（模拟 Pi 的 Runner + 两阶段初始化） ──&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; MiniExtensionRunner&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  private&lt;/span&gt;&lt;span&gt; tools&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Map&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; ToolDef&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  private&lt;/span&gt;&lt;span&gt; handlers&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Map&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;EventName&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Function&lt;/span&gt;&lt;span&gt;[]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  registerExtension&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ext&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Extension&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    const&lt;/span&gt;&lt;span&gt; ctx&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; ExtensionContext&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;      on&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: (&lt;/span&gt;&lt;span&gt;event&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; handler&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;!this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;handlers&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;has&lt;/span&gt;&lt;span&gt;(event))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;handlers&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;set&lt;/span&gt;&lt;span&gt;(event&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; [])&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;handlers&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span&gt;(event)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;push&lt;/span&gt;&lt;span&gt;(handler)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;      registerTool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: (&lt;/span&gt;&lt;span&gt;tool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;tools&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;set&lt;/span&gt;&lt;span&gt;(tool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; tool)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        console&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;  📦 注册工具: &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;${&lt;/span&gt;&lt;span&gt;tool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}`&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ext&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;setup&lt;/span&gt;&lt;span&gt;(ctx)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  async&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; executeTool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; args&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Record&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; unknown&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 触发 tool_call 事件（所有 Extension 的 handler 执行）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    const&lt;/span&gt;&lt;span&gt; handlers&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;handlers&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;tool_call&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ??&lt;/span&gt;&lt;span&gt; []&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;const&lt;/span&gt;&lt;span&gt; h&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; of&lt;/span&gt;&lt;span&gt; handlers)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;      h&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;span&gt; name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; args&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 执行工具&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    const&lt;/span&gt;&lt;span&gt; tool&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;tools&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span&gt;(name)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (tool)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return&lt;/span&gt;&lt;span&gt; tool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;execute&lt;/span&gt;&lt;span&gt;(args)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; `&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;工具 &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;${&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 未找到&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// ── 4. 跑起来 ──&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;async function&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; main&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  const&lt;/span&gt;&lt;span&gt; runner&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; MiniExtensionRunner&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  // 注册 Extension（每个实现一种安全策略）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  runner&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;registerExtension&lt;/span&gt;&lt;span&gt;(interactiveConfirmExt)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  runner&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;registerExtension&lt;/span&gt;&lt;span&gt;(whitelistExt)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  runner&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;registerExtension&lt;/span&gt;&lt;span&gt;(timeWindowExt)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  // 模拟 Agent 调用工具&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  console&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;模拟 write 工具调用：&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  await&lt;/span&gt;&lt;span&gt; runner&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;executeTool&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;write&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, {&lt;/span&gt;&lt;span&gt; path&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;config.ts&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span&gt; content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot; }&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  console&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;模拟 bash 工具调用：&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  await&lt;/span&gt;&lt;span&gt; runner&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;executeTool&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;bash&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, {&lt;/span&gt;&lt;span&gt; command&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;rm -rf /tmp/test&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot; }&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;main&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;yun-xing-xiao-guo&quot;&gt;运行效果&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; npx tsx extension-pattern-demo.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;模拟&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; write 工具调用：&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  ⚠️&lt;/span&gt;&lt;span&gt;  [interactive] 确认：write({&amp;quot;path&amp;quot;:&amp;quot;config.ts&amp;quot;,&amp;quot;content&amp;quot;:&amp;quot;...&amp;quot;}) ? 模拟用户点&amp;quot;允许&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  🚫&lt;/span&gt;&lt;span&gt; [whitelist] BLOCK: write 不在 CI 白名单中&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  🔒&lt;/span&gt;&lt;span&gt; [time-window] BLOCK: 9 点前禁止写文件（当前 15:00）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;模拟&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; bash 工具调用：&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  ⚠️&lt;/span&gt;&lt;span&gt;  [interactive] 确认：bash({&amp;quot;command&amp;quot;:&amp;quot;rm -rf /tmp/test&amp;quot;}) ? 模拟用户点&amp;quot;允许&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  🚫&lt;/span&gt;&lt;span&gt; [whitelist] BLOCK: bash 不在 CI 白名单中&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;guan-jian-she-ji-dian&quot;&gt;关键设计点&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;一个事件 → 多个 handler 并行执行。&lt;/strong&gt; 同一个 &lt;code&gt;tool_call&lt;/code&gt; 事件被三个 Extension 同时监听，每个按自己的规则判断。互不干扰，互不知晓对方的存在。这就是组合的力量。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Extension 之间完全解耦。&lt;/strong&gt; &lt;code&gt;interactiveConfirmExt&lt;/code&gt; 不知道 &lt;code&gt;whitelistExt&lt;/code&gt; 的存在，也不需要知道。只要它们都注册到 Runner，系统自动把事件分发给所有 handler。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;策略可叠加、可替换。&lt;/strong&gt; 你想换一种权限策略？关掉一个 Extension，注册另一个。不需要改 Runner 代码，不需要改其他 Extension。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;zong-jie&quot;&gt;总结&lt;/h2&gt;
&lt;p&gt;今天用一个“三个旋钮 vs 一百个按钮“的类比讲清了 Pi 最核心的设计哲学：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;“不内建“不是功能缺失&lt;/strong&gt;——是发现几乎所有产品功能都可以从三个回调（execute、beforeToolCall、transformContext）组合出来。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Extension 系统用“事件 + 钩子 + 工具注册“模式&lt;/strong&gt;——让第三方在不改核心的前提下扩展 Agent 能力。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Skill（Markdown）和 Extension（TypeScript）互补&lt;/strong&gt;——前者管文档层面（告诉 LLM 怎么做），后者管运行层面（实际执行操作）。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;xia-yi-qi-yu-gao&quot;&gt;下一期预告&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pi 的设计哲学：极简内核 + 反主流选择&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;最后一篇回顾 Pi 的整体哲学——为“用 24% 的代码驱动 100% 的产品形态“付出的代价是什么、这套架构的适用边界在哪、你应该在什么时候选择这种设计（以及什么时候不该）。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;em&gt;本文基于张汉东《&lt;a rel=&quot;external&quot; href=&quot;https://zhanghandong.github.io/pi-book/&quot;&gt;pi 的设计艺术&lt;/a&gt;》（CC BY-NC-SA 4.0）第 15-18 章内容改编。&lt;/em&gt;&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Pi 的设计哲学：极简内核、四个反主流选择与架构的适用边界</title>
        <published>2026-08-06T00:00:00+00:00</published>
        <updated>2026-08-06T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/pi-agent-series-04-design-philosophy/"/>
        <id>https://scp.net.cn/blog/pi-agent-series-04-design-philosophy/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/pi-agent-series-04-design-philosophy/">&lt;blockquote&gt;
&lt;p&gt;本文是 &lt;strong&gt;Pi Agent 系列教程&lt;/strong&gt;第 4 篇（完结篇）。基于张汉东《&lt;a rel=&quot;external&quot; href=&quot;https://zhanghandong.github.io/pi-book/&quot;&gt;pi 的设计艺术&lt;/a&gt;》第 30-32 章改编。前三篇讲清了 Pi 的架构、工具设计、Extension 系统。这一篇做哲学层面的总结——Pi 为什么选择这条路，以及你什么时候该走这条路。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;part-1-gai-nian-pi-de-she-ji-zhe-xue-quan-jing&quot;&gt;Part 1：概念——Pi 的设计哲学全景&lt;/h2&gt;
&lt;h3 id=&quot;24-zhe-ge-shu-zi&quot;&gt;24% 这个数字&lt;/h3&gt;
&lt;p&gt;Pi 的完整代码库里，内核（&lt;code&gt;pi-ai&lt;/code&gt; + &lt;code&gt;pi-agent-core&lt;/code&gt;）只占 24%。剩下 76% 是产品层和外壳层——会话管理、130+ 工具、Prompt 组装、Extension 系统、三种 UI、Slack 适配、GPU 部署工具。&lt;/p&gt;
&lt;p&gt;更精确地说，“真正的核心抽象”——StreamFunction、Context、Model 类型、agentLoop、Agent 类——总共不到 &lt;strong&gt;3000 行&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;这个数字不是碰巧。它是“极简核心、能力外置“哲学的可量化证据。内核只做三件事：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;统一模型调用&lt;/strong&gt;——20+ 厂商，一个接口&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;跑循环&lt;/strong&gt;——无状态双层循环 + 三阶段工具执行管线&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;管状态&lt;/strong&gt;——有状态 Agent 外壳 + 事件订阅 + 消息队列&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;其余一切都在外面。&lt;/p&gt;
&lt;h3 id=&quot;xie-yi-vs-kuang-jia&quot;&gt;协议 vs 框架&lt;/h3&gt;
&lt;p&gt;Pi 的设计可以用一句话概括：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“Agent 系统的核心应该是一个协议（事件流 + 回调），而不是一个框架（内建的功能集）。”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这个区别不是口头上讲的——它在每一行代码里：&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;你想做的事&lt;/th&gt;&lt;th&gt;框架方式&lt;/th&gt;&lt;th&gt;Pi 的协议方式&lt;/th&gt;&lt;th&gt;区别在哪&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;加一个工具&lt;/td&gt;&lt;td&gt;继承基类 + &lt;code&gt;@Tool()&lt;/code&gt; 装饰器&lt;/td&gt;&lt;td&gt;传一个符合 &lt;code&gt;AgentTool&lt;/code&gt; 接口的对象&lt;/td&gt;&lt;td&gt;框架管理生命周期；协议把工具当数据结构&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;换压缩策略&lt;/td&gt;&lt;td&gt;&lt;code&gt;setCompactionStrategy(&quot;summarize&quot;)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;实现 &lt;code&gt;transformContext&lt;/code&gt; 回调&lt;/td&gt;&lt;td&gt;框架预判你的需求；协议不预判任何东西&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;加权限控制&lt;/td&gt;&lt;td&gt;勾选“需要确认“配置项&lt;/td&gt;&lt;td&gt;实现 &lt;code&gt;beforeToolCall&lt;/code&gt; 回调&lt;/td&gt;&lt;td&gt;框架假设一种交互模式；协议不假设&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;从代码分布看，&lt;code&gt;pi-ai&lt;/code&gt; 有 ~27,000 行主要是 20+ 厂商各自的流式适配代码（每个厂商约 200-500 行）。&lt;strong&gt;这才是内核真正大的东西——不是抽象多，而是真实世界的厂商差异多。&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;si-ge-fan-zhu-liu-xuan-ze-bei-hou-de-tong-yi-yuan-ze&quot;&gt;四个反主流选择背后的统一原则&lt;/h3&gt;
&lt;p&gt;回顾第 3 篇的四件“不做的事“，现在可以给出每件的深层理由：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. 不做内建子 Agent。&lt;/strong&gt; 因为 &lt;code&gt;AgentLoop&lt;/code&gt; 是一个无全局状态的可组合纯函数——在工具执行的内部启动另一个循环是完全安全的。子 Agent 作为一个普通工具，拿到了自己的消息列表、自己的回调、自己的停止条件。不需要新的抽象层。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. 不做内建 MCP。&lt;/strong&gt; 因为 Extension + Skill 的组合覆盖了 MCP 的场景但以不同的方式：不需要跨进程通信、不需要额外配置、不需要进程管理。Skill 是最轻的方式——纯 Markdown 注入 System Prompt，零运行时开销。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. 不做内建权限弹窗。&lt;/strong&gt; 因为安全策略与产品形态强耦合。CLI 需要同步终端确认、Slack 需要异步消息、CI/CD 需要零交互。内建弹窗假设一种交互模式——这个假设在产品形态多样化时立即失效。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. 不做内建 Plan Mode。&lt;/strong&gt; 因为 Plan Mode 只是在不同阶段注入不同指令——planning 阶段注入“只做计划“、executing 阶段注入“按计划执行“、reviewing 阶段注入“检查结果“。&lt;code&gt;transformContext&lt;/code&gt; 已经能完成这个模式切换。内建 Plan Mode 会绑死确认方式——CLI 弹窗、Slack 消息、Web 弹窗——每种形式都需要不同的 UI。&lt;/p&gt;
&lt;h3 id=&quot;nei-he-de-bu-zuo-biao-zhun&quot;&gt;内核的“不做“标准&lt;/h3&gt;
&lt;p&gt;Pi 有一个明确的判断标准——一个功能是否该进内核，要过三道关：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. 功能是否依赖产品形态？&lt;/strong&gt; 权限确认的方式因 CLI/Slack/Web 而不同 → 外置。工具执行的位置因本地/Docker 而不同 → 外置。输出渲染因 TUI/Markdown/HTML 而不同 → 外置。事件类型定义必须统一 → 内置。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. 是否有多种等价的实现方式？&lt;/strong&gt; 压缩策略各异（LLM 摘要 / 时间截断 / token 预算）→ 外置为 &lt;code&gt;transformContext&lt;/code&gt; 回调。上下文变换有多种有效方法 → 外置为回调。消息的 LLM 格式因厂商而异 → 内置，在 Provider 层统一。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. 不一致是否产生不可预测的行为？&lt;/strong&gt; 事件类型定义必须统一 → 内置。工具执行的三阶段管线必须一致 → 内置。工具参数因场景而异 → 外置。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;part-2-lei-bi-le-gao-di-ban-vs-le-gao-tao-zhuang&quot;&gt;Part 2：类比——乐高底板 vs 乐高套装&lt;/h2&gt;
&lt;h3 id=&quot;liang-chong-mai-le-gao-de-fang-shi&quot;&gt;两种卖乐高的方式&lt;/h3&gt;
&lt;p&gt;想象两种卖乐高的策略：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;乐高套装&lt;/strong&gt;：一个盒子，里面有 500 块积木和一本说明书。你照着搭，得到一辆完美的消防车。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;乐高底板&lt;/strong&gt;：一块绿色底板，上面有均匀排列的凸起。没有任何说明书。你可以搭任何东西——消防车、城堡、飞船。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pi 是一块乐高底板。LangChain 是一个乐高套装。&lt;/p&gt;
&lt;p&gt;买乐高套装的人打开盒子就能开始。说明书是清楚的，结果是可预知的。代价是：如果你想搭的不是套装里的东西，你要么拆掉重来，要么买另一个套装。&lt;/p&gt;
&lt;p&gt;买乐高底板的人面临一个完全不同的挑战：没有任何说明书。但他们可以搭任何东西，而且中途改主意不需要拆掉已有的一切——积木的组合方式是无限的。&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;乐高套装（框架）&lt;/th&gt;&lt;th style=&quot;text-align: left&quot;&gt;乐高底板（Pi 的协议式设计）&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;开箱即用&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;需要自己组合&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;结果可预知&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;结果取决于你怎么组合&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;改了需求可能要拆掉重来&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;需求变了只需要调整组合方式&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;维护费在产品侧（买新套装）&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;维护费在理解侧（搞懂怎么组合）&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;适合：需求固定的单产品&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;适合：多变的多产品生态&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3 id=&quot;shen-me-shi-hou-bu-gai-yong-le-gao-di-ban&quot;&gt;什么时候不该用乐高底板&lt;/h3&gt;
&lt;p&gt;Pi 明确列出了自己的不适用场景：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;只需要一个 LLM 调用的简单场景&lt;/strong&gt;——不需要完整运行时，用 Vercel AI SDK 或直接调 API&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;需要与现有企业基础设施深度集成的场景&lt;/strong&gt;——商业产品（如 Cursor）提供更完整的解决方案&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;多 Agent 协作是核心需求的场景&lt;/strong&gt;——CrewAI、AutoGen 和 OpenAI Agents SDK 是更好的起点&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;团队只有 1-2 人且不需要支持多种产品形态&lt;/strong&gt;——框架的开发效率远高于自己组合&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;需要开箱即用的 Agent 产品&lt;/strong&gt;——Claude Code 或 Cursor 是更直接的选择&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;part-3-quan-xi-lie-hui-gu-shi-jian-lu-xian-tu&quot;&gt;Part 3：全系列回顾 + 实践路线图&lt;/h2&gt;
&lt;h3 id=&quot;cong-ling-dao-yi-da-jian-ni-de-di-yi-ge-pi-style-agent&quot;&gt;从零到一：搭建你的第一个 Pi-Style Agent&lt;/h3&gt;
&lt;p&gt;如果你想把 Pi 的设计理念应用到自己的 Agent 项目中，按这个顺序动手：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第 1 步：从 Agent Loop 开始（~80 行）&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 一个最小循环，验证&amp;quot;发动机&amp;quot;能转&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;async function&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; agentLoop&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;messages&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; tools&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; signal&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  while&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;true&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    const&lt;/span&gt;&lt;span&gt; resp&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = await&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; callLLM&lt;/span&gt;&lt;span&gt;(messages&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; tools&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; signal)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;!&lt;/span&gt;&lt;span&gt;resp&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;toolCalls)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return&lt;/span&gt;&lt;span&gt; resp&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;content&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    messages&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;push&lt;/span&gt;&lt;span&gt;(resp)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;const&lt;/span&gt;&lt;span&gt; tc&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; of&lt;/span&gt;&lt;span&gt; resp&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;toolCalls)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      const&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = await&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; executeTool&lt;/span&gt;&lt;span&gt;(tc)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      messages&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;push&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;span&gt; role&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;tool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span&gt; content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;第 2 步：拆出 Provider 层（~50 行）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;把 &lt;code&gt;callLLM&lt;/code&gt; 替换为一个可插拔的 Provider 接口。至少支持两家厂商（如 Anthropic + OpenAI），验证“换厂商不影响循环“。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第 3 步：加入 &lt;code&gt;beforeToolCall&lt;/code&gt; 钩子（~30 行）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在工具执行前插入：检查工具名和参数 → block 或 allow。实现一个最简单的“危险命令检测“——匹配 &lt;code&gt;rm -rf /&lt;/code&gt; 返回 block。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第 4 步：加入 &lt;code&gt;transformContext&lt;/code&gt; 钩子（~40 行）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在调 LLM 前插入：控制 LLM 看到什么。先实现最简单的“Token 预算控制“——当消息历史超过 10000 token 时，将最早的消息替换为 “[早期对话已压缩]”。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第 5 步：实现会话树（~100 行）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;用 JSONL + parentId 替代线性消息列表。实现分支和回退——在一个分支上做修改 C，退回到修改前的节点，另起一个分支做修改 D。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第 6 步：搭产品外壳&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;基于前 5 步的内核，选择你的产品形态：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;终端应用 → 用 React Ink 或 Blessed 做 TUI&lt;/li&gt;
&lt;li&gt;Slack Bot → 用 Bolt SDK&lt;/li&gt;
&lt;li&gt;Web 界面 → 用 Express + WebSocket&lt;/li&gt;
&lt;li&gt;API 服务 → 用 Fastify&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;每走一步，你都在“选择要不要把一个功能变成内建“。“不做“始终是一个有效选项。&lt;/p&gt;
&lt;h3 id=&quot;quan-xi-lie-si-pian-hui-gu&quot;&gt;全系列四篇回顾&lt;/h3&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;篇&lt;/th&gt;&lt;th&gt;主题&lt;/th&gt;&lt;th&gt;核心收获&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Pi 是什么&lt;/td&gt;&lt;td&gt;Agent 运行时处理的是“调完 LLM 之后发生什么“。四层洋葱 + 无状态 Loop = 多产品复用。&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;工具设计&lt;/td&gt;&lt;td&gt;给 LLM 设计工具就像给盲人设计菜单——结构化参数 + 精确约束 + 对 LLM 友好的错误信息。&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;能力外置&lt;/td&gt;&lt;td&gt;三个回调（execute / beforeToolCall / transformContext）组合出所有功能。不内建不是缺失，是更强的设计。&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;设计哲学&lt;/td&gt;&lt;td&gt;24% 代码驱动 100% 产品形态。协议胜于框架。知道什么时候不该用这种设计同样重要。&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;如果只记一句话，记住这个：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;内核是协议（事件流 + 回调），不是框架（内建功能集）。极简核心的强大不在它做了什么，而在它允许产品层做什么。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;fu-lu-pi-yu-tong-lei-gong-ju-de-ding-wei-chai-yi&quot;&gt;附录：Pi 与同类工具的定位差异&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;工具&lt;/th&gt;&lt;th&gt;核心定位&lt;/th&gt;&lt;th&gt;最适合&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Pi&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;多产品 Agent 运行时&lt;/td&gt;&lt;td&gt;你需要同一份引擎驱动 CLI/Slack/Web 三种产品形态&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Claude Code&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;单产品优化&lt;/td&gt;&lt;td&gt;你需要一个开箱即用的最强编程助手&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Cursor / Windsurf&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;IDE Agent&lt;/td&gt;&lt;td&gt;你已经在 IDE 里工作，上下文天然丰富&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Aider&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;垂直整合编辑&lt;/td&gt;&lt;td&gt;你只关心代码编辑效率和 diff 精度&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;LangChain&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;LLM 调用编排&lt;/td&gt;&lt;td&gt;你需要快速串联 prompt + chain + agent 的完整工作流&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;CrewAI / AutoGen&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;多 Agent 编排&lt;/td&gt;&lt;td&gt;多 Agent 协作是你核心需求&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;em&gt;本文基于张汉东《&lt;a rel=&quot;external&quot; href=&quot;https://zhanghandong.github.io/pi-book/&quot;&gt;pi 的设计艺术&lt;/a&gt;》（CC BY-NC-SA 4.0）第 30-32 章与全书内容改编。整个系列用费曼学习法（概念 → 类比 → 动手）重构原书核心架构决策为 4 篇渐进教程。&lt;/em&gt;&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Harness Engineering：让 AI 编码智能体“能用、可控、可维护”的工程体系</title>
        <published>2026-03-11T00:00:00+00:00</published>
        <updated>2026-03-11T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/harness-engineering/"/>
        <id>https://scp.net.cn/blog/harness-engineering/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/harness-engineering/">&lt;p&gt;近两年，大家对“AI 写代码”的讨论经常停留在两个层面：要么是模型能力的跃迁（更强的推理、更好的代码），要么是提示词技巧（Prompt Engineering）。但当你真的想把智能体放进一个持续演进的代码库里，让它能在几个月、几年尺度上持续贡献、持续修复、持续维护时，真正决定成败的往往不是模型，而是模型周围那套&lt;strong&gt;可操作、可验证、可演进&lt;/strong&gt;的工程系统。&lt;/p&gt;
&lt;p&gt;这套系统，越来越多的人开始用同一个词来概括：&lt;strong&gt;Harness Engineering&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;本文结合以下几篇材料的观点与案例，给出一个工程视角的中文梳理，并给出一套可以“从零搭一个最小可用 harness”的实践清单：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;https://martinfowler.com/articles/exploring-gen-ai/harness-engineering.html&lt;/li&gt;
&lt;li&gt;https://openai.com/zh-Hans-CN/index/harness-engineering/&lt;/li&gt;
&lt;li&gt;https://medium.com/be-open/what-is-ai-harness-engineering-your-guide-to-controlling-autonomous-systems-30c9c8d2b489&lt;/li&gt;
&lt;li&gt;https://engineering.harness.io/&lt;/li&gt;
&lt;li&gt;https://www.nxcode.io/resources/news/harness-engineering-complete-guide-ai-agent-codex-2026&lt;/li&gt;
&lt;li&gt;https://blog.langchain.com/improving-deep-agents-with-harness-engineering/&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;1-shen-me-shi-harness-engineering&quot;&gt;1. 什么是 Harness Engineering？&lt;/h2&gt;
&lt;p&gt;如果把智能体看作“动力很强但方向感不稳定”的马（或更夸张一点：Medium 文章里用的“幼龙”隐喻），那么 harness（马具、缰绳、鞍具）就是你用来把这股力量&lt;strong&gt;引导到正确方向&lt;/strong&gt;的一整套设施与规则。&lt;/p&gt;
&lt;p&gt;更工程化地说，Harness Engineering 是一门“搭系统”的学问：它关注的是&lt;strong&gt;如何围绕 AI 智能体构建一套可控、可重复、可观测、可验证的工作环境&lt;/strong&gt;，使得智能体能在你的目标函数下稳定产出，而不是偶尔灵光乍现、偶尔胡编乱造。&lt;/p&gt;
&lt;p&gt;它至少包含四类能力：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;告知它应该做什么&lt;/strong&gt;：把有效信息以合适方式送进上下文（Context Engineering）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;限制它不能做什么&lt;/strong&gt;：用结构化约束减少发散解空间（Architectural Constraints）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;验证它做得对不对&lt;/strong&gt;：把正确性转化为可执行的检查（测试、lint、CI、回归验证）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;它跑偏时如何纠偏&lt;/strong&gt;：把失败当信号，把“修复 harness”变成系统性反馈回路（含熵管理/垃圾回收）。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Martin Fowler 在读完 OpenAI 的文章后说，他喜欢“harness”这个词，因为它强调的是“让智能体在工程系统里被约束、被引导、被保持在可维护范围内”，而不是只靠一段大提示词寄希望于模型“自觉”。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;2-openai-de-ji-xian-shi-yan-ling-shou-xie-dai-ma-xian-ba-harness-bi-chu-lai&quot;&gt;2. OpenAI 的“极限实验”：零手写代码，先把 harness 逼出来&lt;/h2&gt;
&lt;p&gt;OpenAI 的 Codex 团队做了一个非常激进的 forcing function：&lt;strong&gt;不允许任何人手工写代码&lt;/strong&gt;。所有代码（应用逻辑、测试、CI、文档、可观测性、内部工具）都由智能体产出。5 个月后，他们宣称代码库规模达到百万行量级，并且经历了交付、部署、故障、修复的完整生命周期。&lt;/p&gt;
&lt;p&gt;无论你是否接受这个实验的全部外推结论，它至少把一个事实暴露得非常清楚：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;当“打字写代码”被禁止以后，工程师真正的工作，会迅速收敛为：设计环境、约束与反馈回路，让智能体可以可靠工作。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;OpenAI 文中有几条非常值得抄作业的关键经验：&lt;/p&gt;
&lt;h3 id=&quot;2-1-gei-zhi-neng-ti-di-tu-bu-yao-gei-qian-ye-shuo-ming-shu&quot;&gt;2.1 给智能体“地图”，不要给“千页说明书”&lt;/h3&gt;
&lt;p&gt;他们强调上下文是稀缺资源。一个庞杂的规则文件会变成陈旧规则的坟场：难以机械检查、容易漂移，最终变成噪声。&lt;/p&gt;
&lt;p&gt;因此他们不把 AGENTS.md 当百科全书，而更像一个&lt;strong&gt;目录/地图&lt;/strong&gt;：短小稳定，指向 repo 内结构化的 docs/ 体系，并用 linter/CI 检查文档的新鲜度、交叉链接与结构完整性。&lt;/p&gt;
&lt;h3 id=&quot;2-2-repo-shi-wei-yi-zhen-shi-shi-jie-zhi-neng-ti-kan-bu-dao-de-dong-xi-deng-yu-bu-cun-zai&quot;&gt;2.2 “Repo 是唯一真实世界”：智能体看不到的东西等于不存在&lt;/h3&gt;
&lt;p&gt;他们非常明确：从智能体角度，Google Docs、Slack 讨论、人脑里的决策都不可见。因此必须把关键知识“仓库化”：设计文档、执行计划、决策日志、技术债列表、质量评分……都版本化地放进 repo，形成可检索、可校验的记录系统。&lt;/p&gt;
&lt;h3 id=&quot;2-3-yong-jia-gou-yue-shu-huan-qu-su-du-yue-zao-yue-ying-de-bian-jie-yue-shao-piao-yi&quot;&gt;2.3 用架构约束换取速度：越早越硬的边界，越少漂移&lt;/h3&gt;
&lt;p&gt;OpenAI 认为智能体在“边界明确、结构可预测”的环境里效率最高。他们用了非常严格的分层约束（示例：Types → Config → Repo → Service → Runtime → UI），并通过自定义 linter 与结构测试机械执行依赖方向与允许的边。&lt;/p&gt;
&lt;p&gt;这背后是一条反直觉但关键的规律：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;对智能体来说，约束不是减速器，而是加速器。约束降低解空间，减少 token 浪费与死胡同探索。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;2-4-ba-pin-wei-bian-ma-cheng-bu-bian-liang-bing-ding-qi-zuo-la-ji-hui-shou&quot;&gt;2.4 把“品味”编码成不变量，并定期做“垃圾回收”&lt;/h3&gt;
&lt;p&gt;当吞吐量远超人类注意力时，漂移几乎必然发生：重复的 helper、命名发散、文档与代码不一致、坏模式扩散……&lt;/p&gt;
&lt;p&gt;他们的应对方式不是“每周五人工清理 AI 残渣”，而是把偏好与原则（例如更偏好共享工具包、拒绝 YOLO 式探测数据形状等）编码成可执行规则，并运行后台的 “doc-gardening / refactor agents” 定期扫描偏差、发起小而频繁的修复 PR，像垃圾回收一样持续对抗熵增。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;3-langchain-de-ke-fu-xian-shi-yan-mo-xing-bu-bian-zhi-gai-harness&quot;&gt;3. LangChain 的“可复现实验”：模型不变，只改 harness&lt;/h2&gt;
&lt;p&gt;LangChain 在一篇文章里给了一个非常工程化、可复现的论证：他们的 coding agent 在 Terminal Bench 2.0 上从 52.8% 提升到 66.5%，从 Top 30 到 Top 5，&lt;strong&gt;模型不变&lt;/strong&gt;（固定 gpt-5.2-codex），只改 harness。&lt;/p&gt;
&lt;p&gt;他们把 harness 的可调旋钮压缩到三类：System Prompt、Tools、Middleware（围绕模型/工具调用的钩子）。并且强调用 Traces（LangSmith）在规模化运行中定位失败模式，然后做针对性改动。&lt;/p&gt;
&lt;p&gt;其中几个改动非常典型，基本可以当作“最小可用 harness”的起点：&lt;/p&gt;
&lt;h3 id=&quot;3-1-qiang-zhi-build-verify-fix-rang-zhi-neng-ti-yang-cheng-ce-shi-bi-huan&quot;&gt;3.1 强制 build → verify → fix：让智能体养成测试闭环&lt;/h3&gt;
&lt;p&gt;一个常见失败模式是：智能体写完代码，扫一眼觉得“看起来对”，就停了——但没有跑测试，没有用事实反馈校验。&lt;/p&gt;
&lt;p&gt;LangChain 的做法包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在 system prompt 里明确“计划/发现 → 构建 → 验证 → 修复”的工作流。&lt;/li&gt;
&lt;li&gt;加一个 PreCompletionChecklistMiddleware：在智能体准备退出时拦截，提醒它对照任务规格跑验证。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;3-2-huan-jing-shang-xia-wen-zi-dong-zhu-ru-jian-shao-mang-sou-yu-wu-pan&quot;&gt;3.2 环境上下文自动注入：减少盲搜与误判&lt;/h3&gt;
&lt;p&gt;他们在 agent start 阶段用 LocalContextMiddleware 扫描目录结构、可用工具链（例如 Python 安装），把“地形图”注入上下文，降低探索成本与误差面。&lt;/p&gt;
&lt;h3 id=&quot;3-3-doom-loop-jian-ce-shi-bie-tong-yi-wen-jian-gai-10-ci-huan-mei-hao&quot;&gt;3.3 Doom Loop 检测：识别“同一文件改 10 次还没好”&lt;/h3&gt;
&lt;p&gt;他们用 LoopDetectionMiddleware 跟踪每个文件的编辑次数，达到阈值就提示“考虑换思路”。这类 guardrail 本质是在用工程手段对抗当前模型的典型短板。&lt;/p&gt;
&lt;h3 id=&quot;3-4-reasoning-sandwich-ba-suan-li-hua-zai-ji-hua-yu-yan-zheng-shang&quot;&gt;3.4 Reasoning Sandwich：把算力花在计划与验证上&lt;/h3&gt;
&lt;p&gt;在有超时约束的基准里，“全程最高推理”反而更差，因为会把时间/令牌预算烧在思考上导致超时。他们用一种启发式：规划阶段高推理、实现阶段中等、验证阶段再高推理。&lt;/p&gt;
&lt;p&gt;这类策略的价值不在于“某个固定配方”，而在于体现 harness 的思维方式：&lt;strong&gt;把隐含的过程控制显式化、可配置化、可度量化。&lt;/strong&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;4-san-da-zhi-zhu-yi-ge-jing-chang-bei-hu-lue-de-di-si-zhi-zhu&quot;&gt;4. 三大支柱 + 一个经常被忽略的第四支柱&lt;/h2&gt;
&lt;p&gt;结合 OpenAI、Fowler 的归纳以及业界总结，harness 常被分成三大块：&lt;/p&gt;
&lt;h3 id=&quot;4-1-context-engineering-shang-xia-wen-gong-cheng&quot;&gt;4.1 Context Engineering（上下文工程）&lt;/h3&gt;
&lt;p&gt;目标：让智能体在做决定时看见“正确的世界”，而不是在信息缺失下胡乱补全。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;静态上下文：repo 内的架构图、API 合同、风格指南、领域词表、变更流程&lt;/li&gt;
&lt;li&gt;动态上下文：日志/指标/追踪、真实运行环境、浏览器 DOM 快照、CI 结果&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;OpenAI 的一句话很关键：&lt;strong&gt;情境是一张地图，不是一本一千页说明书&lt;/strong&gt;。你需要的不是更长的规则，而是更好的信息组织、可检索性与可验证性。&lt;/p&gt;
&lt;h3 id=&quot;4-2-architectural-constraints-jia-gou-yue-shu&quot;&gt;4.2 Architectural Constraints（架构约束）&lt;/h3&gt;
&lt;p&gt;目标：把“好代码的边界条件”机械执行，而不是写在提示词里祈祷智能体自觉。&lt;/p&gt;
&lt;p&gt;典型手段：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;分层与依赖方向校验（结构测试）&lt;/li&gt;
&lt;li&gt;自定义 linter（含面向智能体的错误信息与修复指令）&lt;/li&gt;
&lt;li&gt;文件大小/命名约定/日志结构等“品味不变量”&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;4-3-entropy-management-shang-guan-li-la-ji-hui-shou&quot;&gt;4.3 Entropy Management（熵管理 / 垃圾回收）&lt;/h3&gt;
&lt;p&gt;目标：对抗长期漂移。智能体会复制既有模式，坏模式也会被规模化复制。&lt;/p&gt;
&lt;p&gt;典型手段：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;文档与代码一致性扫描（doc-gardening）&lt;/li&gt;
&lt;li&gt;偏差检测与自动重构 PR&lt;/li&gt;
&lt;li&gt;定期清理死代码、重复工具、循环依赖&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;4-4-verification-yan-zheng-hen-duo-wen-zhang-ti-de-bu-gou-dan-zhe-shi-cheng-bai-guan-jian&quot;&gt;4.4 Verification（验证）：很多文章提得不够，但这是成败关键&lt;/h3&gt;
&lt;p&gt;Fowler 在评论里明确指出：OpenAI 的分享更强调长期可维护性，但他“缺少对功能与行为验证”的讨论。&lt;/p&gt;
&lt;p&gt;从工程落地角度，我也认为验证是 harness 的第四支柱：没有可执行验证，系统就会退化成“写得像对的代码”。一旦把智能体当作生产级 contributor，你必须把“对不对”变成：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;可执行测试（单元/集成/端到端）&lt;/li&gt;
&lt;li&gt;可回归的基线（关键用户旅程、性能预算）&lt;/li&gt;
&lt;li&gt;可观测的事实（日志、trace、指标）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;否则智能体会在奖励不清晰时出现典型问题：Reward Hacking、目标偏移、只修表象不修根因。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;5-shu-yu-ti-xing-harness-engineering-harness-gong-si-gong-cheng-bo-ke&quot;&gt;5. 术语提醒：Harness Engineering ≠ Harness 公司工程博客&lt;/h2&gt;
&lt;p&gt;用户给的链接里包含 https://engineering.harness.io/ ，这是 CI/CD 平台 Harness 的工程博客站点。“Harness Engineering”在那里的含义更多是公司工程实践分享，并不等同于本文讨论的“面向 AI 智能体的 harness 工程体系”。&lt;/p&gt;
&lt;p&gt;不过这种“同词不同义”也很有趣：CI/CD、可观测性、变更审计、验证流水线……恰恰是 AI harness 里最需要被强化和自动化的部分。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;6-zen-me-da-yi-ge-zui-xiao-ke-yong-de-harness-cong-ge-ren-dao-tuan-dui&quot;&gt;6. 怎么搭一个“最小可用”的 Harness（从个人到团队）&lt;/h2&gt;
&lt;p&gt;如果你现在用 Claude/Codex/Cursor 来写代码，但经常遇到：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;代码能跑但不对、或只覆盖 happy path&lt;/li&gt;
&lt;li&gt;改完一个点引入另一个回归&lt;/li&gt;
&lt;li&gt;同一类错误反复出现（命名、目录结构、依赖层次、日志格式）&lt;/li&gt;
&lt;li&gt;代码库越写越“软”，风格漂移越来越大&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;那你需要的不是更花哨的提示词，而是一个最小可用 harness。下面给一套从易到难的 checklist：&lt;/p&gt;
&lt;h3 id=&quot;6-1-cang-ku-nei-di-tu-yu-he-tong&quot;&gt;6.1 仓库内“地图”与合同&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;一份短小稳定的入口文档（AGENTS.md / CLAUDE.md）：告诉智能体从哪里开始、规则在哪、如何验证&lt;/li&gt;
&lt;li&gt;docs/ 结构化知识库：架构分层图、领域边界、编码规范、关键流程（发布/迁移/回滚）&lt;/li&gt;
&lt;li&gt;明确接口合同：边界处的数据形状/Schema、错误码、事件格式（避免 YOLO 探测）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;6-2-qiang-zhi-yan-zheng-bi-huan&quot;&gt;6.2 强制验证闭环&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;让智能体默认先找测试、再补测试、最后跑测试&lt;/li&gt;
&lt;li&gt;在“准备结束”时加一个强制 checklist（可以是脚本、也可以是 middleware/hook）&lt;/li&gt;
&lt;li&gt;把关键用户路径做成可回归的 e2e（哪怕是 3 条最核心的旅程）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;6-3-jia-gou-yue-shu-ke-zhi-xing-hua&quot;&gt;6.3 架构约束可执行化&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;用结构测试或规则校验依赖方向（例如：domain 层不能 import ui 层）&lt;/li&gt;
&lt;li&gt;用 lint 强制日志结构、命名约定、文件大小、禁止某些危险模式&lt;/li&gt;
&lt;li&gt;让错误信息对智能体友好：给出修复建议，而不仅是“错了”&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;6-4-ke-guan-ce-xing-yu-fan-kui-xin-hao&quot;&gt;6.4 可观测性与反馈信号&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;把日志/指标/trace 接入，让智能体能读到运行事实&lt;/li&gt;
&lt;li&gt;把 CI 失败、基准回归当作第一类信号，驱动“修 harness”而不是“重试 10 次”&lt;/li&gt;
&lt;li&gt;保留 traces（尤其是失败轨迹）：为下一轮 harness 迭代提供数据&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;6-5-shang-guan-li-bie-deng-zhai-bao-liao-cai-zhong-gou&quot;&gt;6.5 熵管理（别等“债爆了”才重构）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;定期跑“清理/重构”任务：小步快跑、频繁合并&lt;/li&gt;
&lt;li&gt;扫描文档漂移、重复 util、循环依赖、无主代码&lt;/li&gt;
&lt;li&gt;把“品味”编码成规则或脚本，持续自动化执行&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;7-jie-yu-gong-cheng-shi-de-gong-zuo-zheng-zai-qian-yi-dao-zhi-cheng-jie-gou&quot;&gt;7. 结语：工程师的工作正在迁移到“支撑结构”&lt;/h2&gt;
&lt;p&gt;OpenAI 用“零手写代码”的极端实验告诉我们：当智能体成为主要执行者后，工程纪律并不会消失，它只是迁移了位置——从“每一行代码的手工精雕细琢”，迁移到“环境、约束、验证、反馈回路、熵管理”的支撑结构上。&lt;/p&gt;
&lt;p&gt;如果你希望把 AI 从“辅助写函数”升级为“可托管的生产力系统”，Harness Engineering 是绕不过去的一课。最好的入门方式不是再学十个提示词技巧，而是从一个最小可用 harness 开始：让知识进仓库、让验证可执行、让约束可强制、让失败可观测，并把漂移当作长期必然要治理的对象。&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Linux 内存与 PageCache 深度技术手册</title>
        <published>2026-02-27T10:00:00+08:00</published>
        <updated>2026-02-27T10:00:00+08:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/linux-memory-and-pagecache/"/>
        <id>https://scp.net.cn/blog/linux-memory-and-pagecache/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/linux-memory-and-pagecache/">&lt;h2 id=&quot;mu-lu&quot;&gt;目录&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Linux 内存模型概述&lt;/li&gt;
&lt;li&gt;PageCache 工作机制&lt;/li&gt;
&lt;li&gt;mmap vs read/write 深度对比&lt;/li&gt;
&lt;li&gt;PageCache 驱逐算法（LRU / Multi-Gen LRU）&lt;/li&gt;
&lt;li&gt;cgroup 对 PageCache 的隔离与限制机制&lt;/li&gt;
&lt;li&gt;NUMA 下 PageCache 分布机制&lt;/li&gt;
&lt;li&gt;THP（Transparent Huge Page）对 PageCache 的影响&lt;/li&gt;
&lt;li&gt;O_DIRECT 如何绕过 PageCache&lt;/li&gt;
&lt;li&gt;eBPF 监控 PageCache 命中率&lt;/li&gt;
&lt;li&gt;云原生数据库内存流动全景图&lt;/li&gt;
&lt;li&gt;数据库内核级性能调优手册&lt;/li&gt;
&lt;li&gt;实战案例：K8s 上 MySQL 性能抖动排查全过程&lt;/li&gt;
&lt;li&gt;总结：数据库 + 内核的真实交互模型&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;1-brain-linux-nei-cun-mo-xing-gai-shu&quot;&gt;1. 🧠 Linux 内存模型概述&lt;/h2&gt;
&lt;p&gt;Linux 内存并非“空闲才有价值”，而是遵循一个核心原则：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;可用内存都会被用于缓存。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;he-xin-nei-cun-fen-lei&quot;&gt;核心内存分类&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;匿名页（Anonymous Pages）&lt;/strong&gt;：应用程序动态分配的堆（heap）和栈（stack）内存，无文件背景。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;文件页（File Pages / PageCache）&lt;/strong&gt;：映射文件的内存页，用于缓存文件数据。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Slab&lt;/strong&gt;：内核对象缓存（dentry, inode 等）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;共享内存（Shmem）&lt;/strong&gt;：tmpfs, IPC 共享内存。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;页表（Page Tables）&lt;/strong&gt;：虚拟地址到物理地址的映射表。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;cha-kan-fang-fa&quot;&gt;查看方法&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;free&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -m&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /proc/meminfo&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;guan-jian-zi-duan-jie-xi&quot;&gt;关键字段解析&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cached&lt;/strong&gt;：PageCache 的大小（通常包含 Shmem）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Buffers&lt;/strong&gt;：块设备元数据的缓存。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dirty&lt;/strong&gt;：等待写入磁盘的脏页大小。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Active(file)&lt;/strong&gt;：最近被访问过的文件页（不易回收）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inactive(file)&lt;/strong&gt;：最近未被访问的文件页（优先回收）。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;2-rocket-pagecache-gong-zuo-ji-zhi&quot;&gt;2. 🚀 PageCache 工作机制&lt;/h2&gt;
&lt;p&gt;PageCache 是 Linux 文件 I/O 的统一缓存层。&lt;/p&gt;
&lt;h3 id=&quot;mo-ren-i-o-lu-jing&quot;&gt;默认 I/O 路径&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;mermaid&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;graph&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; LR&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Disk &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;--&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;gt; PageCache &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;--&amp;gt;&lt;/span&gt;&lt;span&gt; UserBuffer&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;(注：简单示意图，Markdown 渲染需支持 mermaid，若不支持可忽略)&lt;/em&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;磁盘 → PageCache → 用户缓冲区&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;he-xin-te-dian&quot;&gt;核心特点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;统一入口&lt;/strong&gt;：所有标准 &lt;code&gt;read/write&lt;/code&gt; 系统调用默认都经过 PageCache。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;mmap 映射&lt;/strong&gt;：&lt;code&gt;mmap&lt;/code&gt; 将文件直接映射到用户地址空间，实际上是直接映射了 PageCache 的物理页。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;sendfile 优化&lt;/strong&gt;：&lt;code&gt;sendfile&lt;/code&gt; 系统调用直接将 PageCache 中的数据拷贝到 socket buffer（或直接通过 DMA 发送），实现零拷贝。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;3-vs-mmap-vs-read-write-shen-du-dui-bi&quot;&gt;3. 🆚 mmap vs read/write 深度对比&lt;/h2&gt;
&lt;h3 id=&quot;3-1-read&quot;&gt;3.1 read()&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;路径&lt;/strong&gt;：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;磁盘 → PageCache → memcpy → 用户空间&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;特点&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;系统调用开销&lt;/strong&gt;：每次读写都需要发起系统调用（Context Switch）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;内存拷贝&lt;/strong&gt;：数据需要在内核态（PageCache）和用户态（User Buffer）之间进行一次拷贝。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;3-2-mmap&quot;&gt;3.2 mmap()&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;路径&lt;/strong&gt;：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;磁盘 → PageCache ↔ 页表映射 ↔ 用户空间&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;触发路径&lt;/strong&gt;：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;do_user_addr_fault&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  → handle_mm_fault&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    → filemap_fault&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;3-3-guan-jian-chai-yi-dui-bi-biao&quot;&gt;3.3 关键差异对比表&lt;/h3&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;项目&lt;/th&gt;&lt;th style=&quot;text-align: left&quot;&gt;read&lt;/th&gt;&lt;th style=&quot;text-align: left&quot;&gt;mmap&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;系统调用频率&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;高频（每次读写）&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;低（建立映射一次，后续缺页触发）&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;内存拷贝&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;有（内核→用户）&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;无（直接访问物理页）&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Page Fault&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;无（除非 buffer 未分配）&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;有（缺页加载时触发）&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;小块 I/O 性能&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;较慢（syscall 开销大）&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;更优（直接内存访问）&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;编程复杂度&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;低&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;高（需处理信号、对齐等）&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;4-broom-pagecache-qu-zhu-suan-fa&quot;&gt;4. 🧹 PageCache 驱逐算法&lt;/h2&gt;
&lt;p&gt;Linux 内核需要决定何时回收内存，以及回收哪些内存。&lt;/p&gt;
&lt;h3 id=&quot;4-1-jing-dian-lru-active-inactive&quot;&gt;4.1 经典 LRU（Active / Inactive）&lt;/h3&gt;
&lt;p&gt;每个 NUMA node 下维护了多条 LRU 链表：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;active_file&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;inactive_file&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;active_anon&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;inactive_anon&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;驱逐顺序（通常）&lt;/strong&gt;：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;inactive_file → active_file → inactive_anon → active_anon&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;File Pages 优先&lt;/strong&gt;：内核倾向于优先回收文件页（PageCache），因为它们是“干净”的（或易于写回），且可以重新从磁盘读取。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Swappiness&lt;/strong&gt;：&lt;code&gt;vm.swappiness&lt;/code&gt; 参数控制内核在回收匿名页和文件页之间的偏好。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;核心函数&lt;/strong&gt;：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;shrink_lruvec&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;4-2-multi-gen-lru-mglru&quot;&gt;4.2 Multi-Gen LRU（MGLRU）&lt;/h3&gt;
&lt;p&gt;新内核（Linux 6.1+）引入了多代 LRU 算法（Multi-Gen LRU）：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Generation 0 (Oldest)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Generation 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Generation 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Generation N (Youngest)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;优点&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;更精准的冷热识别&lt;/strong&gt;：通过多代际跟踪页面访问历史，避免“一次性扫描”导致的热数据误杀。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;降低 CPU 开销&lt;/strong&gt;：减少了锁竞争和遍历链表的开销。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;稳定性提升&lt;/strong&gt;：在大内存服务器和高并发场景下，显著减少了内存抖动和 OOM 风险。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;5-shield-cgroup-dui-pagecache-de-ge-chi-yu-xian-zhi-ji-zhi&quot;&gt;5. 🛡️ cgroup 对 PageCache 的隔离与限制机制&lt;/h2&gt;
&lt;p&gt;在 cgroup v2 中，PageCache 的管理更加精细。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;关键点：PageCache 计入 memory.current&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;cgroup-nei-cun-jie-gou&quot;&gt;cgroup 内存结构&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;mem_cgroup&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  → per-node lruvec&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;guan-jian-can-shu&quot;&gt;关键参数&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;memory.max&lt;/strong&gt;：硬限制。达到此限制时，触发 OOM Kill。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;memory.high&lt;/strong&gt;：软限制。达到此限制时，进程会被 throttle（强制休眠）并触发内存回收。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;memory.low&lt;/strong&gt;：保护阈值。尽量不回收低于此值的 cgroup 内存。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;memory.swap.max&lt;/strong&gt;：Swap 使用上限。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;hui-shou-ji-zhi&quot;&gt;回收机制&lt;/h3&gt;
&lt;p&gt;当某容器内存达到 &lt;code&gt;memory.high&lt;/code&gt; 时：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;触发 &lt;code&gt;memcg reclaim&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;内核尝试只回收该 cgroup 内的 PageCache 和匿名页。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;在 Kubernetes 中：&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;PageCache 也属于 Pod 内存消耗&lt;/strong&gt;。如果应用大量读写文件导致 PageCache 增长，可能会撑满 Pod 的内存限制，导致应用被 OOM Kill（如果未正确配置驱逐策略）。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;6-globe-with-meridians-numa-xia-pagecache-fen-bu-ji-zhi&quot;&gt;6. 🌐 NUMA 下 PageCache 分布机制&lt;/h2&gt;
&lt;p&gt;在 NUMA（Non-Uniform Memory Access）架构下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;本地分配&lt;/strong&gt;：默认情况下，PageCache 分配在当前发起 I/O 的 CPU 所在的 NUMA node 上。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;独立 LRU&lt;/strong&gt;：每个 NUMA node 都有自己独立的 LRU 链表和回收机制。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;cha-kan-numa-zhuang-tai&quot;&gt;查看 NUMA 状态&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;numactl&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; --hardware&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;numastat&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -m&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;feng-xian-yu-tiao-zhan&quot;&gt;风险与挑战&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;跨 Node 访问&lt;/strong&gt;：如果 CPU 0 频繁访问分配在 Node 1 上的 PageCache，会产生远程内存访问延迟。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;热点不均衡&lt;/strong&gt;：如果某个 Node 的内存被 PageCache 占满，可能会触发该 Node 的严重回收（Zone Reclaim），即使其他 Node 还有大量空闲内存。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;you-hua-jian-yi&quot;&gt;优化建议&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 绑定进程到特定 CPU 和内存 Node&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;numactl&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; --cpunodebind=0 --membind=0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;comman&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;7-elephant-thp-transparent-huge-page-dui-pagecache-de-ying-xiang&quot;&gt;7. 🐘 THP（Transparent Huge Page）对 PageCache 的影响&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;默认行为&lt;/strong&gt;：THP（透明大页）默认主要作用于&lt;strong&gt;匿名页&lt;/strong&gt;（Anonymous Pages），通常不直接作用于普通文件系统的 PageCache（tmpfs/shmem 除外）。&lt;/p&gt;
&lt;h3 id=&quot;qian-zai-feng-xian&quot;&gt;潜在风险&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Memory Compaction 抖动&lt;/strong&gt;：为了分配 2MB 的大页，内核需要整理内存碎片，这会导致 CPU 飙升和延迟增加（Latency Spike）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;内存放大&lt;/strong&gt;：小对象也占用大页，可能导致内存浪费。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;shu-ju-ku-huan-jing-jian-yi&quot;&gt;数据库环境建议&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;强烈建议关闭 THP&lt;/strong&gt;：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; never&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /sys/kernel/mm/transparent_hugepage/enabled&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; never&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /sys/kernel/mm/transparent_hugepage/defrag&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;8-motorway-o-direct-ru-he-rao-guo-pagecache&quot;&gt;8. 🛣️ O_DIRECT 如何绕过 PageCache&lt;/h2&gt;
&lt;h3 id=&quot;mo-ren-lu-jing-vs-o-direct&quot;&gt;默认路径 vs O_DIRECT&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;默认路径&lt;/strong&gt;：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;磁盘 → PageCache → 用户 buffer&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;使用 O_DIRECT&lt;/strong&gt;：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;open&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;file&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span&gt; O_DIRECT &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;|&lt;/span&gt;&lt;span&gt; O_RDWR&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;O_DIRECT 路径&lt;/strong&gt;：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;磁盘 → 用户 buffer&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;you-que-dian-fen-xi&quot;&gt;优缺点分析&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;优点&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;避免双重缓存&lt;/strong&gt;：数据库（如 MySQL, Oracle）通常有自己的 Buffer Pool，使用 O_DIRECT 避免了数据在 PageCache 和 Buffer Pool 中存两份。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;精准控制刷盘&lt;/strong&gt;：数据库可以精确控制数据何时持久化，符合 ACID 要求。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;减少 CPU 开销&lt;/strong&gt;：省去了内核态到用户态的内存拷贝。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;缺点&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;必须对齐&lt;/strong&gt;：内存缓冲区和文件偏移量必须按扇区大小（通常 512B 或 4KB）对齐。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;无 Readahead&lt;/strong&gt;：失去了内核自动预读的优化，需要应用自己实现预读。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;mysql-innodb-pei-zhi&quot;&gt;MySQL InnoDB 配置&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;innodb_flush_method&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&lt;/span&gt;&lt;span&gt;O_DIRECT&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;9-detective-ebpf-jian-kong-pagecache-ming-zhong-lu&quot;&gt;9. 🕵️ eBPF 监控 PageCache 命中率&lt;/h2&gt;
&lt;p&gt;传统工具（如 &lt;code&gt;free&lt;/code&gt;, &lt;code&gt;vmstat&lt;/code&gt;）只能看到总量，看不到命中率。eBPF 可以深入内核观测。&lt;/p&gt;
&lt;h3 id=&quot;guan-jian-zhi-biao&quot;&gt;关键指标&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Minor Fault&lt;/strong&gt;：内存中存在（PageCache 命中）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Major Fault&lt;/strong&gt;：内存中不存在，需读磁盘（PageCache 未命中）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;jian-dan-cha-kan&quot;&gt;简单查看&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /proc/[pid]/stat&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 关注第 10 (minflt) 和 12 (majflt) 列&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;shi-yong-bpftrace-shi-shi-zhui-zong&quot;&gt;使用 bpftrace 实时追踪&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 统计各进程触发的文件缺页次数&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;bpftrace&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -e&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;kprobe:filemap_fault { @[comm] = count(); }&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;bcc-gong-ju-ji-tui-jian&quot;&gt;BCC 工具集推荐&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;cachetop&lt;/strong&gt;：实时显示各进程的 PageCache 命中率。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fileslower&lt;/strong&gt;：追踪慢文件读写。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;biolatency&lt;/strong&gt;：统计块设备 I/O 延迟分布。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;10-cloud-yun-yuan-sheng-shu-ju-ku-nei-cun-liu-dong-quan-jing-tu&quot;&gt;10. ☁️ 云原生数据库内存流动全景图&lt;/h2&gt;
&lt;p&gt;以 MySQL 为例，在 Kubernetes 环境下的内存流动：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;用户查询&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   ↓&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;InnoDB Buffer Pool (用户态缓存)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   ↓ miss&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PageCache (内核态缓存) -- [受限于 memory.limit]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   ↓ miss&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;磁盘 (PV/PVC)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;kubernetes-pod-nei-cun-gou-cheng&quot;&gt;Kubernetes Pod 内存构成&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Pod memory.limit&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ├── Buffer Pool (匿名页)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ├── PageCache (文件页)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ├── Slab (内核对象)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ├── 线程栈 (匿名页)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  └── 页表&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;核心矛盾&lt;/strong&gt;：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;PageCache 和 Buffer Pool 都在同一个 &lt;code&gt;memory.limit&lt;/code&gt; 限制下竞争内存。&lt;/strong&gt;
如果 PageCache 增长过快，可能会导致 Buffer Pool 的内存申请失败（如果未预留），或者引发剧烈的内存回收。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;11-wrench-shu-ju-ku-nei-he-ji-xing-neng-diao-you-shou-ce&quot;&gt;11. 🔧 数据库内核级性能调优手册&lt;/h2&gt;
&lt;h3 id=&quot;11-1-huan-cun-ce-lue-xuan-ze&quot;&gt;11.1 缓存策略选择&lt;/h3&gt;
&lt;h4 id=&quot;mo-shi-a-shu-ju-ku-kong-huan-cun-tui-jian-mysql-oracle&quot;&gt;模式 A：数据库控缓存（推荐 MySQL/Oracle）&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;机制&lt;/strong&gt;：数据库维护巨大的 Buffer Pool。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;配置&lt;/strong&gt;：使用 &lt;code&gt;O_DIRECT&lt;/code&gt; 绕过 PageCache。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;优势&lt;/strong&gt;：数据库更懂数据热度，避免双重缓存浪费内存。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;mo-shi-b-yi-lai-os-huan-cun-ru-postgresql-elasticsearch-kafka&quot;&gt;模式 B：依赖 OS 缓存（如 PostgreSQL, Elasticsearch, Kafka）&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;机制&lt;/strong&gt;：利用 PageCache 进行缓存。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;配置&lt;/strong&gt;：标准 &lt;code&gt;read/write&lt;/code&gt; 或 &lt;code&gt;mmap&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;注意&lt;/strong&gt;：&lt;strong&gt;必须&lt;/strong&gt;为 OS 预留足够的内存用于 PageCache，不能将 &lt;code&gt;memory.limit&lt;/code&gt; 全部分配给 JVM Heap 或 Shared Buffers。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;11-2-tui-jian-nei-he-can-shu&quot;&gt;11.2 推荐内核参数&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 降低 swap 倾向，数据库尽量不 swap&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;vm.swappiness&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 脏页回写策略：控制脏页在内存中的比例，避免刷盘时 I/O 阻塞&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;vm.dirty_ratio&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;           # 绝对限制，超过此比例进程同步刷盘（阻塞）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;vm.dirty_background_ratio&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 5&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; # 后台回写阈值，超过此比例后台线程开始刷盘&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;vm.dirty_expire_centisecs&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 3000&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; # 脏页过期时间 30秒&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;11-3-cgroup-tui-jian-ce-lue-k8s&quot;&gt;11.3 cgroup 推荐策略（K8s）&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;resources&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;  requests&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    memory&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;8Gi&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;  limits&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    memory&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;8Gi&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; # BestEffort QoS 容易被驱逐，建议 Guaranteed&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;cgroup v2 下的微调（如果支持）&lt;/strong&gt;：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;memory.high&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; =&lt;/span&gt;&lt;span&gt; 90% * memory.max  &lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 提前触发回收，避免直接 OOM&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;memory.max&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  =&lt;/span&gt;&lt;span&gt; 100%&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;memory.low&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  =&lt;/span&gt;&lt;span&gt; 50% * memory.max  &lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 保护核心工作集不被轻易回收&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;11-4-numa-you-hua&quot;&gt;11.4 NUMA 优化&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;绑定 CPU&lt;/strong&gt;：&lt;code&gt;static&lt;/code&gt; CPU Manager policy (K8s)。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;关闭 NUMA 均衡&lt;/strong&gt;：&lt;code&gt;kernel.numa_balancing = 0&lt;/code&gt; (通常数据库自己管理更好)。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;BIOS 设置&lt;/strong&gt;：关闭 SNC (Sub-NUMA Clustering) 如果不需要极致的本地化优化。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;11-5-guan-bi-thp&quot;&gt;11.5 关闭 THP&lt;/h3&gt;
&lt;p&gt;生产环境数据库服务器强烈建议关闭：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 运行时关闭&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; never&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /sys/kernel/mm/transparent_hugepage/enabled&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; never&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /sys/kernel/mm/transparent_hugepage/defrag&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;12-boom-shi-zhan-an-li-k8s-shang-mysql-xing-neng-dou-dong-pai-cha&quot;&gt;12. 💥 实战案例：K8s 上 MySQL 性能抖动排查&lt;/h2&gt;
&lt;h3 id=&quot;bei-jing&quot;&gt;背景&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;应用&lt;/strong&gt;：MySQL 8.0&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;配置&lt;/strong&gt;：Pod &lt;code&gt;memory.limit&lt;/code&gt; = 8GB, &lt;code&gt;innodb_buffer_pool_size&lt;/code&gt; = 6GB&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;现象&lt;/strong&gt;：每隔一段时间，P99 延迟飙升，I/O 利用率打满，但 CPU 利用率不高。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;pai-cha-bu-zou&quot;&gt;排查步骤&lt;/h3&gt;
&lt;h4 id=&quot;1-jian-cha-memory-current&quot;&gt;1️⃣ 检查 memory.current&lt;/h4&gt;
&lt;p&gt;发现 &lt;code&gt;memory.current&lt;/code&gt; 长期接近 8GB（limit）。&lt;/p&gt;
&lt;h4 id=&quot;2-cha-kan-memory-events&quot;&gt;2️⃣ 查看 memory.events&lt;/h4&gt;
&lt;p&gt;查看 cgroup 的内存事件：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /sys/fs/cgroup/.../memory.events&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;发现 &lt;code&gt;high&lt;/code&gt; 计数持续增加，说明频繁触发了 cgroup 级的内存回收。&lt;/p&gt;
&lt;h4 id=&quot;3-cha-kan-page-fault&quot;&gt;3️⃣ 查看 Page Fault&lt;/h4&gt;
&lt;p&gt;使用 &lt;code&gt;sar -B&lt;/code&gt; 或 &lt;code&gt;vmstat&lt;/code&gt;，发现高峰期 &lt;code&gt;majflt&lt;/code&gt; (Major Fault) 激增。这意味读取数据时发生了物理磁盘 I/O。&lt;/p&gt;
&lt;h3 id=&quot;gen-yin-fen-xi&quot;&gt;根因分析&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;内存布局拥挤&lt;/strong&gt;：Buffer Pool 占 6GB，mysqld 自身开销 + 线程栈 + 系统开销可能占 1GB+。剩余给 PageCache 的空间不足 1GB。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;日志写入&lt;/strong&gt;：MySQL 生成 Binlog 和 Redo Log，这些是文件写入，会产生 PageCache（Dirty Pages）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;内存竞争&lt;/strong&gt;：日志产生的 PageCache 挤占了内存空间，导致 cgroup 达到限制。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;恶性循环&lt;/strong&gt;：内核为了释放内存，回收了部分“冷”的 Buffer Pool 页面（如果是 mmap 方式）或者其他必要的代码段/文件页。当 MySQL 再次访问这些页面时，触发 Major Fault，阻塞 I/O。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;jie-jue-fang-an&quot;&gt;解决方案&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;开启 O_DIRECT&lt;/strong&gt;：确保 &lt;code&gt;innodb_flush_method=O_DIRECT&lt;/code&gt;。这样 InnoDB 数据读写不占用 PageCache，只有 Binlog/Redo Log 占用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;限制 Dirty Ratio&lt;/strong&gt;：调低 &lt;code&gt;vm.dirty_ratio&lt;/code&gt;，让脏页更平滑地刷盘，避免瞬间积压占用大量内存。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;调整 Buffer Pool&lt;/strong&gt;：留出更多 Headroom。例如设置 Buffer Pool 为 5GB，给 OS 留出更多缓冲空间。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;关闭 THP&lt;/strong&gt;：消除 Compaction 带来的 CPU 抖动。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;结果&lt;/strong&gt;：调整后，Major Fault 降低 90%，P99 延迟恢复平稳。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;13-memo-zhong-ji-zong-jie-shu-ju-ku-nei-he-de-zhen-shi-jiao-hu-mo-xing&quot;&gt;13. 📝 终极总结：数据库 + 内核的真实交互模型&lt;/h2&gt;
&lt;h3 id=&quot;he-xin-mao-dun&quot;&gt;核心矛盾&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;裸机环境&lt;/strong&gt;：&lt;strong&gt;PageCache 与匿名页的全局竞争&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;容器环境&lt;/strong&gt;：&lt;strong&gt;memcg 限制 + PageCache 堆积 + NUMA 不均 + 脏页写回策略&lt;/strong&gt; 的叠加效应。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;diao-you-he-xin-si-yao-su&quot;&gt;调优核心四要素&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;决定谁管理缓存&lt;/strong&gt;：数据库自己管（O_DIRECT）还是交给 OS（PageCache）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;控制边界&lt;/strong&gt;：确保缓存（尤其是 PageCache）不会无限膨胀触碰 cgroup 限制。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;控制分布&lt;/strong&gt;：NUMA 绑定减少远程访问。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;控制节奏&lt;/strong&gt;：平滑脏页写回，避免 I/O 阻塞。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;yi-ju-hua-shou-wei&quot;&gt;一句话收尾&lt;/h2&gt;
&lt;p&gt;Linux 内存管理不是“内存够不够”的问题，而是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;缓存由谁控制，以及在什么边界内控制。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;em&gt;参考资料：&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;kernel.org, Linux Memory Management Documentation&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://zhuanlan.zhihu.com/p/585813632&quot;&gt;一文搞清楚linux系统内存详情：buffer/cache等 - 知乎&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://fanlv.fun/2020/09/13/linux-in-action/&quot;&gt;《Linux内核技术实战》&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://www.cyningsun.com/12-11-2024/linux-page-cache-minibook-cn.html&quot;&gt;译｜Linux Page Cache mini book&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://www.sunliaodong.cn/2021/03/11/Linux-PageCache%E8%AF%A6%E8%A7%A3/&quot;&gt;Linux PageCache详解 | 一蓑烟雨任平生&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://mingming.tech/2018/03/14/HighAvailability/2018-03-14-monitor-system/&quot;&gt;自用型监控系统方案 | 心静思远&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>OpenClaw：开启 AI Agent 时代的超级个体与变现思考</title>
        <published>2026-02-27T10:00:00+08:00</published>
        <updated>2026-02-27T10:00:00+08:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/openclaw-analysis/"/>
        <id>https://scp.net.cn/blog/openclaw-analysis/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/openclaw-analysis/">&lt;p&gt;随着 AI 技术的飞速发展，&lt;strong&gt;OpenClaw&lt;/strong&gt;（原 Clawdbot）作为一款强大的本地 AI Agent 工具，近期在技术圈引发了热烈讨论。它不仅代表了 AI 助理从简单的对话交互向深度任务执行的转变，更为开发者和自由职业者提供了全新的变现思路。本文将基于最新的技术动态，深入剖析 OpenClaw 的核心功能及其背后的商业价值。&lt;/p&gt;
&lt;h2 id=&quot;openclaw-shi-shen-me&quot;&gt;OpenClaw 是什么？&lt;/h2&gt;
&lt;p&gt;OpenClaw 是一个开源的、支持 &lt;strong&gt;MCP (Model Context Protocol)&lt;/strong&gt; 的本地 AI Agent 框架。它的核心愿景是让 AI 不仅仅是一个聊天机器人，而是一个能够理解意图、规划任务并执行操作的“数字员工”。&lt;/p&gt;
&lt;p&gt;与传统的 ChatGPT 或 Claude 等云端模型不同，OpenClaw 强调&lt;strong&gt;本地化部署&lt;/strong&gt;和&lt;strong&gt;深度集成&lt;/strong&gt;。它可以运行在用户的本地机器上，直接访问文件系统、操作软件、调用 API，甚至管理日历和邮件，从而实现真正意义上的“办公自动化”。&lt;/p&gt;
&lt;h2 id=&quot;he-xin-ji-shu-te-xing&quot;&gt;核心技术特性&lt;/h2&gt;
&lt;h3 id=&quot;1-agentic-workflow-dai-li-gong-zuo-liu&quot;&gt;1. Agentic Workflow（代理工作流）&lt;/h3&gt;
&lt;p&gt;OpenClaw 的强大之处在于其将自然语言指令转化为可执行步骤的能力。用户只需输入“帮我整理下周的会议并发送邮件给参会者”，OpenClaw 就能自动拆解任务：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;读取日历数据&lt;/li&gt;
&lt;li&gt;识别参会人员&lt;/li&gt;
&lt;li&gt;撰写邮件草稿&lt;/li&gt;
&lt;li&gt;调用邮件客户端发送&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这种从“意图”到“行动”的转化，是 AI Agent 的核心竞争力。&lt;/p&gt;
&lt;h3 id=&quot;2-mcp-model-context-protocol-zhi-chi&quot;&gt;2. MCP (Model Context Protocol) 支持&lt;/h3&gt;
&lt;p&gt;MCP 是近期 AI 领域的一个重要协议，旨在标准化模型与上下文（Context）之间的交互。OpenClaw 通过支持 MCP，能够更灵活地接入各种数据源和工具。这意味着开发者可以轻松编写插件，让 OpenClaw 读取 Notion 笔记、操作 GitHub 仓库，甚至控制智能家居设备。&lt;/p&gt;
&lt;h3 id=&quot;3-ben-di-you-xian-yu-yin-si-an-quan&quot;&gt;3. 本地优先与隐私安全&lt;/h3&gt;
&lt;p&gt;在数据隐私日益受到关注的今天，OpenClaw 的本地化特性显得尤为重要。所有敏感数据（如个人文档、密钥、通讯录）都无需上传云端，完全在本地处理。这不仅保障了隐私，也避免了网络延迟带来的性能瓶颈。&lt;/p&gt;
&lt;h2 id=&quot;bian-xian-mo-shi-fen-xi-ru-he-li-yong-openclaw-zhuan-qian&quot;&gt;变现模式分析：如何利用 OpenClaw 赚钱？&lt;/h2&gt;
&lt;p&gt;OpenClaw 的出现，让“超级个体”的概念不再遥远。对于技术人员和早期采用者来说，主要有以下几种变现路径：&lt;/p&gt;
&lt;h3 id=&quot;1-ji-neng-bao-yu-mo-ban-xiao-shou-selling-skill-packs&quot;&gt;1. 技能包与模板销售 (Selling Skill Packs)&lt;/h3&gt;
&lt;p&gt;就像 WordPress 有主题市场一样，OpenClaw 的生态系统也孕育了“技能包”市场。开发者可以编写特定的 Agent 技能（Skill），例如“自动化财报分析”、“社交媒体自动运营”或“跨境电商选品助手”，并将其打包出售。用户购买后，只需导入即可让自己的 OpenClaw 具备相应能力。&lt;/p&gt;
&lt;h3 id=&quot;2-ai-dai-yun-ying-yu-fu-wu-ai-operations&quot;&gt;2. AI 代运营与服务 (AI Operations)&lt;/h3&gt;
&lt;p&gt;利用 OpenClaw 强大的自动化能力，个人可以承接远超传统工作量的任务。例如，一个人可以同时运营 10 个社交媒体账号，或者为多家小微企业提供通过 AI 增强的客户服务。这种“一人成军”的模式，极大地降低了人力成本，提高了服务毛利。&lt;/p&gt;
&lt;h3 id=&quot;3-ding-zhi-hua-agent-kai-fa-custom-agent-development&quot;&gt;3. 定制化 Agent 开发 (Custom Agent Development)&lt;/h3&gt;
&lt;p&gt;许多非技术背景的企业主也希望利用 AI 提效，但缺乏部署和配置 OpenClaw 的能力。提供“代建助手”服务，为企业量身定制专属的 AI 员工（如自动处理订单的客服 Agent、自动搜集竞品信息的市场 Agent），将是一个高客单价的蓝海市场。&lt;/p&gt;
&lt;h3 id=&quot;4-zi-you-zhi-ye-zhe-de-xiao-lu-bei-zeng-qi&quot;&gt;4. 自由职业者的效率倍增器&lt;/h3&gt;
&lt;p&gt;对于自由职业者而言，OpenClaw 是最好的“副驾驶”。它可以处理发票、合同、日程安排等琐事，让你专注于核心业务。虽然这不是直接的“卖软件赚钱”，但通过提升单位时间的产出，间接实现了收入倍增。&lt;/p&gt;
&lt;h2 id=&quot;si-kao-yu-zhan-wang&quot;&gt;思考与展望&lt;/h2&gt;
&lt;p&gt;OpenClaw 的兴起，预示着软件交互范式的变革。未来，我们可能不再需要频繁点击 GUI 界面，而是通过自然语言指挥 Agent 去调用 API 完成工作。&lt;/p&gt;
&lt;p&gt;这也对传统的 SaaS 模式提出了挑战：当 AI Agent 可以直接与数据库或 API 交互时，繁琐的前端界面是否还有存在的必要？&lt;/p&gt;
&lt;p&gt;对于个人而言，掌握 OpenClaw 及其背后的 Agent 逻辑，不仅是学习一个新工具，更是为即将到来的“AI 原生经济”储备核心竞争力。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;注&lt;/strong&gt;：OpenClaw 作为一个强大的工具，其使用需遵守相关法律法规。技术本身中立，但使用者的意图决定了其价值。建议在合法合规的前提下探索其潜力。&lt;/p&gt;
&lt;/blockquote&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>给迷惘一代的哲学药方：当尼采、佛陀与老子在十字路口相遇</title>
        <published>2026-02-03T14:00:00+08:00</published>
        <updated>2026-02-03T14:00:00+08:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/guidance-for-the-lost-soul-five-philosophies/"/>
        <id>https://scp.net.cn/blog/guidance-for-the-lost-soul-five-philosophies/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/guidance-for-the-lost-soul-five-philosophies/">&lt;p&gt;在这个充满不确定性的时代，“迷惘”似乎成了我们共同的底色。&lt;/p&gt;
&lt;p&gt;我们在“内卷”与“躺平”之间反复横跳，在技术的加速与精神的空虚中不知所措。我们渴望答案，但传统的灯塔似乎都在风雨中摇曳不明。&lt;/p&gt;
&lt;p&gt;当你站在人生的十字路口，不知道该往哪里走时，不妨停下来，听听人类历史最智慧的五个声音。他们代表了五种截然不同的活法，五种看待世界的目光。它们不是标准答案，而是五剂药方，治愈不同症状的灵魂顽疾。&lt;/p&gt;
&lt;h2 id=&quot;di-yi-ji-yao-ni-cai-de-lie-jiu-gei-ke-wang-li-liang-bu-gan-ping-yong-de-ni&quot;&gt;第一剂药：尼采的烈酒 —— 给渴望力量、不甘平庸的你&lt;/h2&gt;
&lt;p&gt;如果你感到生活的平庸让你窒息，如果你厌倦了随波逐流，如果你觉得痛苦毫无意义，那么尼采是你的良药。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;核心指引：痛苦是成长的燃料，成为你自己的立法者。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;尼采对现代人的“末人”状态（追求安逸、毫无激情）嗤之以鼻。他告诉你，&lt;strong&gt;不要逃避痛苦&lt;/strong&gt;。痛苦不是需要被消除的错误，而是生命力爆发的契机。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;“热爱命运”（Amor fati）&lt;/strong&gt;：不要仅仅忍受你的命运，要热爱它。哪怕是生命中最艰难的时刻，也要把它视为塑造伟大自我的必要一环。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“自我克服”&lt;/strong&gt;：真正的超越不是等待救世主，而是依靠“权力意志”不断超越昨天的自己。你要做价值的创造者，而不是传统道德的盲从者。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;给迷惘者的建议：&lt;/strong&gt;
不要害怕特立独行，不要害怕痛苦。去创造属于你自己的价值体系，把每一次挫折都变成向上的台阶。像个战士一样去生活，在这个无意义的世界里，强力地创造出意义。&lt;/p&gt;
&lt;h2 id=&quot;di-er-ji-yao-fo-tuo-de-qing-cha-gei-jiao-lu-bu-an-zhi-nian-shen-zhong-de-ni&quot;&gt;第二剂药：佛陀的清茶 —— 给焦虑不安、执念深重的你&lt;/h2&gt;
&lt;p&gt;如果你被无尽的欲望折磨，如果你对未来充满恐惧，如果你觉得“我”太重，压得喘不过气，请喝下这杯清茶。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;核心指引：向内观看，痛苦源于执着，解脱在于放下。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;佛教一针见血地指出，人生本质是“苦”，而苦的根源在于我们对无常事物的执着，以及对一个恒常不变的“自我”的虚妄认同。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;“无我”&lt;/strong&gt;：你所以为的那个需要维护尊严、需要更多财富、需要别人认可的“我”，其实是一系列因缘聚合的假象。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“缘起性空”&lt;/strong&gt;：一切都在变化，没有什么是永恒的。接受无常，你就不再会被得失所困扰。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;给迷惘者的建议：&lt;/strong&gt;
试着做减法。当你焦虑时，问问自己：“我在执着什么？”当你愤怒时，问问自己：“是谁在愤怒？”通过正念与觉察，从情绪的漩涡中抽离出来。不需要向外抓取，平静就在你的内心。&lt;/p&gt;
&lt;h2 id=&quot;di-san-ji-yao-ji-du-de-sheng-can-gei-gu-du-wu-yi-xun-zhao-gui-shu-de-ni&quot;&gt;第三剂药：基督的圣餐 —— 给孤独无依、寻找归属的你&lt;/h2&gt;
&lt;p&gt;如果你感到个体的渺小与软弱，如果你在罪恶感中挣扎，如果你渴望一种超越世俗的、无条件的爱，这里有你的安慰。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;核心指引：承认软弱，在信仰与爱中获得新生。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;不同于尼采的强力意志，基督教让你学会&lt;strong&gt;谦卑&lt;/strong&gt;。它告诉你，人是不完美的，是有局限的，但这没关系。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;“信、望、爱”&lt;/strong&gt;：即便生活在黑暗中，也要心存盼望。其中最大的是爱——不仅是爱神，更是“爱邻如己”。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“交托”&lt;/strong&gt;：你不必独自背负一切重担。学会将你的忧虑、你的罪责交托给那个更高的存在。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;给迷惘者的建议：&lt;/strong&gt;
不要试图独自硬抗所有的风雨。承认自己的脆弱不是羞耻。去爱具体的人，去建立真实的连接。在服务他人和信仰中，你会发现原本破碎的自我得到了修复。&lt;/p&gt;
&lt;h2 id=&quot;di-si-ji-yao-kong-zi-de-gan-liang-gei-zai-she-hui-ze-ren-zhong-zheng-zha-xun-qiu-ru-shi-jia-zhi-de-ni&quot;&gt;第四剂药：孔子的干粮 —— 给在社会责任中挣扎、寻求入世价值的你&lt;/h2&gt;
&lt;p&gt;如果你在家庭、职场和社会关系中感到疲惫，但又无法割舍对他人的责任，如果你想在这个现实世界里踏实地做点什么，孔子是最好的导师。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;核心指引：在关系中找到坐标，通过修身实现社会价值。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;儒家不谈玄虚的彼岸，它只关注此时、此地、此人。人不是孤岛，人是关系的总和。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;“修齐治平”&lt;/strong&gt;：人生的意义是一步步扩大的。先把自己修养好，照顾好家庭，再推己及人去服务社会。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“知其不可而为之”&lt;/strong&gt;：即使世界崩坏，也要坚守内心的道义。这种坚韧的入世精神，是中国人骨子里的脊梁。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;给迷惘者的建议：&lt;/strong&gt;
不要空想，去行动。从好好对待父母开始，从认真完成手头的工作开始。在日常的伦理实践中，你会找到安身立命的感觉。做一个靠谱的人，比做一个深刻的人更难，也更重要。&lt;/p&gt;
&lt;h2 id=&quot;di-wu-ji-yao-lao-zi-de-shan-quan-gei-shen-xin-ju-pi-ke-wang-zi-you-de-ni&quot;&gt;第五剂药：老子的山泉 —— 给身心俱疲、渴望自由的你&lt;/h2&gt;
&lt;p&gt;如果你觉得现代社会的规则太累，如果你厌倦了竞争和虚伪，如果你想从无休止的“进取”中逃离，老子在山林间等你。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;核心指引：顺应自然，无为而无不为，做减法的智慧。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;道教告诉你，人生的很多痛苦都是“人为”造作出来的。我们离“道”（自然规律）太远了。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;“道法自然”&lt;/strong&gt;：像水一样生活（上善若水），柔软却有力量，利万物而不争。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“返璞归真”&lt;/strong&gt;：剥离掉那些复杂的社会标签、名利欲望，回到生命最本真的状态。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“无为”&lt;/strong&gt;：不是什么都不做，而是不妄为，顺势而为。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;给迷惘者的建议：&lt;/strong&gt;
学会“躺平”的艺术——不是摆烂，而是不再与生活死磕。给自己留白，去亲近自然。在这个加法过度的时代，试着过一种“低欲望、高自由”的生活。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;jie-yu-ni-de-yao-fang-you-ni-zi-ji-diao-zhi&quot;&gt;结语：你的药方，由你自己调制&lt;/h2&gt;
&lt;p&gt;这五种思想体系，指向了五个不同的方向：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;尼采&lt;/strong&gt;指向上方，那是&lt;strong&gt;创造&lt;/strong&gt;的高度；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;佛陀&lt;/strong&gt;指向内部，那是&lt;strong&gt;解脱&lt;/strong&gt;的深度；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;基督&lt;/strong&gt;指向彼岸，那是&lt;strong&gt;信仰&lt;/strong&gt;的热度；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;孔子&lt;/strong&gt;指向人间，那是&lt;strong&gt;责任&lt;/strong&gt;的广度；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;老子&lt;/strong&gt;指向自然，那是&lt;strong&gt;自由&lt;/strong&gt;的风度。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;你不需要完全皈依某一种。&lt;/p&gt;
&lt;p&gt;当你需要勇气时，读读尼采；当你焦虑失眠时，想想佛陀；当你感到冷漠时，学学基督；当你想要做事时，效法孔子；当你身心俱疲时，跟随老子。&lt;/p&gt;
&lt;p&gt;人生没有标准答案，迷惘正是因为可能性的存在。愿你在这五种智慧的交响中，找到属于你自己的旋律。&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>给 Java 插上翅膀：Alibaba Dragonwell Wisp 协程深度解析与实战避坑指南</title>
        <published>2026-02-01T12:00:00+08:00</published>
        <updated>2026-02-01T12:00:00+08:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/alibaba-dragonwell-wisp-coroutine-practice/"/>
        <id>https://scp.net.cn/blog/alibaba-dragonwell-wisp-coroutine-practice/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/alibaba-dragonwell-wisp-coroutine-practice/">&lt;p&gt;在云原生时代，高并发已成为后端服务的标配。Java 作为服务端霸主，其传统的 1:1 线程模型（一个 Java 线程对应一个内核线程）在面对海量轻量级任务时，往往因频繁的内核态/用户态切换和高昂的内存开销而显得力不从心。&lt;/p&gt;
&lt;p&gt;Go 语言凭借 Goroutine 协程机制在并发领域异军突起，让 Java 开发者羡慕不已。虽然 OpenJDK 的 Project Loom（Virtual Threads）已经正式发布，但在它到来之前，阿里巴巴 Dragonwell JDK 的 &lt;strong&gt;Wisp 协程&lt;/strong&gt;技术早已在电商核心生产环境经历了数次双十一的考验。&lt;/p&gt;
&lt;p&gt;本文将深入解析 Wisp 协程的原理，提供实战案例，并重点揭示那些官方文档中鲜少提及的“深坑”。&lt;/p&gt;
&lt;h2 id=&quot;yi-wei-shen-me-wo-men-xu-yao-wisp&quot;&gt;一、 为什么我们需要 Wisp？&lt;/h2&gt;
&lt;h3 id=&quot;1-1-java-chuan-tong-xian-cheng-mo-xing-de-tong-dian&quot;&gt;1.1 Java 传统线程模型的痛点&lt;/h3&gt;
&lt;p&gt;Java 的 &lt;code&gt;java.lang.Thread&lt;/code&gt; 默认对应操作系统的内核线程（Kernel Thread）。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;调度开销大&lt;/strong&gt;：线程的挂起和唤醒需要内核介入，涉及昂贵的上下文切换（Context Switch）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;资源消耗高&lt;/strong&gt;：每个线程需要独立的栈空间（默认 1MB），数万个线程会迅速耗尽内存。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;并发瓶颈&lt;/strong&gt;：受限于 OS 调度能力，单机支撑的线程数通常在几千级别，难以应对数十万并发连接。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;1-2-wisp-de-jie-jue-fang-an-m-n-mo-xing&quot;&gt;1.2 Wisp 的解决方案：M:N 模型&lt;/h3&gt;
&lt;p&gt;Wisp 是在 JVM 层面实现的&lt;strong&gt;有栈对称式协程&lt;/strong&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;用户态调度&lt;/strong&gt;：Wisp 在 JVM 内部维护了一个调度器，将大量的 Java 线程（协程）映射到少量的内核线程（称为 &lt;strong&gt;Carrier Threads&lt;/strong&gt;）上。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;完全兼容&lt;/strong&gt;：这是 Wisp 最大的杀手锏。它不需要你学习类似 &lt;code&gt;async/await&lt;/code&gt; 的新语法，也不需要像 Kotlin 协程那样修改代码。&lt;strong&gt;你写的还是 &lt;code&gt;Thread&lt;/code&gt;，但在底层，它变成了协程。&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当你的代码调用 &lt;code&gt;InputStream.read()&lt;/code&gt; 或 &lt;code&gt;Thread.sleep()&lt;/code&gt; 时，Wisp 会拦截这些调用，挂起当前协程，释放 Carrier 线程去执行其他任务。等到数据准备好或时间到达，协程会被自动唤醒。&lt;/p&gt;
&lt;h2 id=&quot;er-shi-zhan-cong-0-dao-1-ti-yan-wisp&quot;&gt;二、 实战：从 0 到 1 体验 Wisp&lt;/h2&gt;
&lt;h3 id=&quot;2-1-huan-jing-zhun-bei&quot;&gt;2.1 环境准备&lt;/h3&gt;
&lt;p&gt;Wisp 是 Alibaba Dragonwell JDK 的特性。你需要下载安装 Dragonwell 8 或 11+。&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 示例：安装 Dragonwell (以 Linux 为例)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;wget&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; https://github.com/dragonwell-project/dragonwell8/releases/download/dragonwell-standard-8.16.17_jdk8u382-ga/Alibaba_Dragonwell_Standard_8.16.17_x64_linux.tar.gz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tar&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -zxvf Alibaba_Dragonwell_Standard_8.16.17_x64_linux.tar.gz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;export&lt;/span&gt;&lt;span&gt; JAVA_HOME&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt;/path/to/dragonwell&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;export&lt;/span&gt;&lt;span&gt; PATH&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt;$JAVA_HOME/bin:$PATH&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;2-2-xing-neng-dui-bi-pingpong-ce-shi&quot;&gt;2.2 性能对比：PingPong 测试&lt;/h3&gt;
&lt;p&gt;我们通过一个经典的 PingPong 测试来模拟高频上下文切换场景。&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; java&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;util&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;concurrent&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;public class&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; PingPong&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    static final&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; ExecutorService&lt;/span&gt;&lt;span&gt; THREAD_POOL&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; Executors&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;newCachedThreadPool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public static void&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; main&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[]&lt;/span&gt;&lt;span&gt; args&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; throws&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Exception&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        BlockingQueue&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Byte&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; q1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; LinkedBlockingQueue&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&amp;gt;(),&lt;/span&gt;&lt;span&gt; q2 &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;= new&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; LinkedBlockingQueue&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&amp;gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // 模拟两个线程互相投递数据&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        THREAD_POOL&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;submit&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(()&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; pingpong&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;q2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; q1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        Future&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; f&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; THREAD_POOL&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;submit&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(()&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; pingpong&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;q1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; q2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        q1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;byte&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; // 启动&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        System&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;out&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Cost: &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span&gt; f&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; ms&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        THREAD_POOL&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;shutdown&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    private static long&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; pingpong&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;BlockingQueue&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Byte&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; BlockingQueue&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Byte&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; out&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; throws&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Exception&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        long&lt;/span&gt;&lt;span&gt; start&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; System&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;currentTimeMillis&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // 互相传递 100 万次，极高频的阻塞/唤醒&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        for&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;int&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1_000_000&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span&gt; out&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;in&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;take&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;())&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return&lt;/span&gt;&lt;span&gt; System&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;currentTimeMillis&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; -&lt;/span&gt;&lt;span&gt; start&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;运行结果对比：&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;普通 Java 模式&lt;/strong&gt;：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;java&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; PingPong&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 输出: Cost: 2346 ms (具体视机器性能)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;开启 Wisp 模式&lt;/strong&gt;：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# -XX:+UseWisp2: 开启 Wisp2 协程&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# -XX:ActiveProcessorCount=1: 限制 Carrier 线程数为 1，强制在单核上调度，测试极致切换性能&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;java&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -XX:+UnlockExperimentalVMOptions -XX:+UseWisp2 -XX:ActiveProcessorCount=1 PingPong&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 输出: Cost: 180 ms&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;性能提升超过 10 倍！&lt;/strong&gt; 原因在于 Wisp 将 &lt;code&gt;LinkedBlockingQueue&lt;/code&gt; 的 &lt;code&gt;put/take&lt;/code&gt; 导致的线程阻塞转换为了协程挂起，完全在用户态完成，避免了 200 万次内核系统调用。&lt;/p&gt;
&lt;h2 id=&quot;san-shen-du-bi-keng-zhi-nan-wisp-bu-shi-yin-dan&quot;&gt;三、 深度避坑指南：Wisp 不是银弹&lt;/h2&gt;
&lt;p&gt;虽然官方宣称“透明兼容”，但在实际生产环境，如果不理解 Wisp 的调度原理，很容易踩到致命的坑。&lt;strong&gt;Wisp 的核心原则是：千万不要阻塞 Carrier 线程。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Carrier 线程通常与 CPU 核心数相当（例如 8 核机器有 8 个 Carrier）。一旦 Carrier 被阻塞，就相当于减少了一个 CPU 核心的算力；如果所有 Carrier 都在等待 OS 锁或 IO，整个 JVM 就会“假死”。&lt;/p&gt;
&lt;h3 id=&quot;3-1-zhi-ming-xian-jing-yi-jni-yu-native-dai-ma&quot;&gt;3.1 致命陷阱一：JNI 与 Native 代码&lt;/h3&gt;
&lt;p&gt;这是 Wisp 最大的盲区。Wisp 只能拦截 JDK 内部的 Java 方法调用。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;现象&lt;/strong&gt;：如果你调用了一个 JNI 方法（例如某些压缩库、加密库或旧版驱动），而这个 Native 方法内部执行了阻塞式 IO 或 &lt;code&gt;sleep&lt;/code&gt;，JVM 是无法感知的。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;后果&lt;/strong&gt;：该操作会直接阻塞底层的 Carrier 线程。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;避坑&lt;/strong&gt;：审查所有第三方依赖，确保没有在核心路径上使用执行长时间阻塞操作的 Native 库。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;3-2-zhi-ming-xian-jing-er-thread-sleep-de-wu-jie&quot;&gt;3.2 致命陷阱二：Thread.sleep() 的误解&lt;/h3&gt;
&lt;p&gt;虽然 Wisp 已经 Hook 了 &lt;code&gt;java.lang.Thread.sleep()&lt;/code&gt;，将其转化为非阻塞的定时器等待，但这并不意味着你可以滥用它。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;坑点&lt;/strong&gt;：不要在循环中使用极短时间的 &lt;code&gt;sleep&lt;/code&gt; (如 &lt;code&gt;sleep(0)&lt;/code&gt; 或 &lt;code&gt;sleep(1)&lt;/code&gt;) 来做自旋等待。在协程模式下，频繁的调度开销虽然降低了，但大量的微小休眠仍会增加调度器的负担。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;更深层的坑&lt;/strong&gt;：如果你的代码通过反射或其他 Hack 手段绕过了 JDK 标准库，直接调用了 &lt;code&gt;Unsafe.park&lt;/code&gt; 或其他底层原语，且该原语未被 Wisp 适配，同样会阻塞 Carrier。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;3-3-zhi-ming-xian-jing-san-synchronized-yu-suo-jing-zheng&quot;&gt;3.3 致命陷阱三：synchronized 与 锁竞争&lt;/h3&gt;
&lt;p&gt;Wisp 对 &lt;code&gt;synchronized&lt;/code&gt; 关键字做了优化，使其在竞争锁时挂起协程而非阻塞线程。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;风险&lt;/strong&gt;：如果锁内的临界区代码执行时间过长（例如在 &lt;code&gt;synchronized&lt;/code&gt; 块里做 IO），或者锁竞争极其激烈，依然会导致性能抖动。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;建议&lt;/strong&gt;：尽量使用 &lt;code&gt;java.util.concurrent&lt;/code&gt; 包下的 &lt;code&gt;ReentrantLock&lt;/code&gt; 等高级锁，Wisp 对 JUC 的适配通常比对 Monitor 锁的适配更完善。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;3-4-zhi-ming-xian-jing-si-cpu-mi-ji-xing-ren-wu-the-starvation-problem&quot;&gt;3.4 致命陷阱四：CPU 密集型任务 (The Starvation Problem)&lt;/h3&gt;
&lt;p&gt;Wisp 是&lt;strong&gt;协作式调度&lt;/strong&gt;（尽管有抢占机制，但并不如 OS 调度器暴力）。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;场景&lt;/strong&gt;：如果一个协程执行死循环计算（如加密解密、大数运算）且不进行任何 IO 或 sleep 操作。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;后果&lt;/strong&gt;：该协程会长期霸占 Carrier 线程，导致同一 Carrier 队列中的其他协程（比如处理 HTTP 请求的协程）无法得到执行机会，产生“饥饿”现象。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;避坑&lt;/strong&gt;：Wisp 专为 &lt;strong&gt;IO 密集型&lt;/strong&gt;场景设计。如果必须在 Wisp 应用中处理 CPU 密集型任务，请将其放入单独的普通线程池（通过配置排除 Wisp 管理），或者手动在计算中插入 &lt;code&gt;Thread.yield()&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;3-5-xian-jing-wu-threadlocal-de-nei-cun-peng-zhang&quot;&gt;3.5 陷阱五：ThreadLocal 的内存膨胀&lt;/h3&gt;
&lt;p&gt;在传统模式下，线程数有限，ThreadLocal 占用的内存可控。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;风险&lt;/strong&gt;：在 Wisp 模式下，协程数量可能达到数十万。如果每个协程都在 ThreadLocal 中存放了 1MB 的大对象，内存会瞬间爆炸。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;建议&lt;/strong&gt;：务必在协程结束（请求结束）时清理 ThreadLocal；尽量减少 ThreadLocal 中存储的数据量。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;si-zong-jie&quot;&gt;四、 总结&lt;/h2&gt;
&lt;p&gt;Dragonwell Wisp 是 Java 生态中一个极具创新性的技术，它让 Java 开发者在 Loom 普及之前就能享受到协程的红利。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;适用场景&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;✅ IO 密集型应用（Web Server, Gateway, RPC Client）。&lt;/li&gt;
&lt;li&gt;✅ 大量并发连接（如长连接推送服务）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;不适用场景&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;❌ CPU 密集型计算（图像处理、科学计算）。&lt;/li&gt;
&lt;li&gt;❌ 强依赖 JNI 阻塞调用的遗留系统。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;使用 Wisp 时，请时刻牢记：&lt;strong&gt;你的“线程”不再是操作系统调度的了，请善待那个在底层默默扛活的 Carrier 线程。&lt;/strong&gt;&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>拒绝 &#39;Vibe Coding&#39; 的虚幻快感：深度解析 Spec-Driven Development (SDD) 与 AI 编程的未来</title>
        <published>2026-02-01T10:00:00+08:00</published>
        <updated>2026-02-01T10:00:00+08:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/spec-driven-development-depth-analysis/"/>
        <id>https://scp.net.cn/blog/spec-driven-development-depth-analysis/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/spec-driven-development-depth-analysis/">&lt;p&gt;在 2025 年的 AI 编程浪潮中，一个新的热词悄然兴起——&lt;strong&gt;Spec-Driven Development (SDD，规格驱动开发)&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;随着 AI 编码工具（如 Cursor, Windsurf, GitHub Copilot）的普及，开发者们陷入了一种被称为 &lt;strong&gt;“Vibe Coding” (氛围编码)&lt;/strong&gt; 的状态：你描述一个模糊的目标，AI 给你一段看起来不错的代码，你凭感觉（Vibe）运行它。如果跑通了，皆大欢喜；如果跑不通，就再试一次。&lt;/p&gt;
&lt;p&gt;然而，ThoughtWorks 的技术专家 Liu Shangqi 指出：“Vibe Coding 虽然快，但往往导致不可维护、充满缺陷的一次性代码。”&lt;/p&gt;
&lt;p&gt;为了解决这个问题，SDD 应运而生。它不是要回到繁琐的瀑布流，而是要让 AI 编程从“凭感觉”走向“有纪律”。本文将结合 &lt;strong&gt;Martin Fowler&lt;/strong&gt; 的最新观察、&lt;strong&gt;ThoughtWorks&lt;/strong&gt; 的深度思考，以及 &lt;strong&gt;GitHub Spec Kit&lt;/strong&gt; 的实战案例，带你深入理解这一编程范式。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;yi-shen-me-shi-sdd-ji-yu-martin-fowler-yu-thoughtworks-de-shi-jiao&quot;&gt;一、 什么是 SDD？(基于 Martin Fowler 与 ThoughtWorks 的视角)&lt;/h2&gt;
&lt;p&gt;SDD 的定义目前仍处于演变之中，但核心理念已逐渐清晰。&lt;/p&gt;
&lt;h3 id=&quot;1-martin-fowler-de-ding-yi-yu-fen-ji&quot;&gt;1. Martin Fowler 的定义与分级&lt;/h3&gt;
&lt;p&gt;软件开发教父 &lt;strong&gt;Martin Fowler&lt;/strong&gt; 在其文章《Understanding Spec-Driven-Development》中，对 SDD 进行了非常精准的定义。为了保留原意，我们引用他的核心观点：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“Spec-driven development means writing a ‘spec’ before writing code with AI (‘documentation first’). The spec becomes the source of truth for the human and the AI.”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;（SDD 意味着在使用 AI 写代码之前先写“规格说明书”（文档优先）。这份规格说明书成为了人类和 AI 共同的“单一事实来源”。）&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Fowler 敏锐地指出，目前的 SDD 工具其实处于三个不同的&lt;strong&gt;实现层级 (Implementation Levels)&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Level 1: Spec-first (规格优先)&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;原文&lt;/em&gt;：“A well thought-out spec is written first, and then used in the AI-assisted development workflow for the task at hand.”&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;解读&lt;/strong&gt;：先写好 Spec，再让 AI 写代码。任务完成后，Spec 可能就被丢在一边了。目前的 Spec Kit 和 Kiro 大多处于这个阶段。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Level 2: Spec-anchored (规格锚定)&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;原文&lt;/em&gt;：“The spec is kept even after the task is complete, to continue using it for evolution and maintenance of the respective feature.”&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;解读&lt;/strong&gt;：Spec 不仅用于生成代码，还被保留下来。后续维护时，必须先更新 Spec，再更新代码，Spec 是代码的“锚”。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Level 3: Spec-as-source (规格即源码)&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;原文&lt;/em&gt;：“The spec is the main source file over time, and only the spec is edited by the human, the human never touches the code.”&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;解读&lt;/strong&gt;：这是最激进的愿景。人类只写 Spec，代码完全是编译产物（Byproduct）。人类不再触碰代码文件。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;2-thoughtworks-de-shi-jiao-shang-xia-wen-gong-cheng&quot;&gt;2. ThoughtWorks 的视角：上下文工程&lt;/h3&gt;
&lt;p&gt;ThoughtWorks 的 &lt;strong&gt;Liu Shangqi&lt;/strong&gt; 则从&lt;strong&gt;上下文工程 (Context Engineering)&lt;/strong&gt; 的角度解读了 SDD。他认为：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“Prompt engineering optimizes human-LLM interaction, while context engineering optimizes agent-LLM interaction.”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;（提示词工程优化的是“人与大模型”的交互，而上下文工程优化的是“Agent 与大模型”的交互。）&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在 SDD 中，Spec 本质上就是一种被精心设计的、压缩了的上下文（Context）。通过将需求分析与编码实现分离，SDD 实际上是在进行一种高级的“少样本提示 (Few-shot prompting)”，用结构化的 Spec 来约束 AI 的发散性。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;er-shi-zhan-an-li-github-spec-kit-de-gong-zuo-liu&quot;&gt;二、 实战案例：GitHub Spec Kit 的工作流&lt;/h2&gt;
&lt;p&gt;Martin Fowler 提到的工具中，&lt;strong&gt;Spec Kit&lt;/strong&gt; 是目前最容易上手且开源的 SDD 工具集。虽然 GitHub 官方文档较为冗长，但我们可以将其核心工作流提炼为四个关键步骤。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Spec Kit 的核心哲学&lt;/strong&gt;：不要让 AI 猜你想做什么，而是用结构化的文档“驾驶”它。&lt;/p&gt;
&lt;h3 id=&quot;shi-zhan-yan-shi-kai-fa-yi-ge-ge-ren-zhao-pian-zheng-li-qi&quot;&gt;实战演示：开发一个“个人照片整理器”&lt;/h3&gt;
&lt;p&gt;假设我们要开发一个本地照片整理应用。在 Spec Kit 的模式下，我们不会直接对 AI 说“帮我写个相册应用”，而是遵循以下流程：&lt;/p&gt;
&lt;h4 id=&quot;1-que-li-xian-fa-constitution&quot;&gt;1. 确立宪法 (Constitution)&lt;/h4&gt;
&lt;p&gt;首先，Spec Kit 引入了 &lt;code&gt;Constitution&lt;/code&gt;（宪法）的概念。这是一份项目级的最高准则，AI 在生成任何内容时都必须遵守。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;内容示例&lt;/em&gt;：“所有数据库操作必须使用 SQLite”、“前端必须使用 Tailwind CSS”、“代码必须包含详细注释”。&lt;/li&gt;
&lt;li&gt;&lt;em&gt;作用&lt;/em&gt;：这就像是给 AI 戴上了“紧箍咒”，防止它在技术选型上放飞自我。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;2-ding-yi-gui-ge-specify&quot;&gt;2. 定义规格 (Specify)&lt;/h4&gt;
&lt;p&gt;这是 SDD 的起点。我们需要运行 &lt;code&gt;/speckit.specify&lt;/code&gt; 命令。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;输入&lt;/strong&gt;：自然语言描述（如“我想要一个按日期分组的照片墙，支持拖拽排序”）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AI 输出&lt;/strong&gt;：生成一份详细的 &lt;code&gt;spec.md&lt;/code&gt;。这份文档不会包含代码，而是包含：
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;用户旅程 (User Journey)&lt;/strong&gt;：用户如何打开应用，如何点击。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;功能边界&lt;/strong&gt;：明确什么要做，什么&lt;strong&gt;不做&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;成功标准&lt;/strong&gt;：如何判断功能已完成。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;em&gt;关键点&lt;/em&gt;：在这个阶段，你只关注“做什么 (What)”，完全不关注“怎么做 (How)”。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;3-ji-shu-ji-hua-plan&quot;&gt;3. 技术计划 (Plan)&lt;/h4&gt;
&lt;p&gt;有了 Spec 后，运行 &lt;code&gt;/speckit.plan&lt;/code&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;AI 输出&lt;/strong&gt;：生成 &lt;code&gt;plan.md&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;内容&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;架构设计&lt;/strong&gt;：选择 Vite + React。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;数据模型&lt;/strong&gt;：定义 &lt;code&gt;Photo&lt;/code&gt; 和 &lt;code&gt;Album&lt;/code&gt; 的数据库表结构。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;文件结构&lt;/strong&gt;：预估需要创建哪些文件。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;em&gt;关键点&lt;/em&gt;：这是将业务需求翻译成技术语言的过程。你可以在这里审查 AI 的技术选型是否合理。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;4-ren-wu-chai-jie-yu-zhi-xing-tasks-implement&quot;&gt;4. 任务拆解与执行 (Tasks &amp;amp; Implement)&lt;/h4&gt;
&lt;p&gt;最后，运行 &lt;code&gt;/speckit.tasks&lt;/code&gt; 和 &lt;code&gt;/speckit.implement&lt;/code&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AI 会将 &lt;code&gt;plan.md&lt;/code&gt; 拆解为一系列微小的、可执行的 Checklist（任务清单）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;执行&lt;/strong&gt;：AI 逐个勾选任务，生成代码，并通过测试。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;总结 Spec Kit 的模式&lt;/strong&gt;：它将“写代码”这个巨大的黑盒，拆解成了 &lt;strong&gt;意图 -&amp;gt; 规格 -&amp;gt; 计划 -&amp;gt; 任务 -&amp;gt; 代码&lt;/strong&gt; 的透明流水线。这正是“拒绝 Vibe Coding”的体现。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;san-shen-du-dui-bi-kiro-yu-tessl&quot;&gt;三、 深度对比：Kiro 与 Tessl&lt;/h2&gt;
&lt;p&gt;除了 Spec Kit，Martin Fowler 还深入体验了另外两款工具，它们的理念各有千秋。&lt;/p&gt;
&lt;h3 id=&quot;1-kiro-qing-liang-ji-de-spec-first&quot;&gt;1. Kiro：轻量级的 “Spec-first”&lt;/h3&gt;
&lt;p&gt;Martin Fowler 认为 Kiro 是最简单的工具。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;原文&lt;/em&gt;：“Kiro is the simplest (or most lightweight) one… Workflow: Requirements → Design → Tasks.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Kiro 的流程非常直观：&lt;strong&gt;需求 -&amp;gt; 设计 -&amp;gt; 任务&lt;/strong&gt;。它通过 VS Code 插件引导用户完成这三步。但 Fowler 也指出了它的局限性：对于复杂的、跨多个任务的长期维护，Kiro 似乎缺乏“Spec-anchored（规格锚定）”的机制。&lt;/p&gt;
&lt;h3 id=&quot;2-tessl-ji-jin-de-spec-as-source&quot;&gt;2. Tessl：激进的 “Spec-as-source”&lt;/h3&gt;
&lt;p&gt;Tessl 是 Fowler 眼中最独特的工具，因为它试图实现 SDD 的终极形态——&lt;strong&gt;Spec 即源码&lt;/strong&gt;。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;原文&lt;/em&gt;：“Tessl is the only one… that explicitly aspires to a spec-anchored approach… The code even marked with a comment at the top saying &lt;code&gt;// GENERATED FROM SPEC - DO NOT EDIT&lt;/code&gt;.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在 Tessl 的愿景中，开发者编辑的是 Spec 文件（可能是某种结构化的 Markdown 或 DSL），而 &lt;code&gt;.js&lt;/code&gt; 或 &lt;code&gt;.py&lt;/code&gt; 文件完全由 AI 自动生成，且不可手动编辑。这就像我们写 TypeScript 编译成 JavaScript 一样，未来我们将写 Spec 编译成 Code。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;si-tiao-zhan-yu-fan-si&quot;&gt;四、 挑战与反思&lt;/h2&gt;
&lt;p&gt;SDD 是否是灵丹妙药？Martin Fowler 和 ThoughtWorks 都给出了冷静的思考。&lt;/p&gt;
&lt;h3 id=&quot;1-shi-pu-bu-liu-de-hui-gui-ma&quot;&gt;1. 是“瀑布流”的回归吗？&lt;/h3&gt;
&lt;p&gt;很多人看到 SDD 的“先文档后编码”流程，会质疑这是不是倒退回了瀑布开发模型。
ThoughtWorks 的 Liu Shangqi 反驳道：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;原文&lt;/em&gt;：“It’s not creating huge feedback loops like waterfall — it’s providing a mechanism for shorter and effective ones than would otherwise be possible with pure vibe coding.”&lt;/p&gt;
&lt;p&gt;（这并不是制造像瀑布流那样巨大的反馈环，而是提供了一种机制，相比纯粹的 Vibe Coding，它能带来更短、更有效的反馈。）&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Vibe Coding 看似快，但由于缺乏设计，往往在后期陷入无尽的 Debug 泥潭。SDD 实际上是在“慢”中求“快”。&lt;/p&gt;
&lt;h3 id=&quot;2-gui-ge-piao-yi-spec-drift-de-feng-xian&quot;&gt;2. 规格漂移 (Spec Drift) 的风险&lt;/h3&gt;
&lt;p&gt;Liu Shangqi 也提到了一个核心痛点：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;原文&lt;/em&gt;：“Spec drift and hallucination are inherently difficult to avoid. We still need highly deterministic CI/CD practices…”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;如果代码被修改了，但 Spec 没有更新，Spec 就成了废纸。这是 SDD 面临的最大挑战。除非像 Tessl 那样强制“单向生成”，否则保持 Spec 与代码的同步需要极高的纪律性。&lt;/p&gt;
&lt;h3 id=&quot;3-one-workflow-to-fit-all-sizes-yi-tao-liu-cheng-tong-chi&quot;&gt;3. “One workflow to fit all sizes?” (一套流程通吃？)&lt;/h3&gt;
&lt;p&gt;Martin Fowler 提出了一个非常犀利的质疑：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;原文&lt;/em&gt;：“When I asked Kiro to fix a small bug… it quickly became clear that the workflow was like using a sledgehammer to crack a nut.”&lt;/p&gt;
&lt;p&gt;（当我让 Kiro 修一个小 Bug 时……这简直是杀鸡用牛刀。）&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;目前的 SDD 工具（无论是 Spec Kit 还是 Kiro）往往流程繁琐，对于修复一个小 Bug 来说，写一套完整的 Spec 显得过于笨重。未来的 SDD 工具必须能够适应不同粒度的任务。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;jie-yu&quot;&gt;结语&lt;/h2&gt;
&lt;p&gt;Spec-Driven Development 正在重新定义人与 AI 的协作模式。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对于&lt;strong&gt;简单任务&lt;/strong&gt;，“Vibe Coding” 或许依然有效。&lt;/li&gt;
&lt;li&gt;但对于&lt;strong&gt;复杂系统&lt;/strong&gt;，我们需要 Spec Kit 这样的工具来确立“宪法”与“计划”。&lt;/li&gt;
&lt;li&gt;而在&lt;strong&gt;未来&lt;/strong&gt;，我们或许会像 Tessl 预言的那样，只维护 Spec，让代码成为 AI 时代的汇编语言。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在这个转型期，保持清醒，不盲目追求速度，回归对软件行为（Behavior）的深度定义，或许才是程序员在 AI 时代的核心竞争力。&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>用 opencode + agent-skills 开发俄罗斯方块：自然语言驱动工程流</title>
        <published>2026-01-15T00:00:00+00:00</published>
        <updated>2026-01-15T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/opencode-agent-skills-tetris-tutorial/"/>
        <id>https://scp.net.cn/blog/opencode-agent-skills-tetris-tutorial/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/opencode-agent-skills-tetris-tutorial/">&lt;p&gt;之前我写过 &lt;a href=&quot;/blog/skill-system-2048-full-demo/&quot;&gt;用 Matt Pocock 的 Skill 系统开发 2048&lt;/a&gt;，那套流程是&lt;strong&gt;斜杠命令驱动&lt;/strong&gt;——&lt;code&gt;/grill-with-docs&lt;/code&gt;、&lt;code&gt;/to-spec&lt;/code&gt;、&lt;code&gt;/to-tickets&lt;/code&gt;、&lt;code&gt;/implement&lt;/code&gt;，每个阶段都要手动喊。&lt;/p&gt;
&lt;p&gt;这次用 &lt;a rel=&quot;external&quot; href=&quot;https://github.com/addyosmani/agent-skills&quot;&gt;addyosmani/agent-skills&lt;/a&gt; + &lt;a rel=&quot;external&quot; href=&quot;https://opencode.ai/&quot;&gt;opencode&lt;/a&gt; 跑一遍俄罗斯方块，&lt;strong&gt;全程没说一个斜杠命令&lt;/strong&gt;。Skill 不是手动触发的，是 agent 自己根据意图挑的。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;yi-wei-shen-me-shi-opencode-agent-skills&quot;&gt;一、为什么是 opencode + agent-skills&lt;/h2&gt;
&lt;p&gt;两件事说清楚：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;opencode 是什么&lt;/strong&gt;：开源终端 AI coding agent，&lt;a rel=&quot;external&quot; href=&quot;https://github.com/anomalyco/opencode&quot;&gt;anomalyco/opencode&lt;/a&gt;，19 万 star。装好之后就是个 TUI，可以聊、可以改、可以跑命令。&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; install -g opencode-ai&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 或者&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;brew&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; install anomalyco/tap/opencode&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;agent-skills 是什么&lt;/strong&gt;：24 个工程实践 skill 的 Markdown 集合，按生命周期分 6 个阶段——Define、Plan、Build、Verify、Review、Ship。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;关键区别&lt;/strong&gt;：在 Claude Code 里你写 &lt;code&gt;/grill-with-docs&lt;/code&gt; 才调 skill。在 opencode 里你&lt;strong&gt;只说人话&lt;/strong&gt;，agent 自己根据你的意图挑 skill。背后靠的是项目根目录的 &lt;code&gt;AGENTS.md&lt;/code&gt;。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;er-zhun-bei-gong-zuo-5-fen-zhong-da-hao&quot;&gt;二、准备工作：5 分钟搭好&lt;/h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; tetris&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; cd&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; tetris&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; clone https://github.com/addyosmani/agent-skills.git .&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Clone 完之后，工作区里有两样关键东西：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;tetris/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── AGENTS.md              # 给 agent 的元指令，告诉它怎么挑 skill&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;└── skills/                # 24 个 skill 的 SKILL.md&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├── spec-driven-development/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├── planning-and-task-breakdown/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├── test-driven-development/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├── incremental-implementation/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├── frontend-ui-engineering/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├── browser-testing-with-devtools/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├── debugging-and-error-recovery/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├── code-review-and-quality/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    └── ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;AGENTS.md&lt;/code&gt; 是 opencode 的核心。它告诉 agent：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;什么时候该查 skills/&lt;/strong&gt;（任何非平凡任务）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;怎么读 SKILL.md&lt;/strong&gt;（Frontmatter → When to Use → Process → Verification）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;怎么调&lt;/strong&gt;（用 &lt;code&gt;skill&lt;/code&gt; 工具）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;cd tetris &amp;amp;&amp;amp; opencode&lt;/code&gt; 进 TUI，环境就绪。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;san-gong-zuo-yuan-li-zi-ran-yu-yan-zi-dong-skill-diao-du&quot;&gt;三、工作原理：自然语言 → 自动 skill 调度&lt;/h2&gt;
&lt;p&gt;打开 opencode 后，&lt;strong&gt;不要&lt;/strong&gt;先敲 &lt;code&gt;/spec&lt;/code&gt; 之类的命令。直接说人话。&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;你说的&lt;/th&gt;&lt;th&gt;agent 自动调用的 skill&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;“我想做一个网页版俄罗斯方块，先帮我梳理下需求和规格”&lt;/td&gt;&lt;td&gt;&lt;code&gt;spec-driven-development&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;“把上面的 spec 拆成可执行的 tickets”&lt;/td&gt;&lt;td&gt;&lt;code&gt;planning-and-task-breakdown&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;“按 ticket 顺序实现，每步先写测试”&lt;/td&gt;&lt;td&gt;&lt;code&gt;incremental-implementation&lt;/code&gt; + &lt;code&gt;test-driven-development&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;“界面太丑了，按现代极简风重做”&lt;/td&gt;&lt;td&gt;&lt;code&gt;frontend-ui-engineering&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;“在浏览器里实际跑一下，看有没有问题”&lt;/td&gt;&lt;td&gt;&lt;code&gt;browser-testing-with-devtools&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;“旋转的时候方块穿墙了，帮我定位下原因”&lt;/td&gt;&lt;td&gt;&lt;code&gt;debugging-and-error-recovery&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;“代码 review 一下，看哪里可以改进”&lt;/td&gt;&lt;td&gt;&lt;code&gt;code-review-and-quality&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;每个 skill 的 &lt;code&gt;SKILL.md&lt;/code&gt; 都规定了触发条件（“When to Use”）。AGENTS.md 教 agent 看到匹配就调。&lt;/p&gt;
&lt;p&gt;这就是 addyosmani/agent-skills 跟 Matt Pocock 那套的本质区别：&lt;strong&gt;没有手动入口，全靠意图匹配&lt;/strong&gt;。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;si-shi-zhan-e-luo-si-fang-kuai-7-ge-jie-duan&quot;&gt;四、实战：俄罗斯方块 7 个阶段&lt;/h2&gt;
&lt;h3 id=&quot;jie-duan-1-spec-driven-development-ba-e-luo-si-fang-kuai-bian-cheng-ke-yan-shou-de-gui-ge&quot;&gt;阶段 1：spec-driven-development — 把“俄罗斯方块“变成可验收的规格&lt;/h3&gt;
&lt;p&gt;直接说：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“我想做一个网页版俄罗斯方块。先按 spec-driven-development 这个 skill 帮我生成完整规格。”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;agent 读 &lt;code&gt;skills/spec-driven-development/SKILL.md&lt;/code&gt;，按它的模板把规格写进 &lt;code&gt;SPEC.md&lt;/code&gt;。&lt;strong&gt;真实产出&lt;/strong&gt;（节选）：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; 俄罗斯方块规格说明 (v1)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;##&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; 范围&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;###&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; 核心机制&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; 10×20 网格，顶部生成 7 种标准 tetromino (I/O/T/S/Z/L/J)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; 每 800ms 下落一格，level 越高越快&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; 方向键 ← → 移动，上键旋转，下键软落，空格硬落&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; 一行填满时消除，计分&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; 顶部无法放置新方块时 Game Over&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;###&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; 计分&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; 单消：100 × level&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; 双消：300 × level&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; 三消：500 × level&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; 四消（Tetris）：800 × level&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;###&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; 下一块预览&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; 右侧窗口显示下一个方块&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;##&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; 验收标准&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; [ ] 7 种方块形状正确&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; [ ] 旋转不穿墙、不覆盖已放置方块（墙 kick 简化版）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; [ ] 满行消除正确，多行同时消除计分正确&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; [ ] 硬落立即到底，软落加速下落&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; [ ] 等级随消除行数提升，下落速度对应&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; [ ] 无法生成新方块时 Game Over&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; [ ] 分数、等级、下一个方块 UI 实时更新&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;跟直接对话的差别&lt;/strong&gt;：直接说“做个俄罗斯方块“，agent 大概率直接开干。规格明确后，后面每一步都有锚点——不会出现“做完了发现 UI 风格不是想要的“。&lt;/p&gt;
&lt;h3 id=&quot;jie-duan-2-planning-and-task-breakdown-ba-spec-qie-cheng-ke-yan-zheng-de-ticket&quot;&gt;阶段 2：planning-and-task-breakdown — 把 spec 切成可验证的 ticket&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;“按 spec 拆 ticket，每个独立可验证，标注依赖。”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;输出 &lt;code&gt;tickets/&lt;/code&gt;：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;tickets/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── 01-grid-and-rendering.md          # blocking: none&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── 02-piece-spawn-and-types.md       # blocking: 01&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── 03-gravity-and-timing.md          # blocking: 02&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── 04-movement-and-rotation.md       # blocking: 02&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── 05-line-clear-detection.md        # blocking: 01&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── 06-scoring-and-level.md           # blocking: 05&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── 07-next-piece-preview.md          # blocking: 02&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── 08-soft-drop-and-hard-drop.md     # blocking: 04&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;└── 09-game-over-detection.md         # blocking: 03, 05&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;每个 ticket 自带验收列表。比如 &lt;code&gt;04-movement-and-rotation.md&lt;/code&gt;：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Ticket 04: 移动与旋转&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;##&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; 依赖&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;01 (grid), 02 (piece spawn)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;##&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; 实现要点&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; ← → 移动：边界检测&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; ↑ 旋转：90 度矩阵变换 + 简化版 wall kick（左右各偏移 1 格尝试）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; 旋转不合法时回退原状态&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;##&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; 测试&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; [ ] piece 在左边界时 ← 不动&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; [ ] piece 在右边界时 → 不动&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; [ ] piece 旋转正确（提供 7 种形状的旋转前/后状态对照）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; [ ] piece 紧贴方块时 ↑ 不旋转、保持原状&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; [ ] 旋转越界时 wall kick 成功&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;##&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; 验收&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;跑 &lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;`npm test`&lt;/span&gt;&lt;span&gt;，全部通过；浏览器手动测一遍 7 种方块的旋转。&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;incremental-implementation&lt;/code&gt; skill 看到这个依赖图，会按拓扑序 01 → 02 → 03 → … 一个一个做。&lt;/p&gt;
&lt;h3 id=&quot;jie-duan-3-test-driven-development-incremental-implementation-hong-lu-xun-huan&quot;&gt;阶段 3：test-driven-development + incremental-implementation — 红绿循环&lt;/h3&gt;
&lt;p&gt;以 ticket 04（旋转）为例。&lt;/p&gt;
&lt;h4 id=&quot;red-xian-xie-failing-test&quot;&gt;Red：先写 failing test&lt;/h4&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// tests/rotation.test.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; describe&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; it&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; expect&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;vitest&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; createPiece&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; rotatePiece&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;../src/piece.js&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;describe&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;rotation&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;, ()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  it&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;T-piece rotates 90 degrees clockwise&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;, ()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    const&lt;/span&gt;&lt;span&gt; t&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; createPiece&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // T 初始:  .T.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    //          TTT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    const&lt;/span&gt;&lt;span&gt; rotated&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; rotatePiece&lt;/span&gt;&lt;span&gt;(t&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 旋转后:  T.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    //          TT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    //          T.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    expect&lt;/span&gt;&lt;span&gt;(rotated&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;cells)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;toEqual&lt;/span&gt;&lt;span&gt;([&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      {&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; x&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; y&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }, {&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; x&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; y&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }, {&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; x&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 5&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; y&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }, {&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; x&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; y&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ])&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  }&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  it&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;rotation fails when blocked, returns original piece&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;, ()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 准备一个 T，紧贴左边墙&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    const&lt;/span&gt;&lt;span&gt; t&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; createPiece&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 5&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    const&lt;/span&gt;&lt;span&gt; rotated&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; rotatePiece&lt;/span&gt;&lt;span&gt;(t&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // wall kick 失败，应回退&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    expect&lt;/span&gt;&lt;span&gt;(rotated)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;toBe&lt;/span&gt;&lt;span&gt;(t)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; // 返回原对象&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  }&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;跑 &lt;code&gt;npm test&lt;/code&gt; → &lt;strong&gt;Red&lt;/strong&gt;。&lt;/p&gt;
&lt;h4 id=&quot;green-zui-xiao-shi-xian&quot;&gt;Green：最小实现&lt;/h4&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// src/piece.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;const&lt;/span&gt;&lt;span&gt; SHAPES&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  I&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span&gt;]]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  O&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span&gt;]]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  T&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span&gt;]]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  S&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span&gt;]]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  Z&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span&gt;]]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  L&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span&gt;]]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  J&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span&gt;]]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;export function&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; createPiece&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; cells&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; SHAPES[type]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;map&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;([&lt;/span&gt;&lt;span&gt;dx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; dy&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;])&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; x&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span&gt; dx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; y&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span&gt; dy&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;export function&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; rotatePiece&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;piece&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; times&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  let&lt;/span&gt;&lt;span&gt; current&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; piece&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span&gt; times&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    const&lt;/span&gt;&lt;span&gt; rotated&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      ...&lt;/span&gt;&lt;span&gt;current&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;      cells&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; current&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;cells&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;map&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;({&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; })&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;        x&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; current&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span&gt; (y&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; -&lt;/span&gt;&lt;span&gt; current&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;y)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;        y&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; current&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; -&lt;/span&gt;&lt;span&gt; (x&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; -&lt;/span&gt;&lt;span&gt; current&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;x)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      }&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 简化版 wall kick：尝试 ±1 偏移&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;isValidPosition&lt;/span&gt;&lt;span&gt;(rotated))&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      const&lt;/span&gt;&lt;span&gt; kicked&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; tryWallKick&lt;/span&gt;&lt;span&gt;(rotated)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      if&lt;/span&gt;&lt;span&gt; (kicked) current&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; kicked&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      else return&lt;/span&gt;&lt;span&gt; piece&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; // 回退&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; else&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      current&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; rotated&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  return&lt;/span&gt;&lt;span&gt; current&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;跑 &lt;code&gt;npm test&lt;/code&gt; → &lt;strong&gt;Green&lt;/strong&gt;。&lt;/p&gt;
&lt;h4 id=&quot;code-review-zi-jian&quot;&gt;Code Review：自检&lt;/h4&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;## Standards (per code-review-and-quality skill)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- [x] 函数单一职责&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- [x] 无 magic number（旋转矩阵来自 SRS 标准）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- [x] 边界处理完整&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;## Spec&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- [x] 旋转正确&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- [x] 越界回退&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- [x] wall kick 简化版&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;每个 ticket 走完都是这种节奏：Red → Green → Review → Commit。&lt;/p&gt;
&lt;h3 id=&quot;jie-duan-4-frontend-ui-engineering-rang-ta-kan-qi-lai-bu-xiang-1990&quot;&gt;阶段 4：frontend-ui-engineering — 让它看起来不像 1990&lt;/h3&gt;
&lt;p&gt;ticket 全绿后：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“基础功能通了，但 UI 太丑。按 frontend-ui-engineering 的标准重做，CSS Variables + 现代极简风。”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;agent 调 &lt;code&gt;frontend-ui-engineering&lt;/code&gt;，做几件事：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;设计令牌&lt;/strong&gt;：颜色、字号、间距全走 CSS Variables&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;响应式&lt;/strong&gt;：移动端可玩&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;可访问性&lt;/strong&gt;：键盘 focus、aria-label&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;动画&lt;/strong&gt;：消行闪烁、方块硬落的轨迹&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;产出节选：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;css&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;root&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  --bg&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: #&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0f0f17&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  --grid-line&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; rgba&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;255&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 255&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 255&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0.04&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  --piece-I&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: #&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;00f0f0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  --piece-O&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: #&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;f0f000&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  --piece-T&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: #&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;a000f0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  --piece-S&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: #&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;00f000&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  --piece-Z&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: #&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;f00000&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  --piece-L&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: #&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;f0a000&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  --piece-J&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: #&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0000f0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  --font-mono&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;JetBrains Mono&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; monospace;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;jie-duan-5-browser-testing-with-devtools-zai-zhen-liu-lan-qi-li-pao&quot;&gt;阶段 5：browser-testing-with-devtools — 在真浏览器里跑&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;“用 browser-testing-with-devtools 在 Chrome 里实际跑一下，截图、检查 console、确认交互正常。”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;agent 通过 Chrome DevTools MCP 实际启动浏览器（不是 mock），做这些检查：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;页面加载后 canvas 渲染正确&lt;/li&gt;
&lt;li&gt;键盘事件触发，无 console error&lt;/li&gt;
&lt;li&gt;7 种方块都能生成和旋转&lt;/li&gt;
&lt;li&gt;满行消除动画播放&lt;/li&gt;
&lt;li&gt;localStorage 保存最高分&lt;/li&gt;
&lt;li&gt;移动端 touch 事件正常&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;发现问题直接进阶段 6。&lt;/p&gt;
&lt;h3 id=&quot;jie-duan-6-debugging-and-error-recovery-xiu-bug&quot;&gt;阶段 6：debugging-and-error-recovery — 修 bug&lt;/h3&gt;
&lt;p&gt;实测发现：长条 I 在边缘旋转时偶尔“消失一帧“。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“I 方块在右边缘旋转偶尔消失。按 debugging-and-error-recovery 的流程查一下。”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;agent 按 skill 模板走：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Reproduce&lt;/strong&gt;：写最小复现（5 行代码触发）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Isolate&lt;/strong&gt;：定位到 &lt;code&gt;rotatePiece&lt;/code&gt; 的 wall kick 逻辑——I 占 4 格，偏移 ±1 不够&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hypothesize&lt;/strong&gt;：I 需要 ±2 偏移&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Verify&lt;/strong&gt;：补测试用例，修复，跑全测&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 修复&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; tryWallKick&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;piece&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;const&lt;/span&gt;&lt;span&gt; dx&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; of&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;2&lt;/span&gt;&lt;span&gt;])&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    const&lt;/span&gt;&lt;span&gt; kicked&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ...&lt;/span&gt;&lt;span&gt;piece&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; x&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; piece&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span&gt; dx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;isValidPosition&lt;/span&gt;&lt;span&gt;(kicked))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return&lt;/span&gt;&lt;span&gt; kicked&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  return null;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;回归测试通过。&lt;/p&gt;
&lt;h3 id=&quot;jie-duan-7-code-review-and-quality-zui-hou-yi-dao-zha&quot;&gt;阶段 7：code-review-and-quality — 最后一道闸&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;“按 code-review-and-quality 的清单 review 一遍最终代码。”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;agent 按 checklist 过一遍：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
无 dead code（所有函数都有调用）&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
无过度抽象（没有“为了将来“的接口）&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
错误处理完整（边界、非法输入）&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
性能可接受（60fps 渲染）&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
测试覆盖核心逻辑（rotation、line clear、scoring）&lt;/li&gt;
&lt;li&gt;&lt;input disabled=&quot;&quot; type=&quot;checkbox&quot;/&gt;
文档齐全（README + 注释）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;发现两处改进：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;spawnPiece&lt;/code&gt; 里 &lt;code&gt;Math.random()&lt;/code&gt; 直接调，测试难 mock——抽成参数注入&lt;/li&gt;
&lt;li&gt;&lt;code&gt;render&lt;/code&gt; 每次全量重绘，可以加 dirty flag 优化&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;修完。最终 commit。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;wu-wan-zheng-dai-ma-zui-zhong-jiao-fu&quot;&gt;五、完整代码（最终交付）&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;index.html&lt;/code&gt; 单文件，约 380 行：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;html&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;!DOCTYPE&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; html&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;html&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; lang&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;zh&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;head&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  &amp;lt;meta&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; charset&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;UTF-8&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  &amp;lt;meta&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;viewport&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;width=device-width, initial-scale=1.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  &amp;lt;title&amp;gt;&lt;/span&gt;&lt;span&gt;Tetris&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  &amp;lt;style&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    :&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;root&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      --bg&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: #&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0f0f17&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      --panel&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: #&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1a1a24&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      --text&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: #&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;e8e8f0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      --grid-line&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; rgba&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;255&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 255&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 255&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0.05&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      --piece-I&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: #&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;00f0f0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; --piece-O&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: #&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;f0f000&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; --piece-T&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: #&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;a000f0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      --piece-S&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: #&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;00f000&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; --piece-Z&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: #&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;f00000&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; --piece-L&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: #&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;f0a000&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; --piece-J&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: #&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;4040ff&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      --font-mono&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;JetBrains Mono&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ui-monospace&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; monospace;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    *&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; box-sizing&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; border-box;&lt;/span&gt;&lt;span&gt; margin&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; padding&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    body&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      font-family&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;--font-mono&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      background&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;--bg&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; color&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;--text&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      display&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; flex;&lt;/span&gt;&lt;span&gt; justify-content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; center;&lt;/span&gt;&lt;span&gt; align-items&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; center;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      min-height&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 100&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;vh;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    .&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;game&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; display&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; flex;&lt;/span&gt;&lt;span&gt; gap&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 24&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    canvas&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; background&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;--panel&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; border-radius&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 8&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    .&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;panel&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; display&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; flex;&lt;/span&gt;&lt;span&gt; flex-direction&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; column;&lt;/span&gt;&lt;span&gt; gap&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 16&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px;&lt;/span&gt;&lt;span&gt; min-width&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 140&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    .&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;stat&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; background&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;--panel&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; padding&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 12&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 16&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px;&lt;/span&gt;&lt;span&gt; border-radius&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 8&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    .&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;stat&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; label&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; font-size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 11&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px;&lt;/span&gt;&lt;span&gt; text-transform&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; uppercase;&lt;/span&gt;&lt;span&gt; opacity&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0.6&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    .&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;stat&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; .&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; font-size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 24&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px;&lt;/span&gt;&lt;span&gt; font-weight&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; bold;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    .&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;overlay&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      position&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; fixed;&lt;/span&gt;&lt;span&gt; inset&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; background&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; rgba&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0.7&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      display&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; none;&lt;/span&gt;&lt;span&gt; align-items&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; center;&lt;/span&gt;&lt;span&gt; justify-content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; center;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      flex-direction&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; column;&lt;/span&gt;&lt;span&gt; gap&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 16&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    .&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;overlay&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;show&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; display&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; flex;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    canvas.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; width&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 100&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px;&lt;/span&gt;&lt;span&gt; height&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 100&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px;&lt;/span&gt;&lt;span&gt; background&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;--panel&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; border-radius&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 8&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    .&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;controls&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; font-size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 12&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px;&lt;/span&gt;&lt;span&gt; opacity&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0.7&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; line-height&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1.8&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    kbd&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; background&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;--panel&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; padding&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 6&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px;&lt;/span&gt;&lt;span&gt; border-radius&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  &amp;lt;/style&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;body&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  &amp;lt;div&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;game&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    &amp;lt;canvas&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;board&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; width&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;300&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; height&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;600&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&amp;lt;/canvas&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    &amp;lt;div&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;panel&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      &amp;lt;div&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;stat&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&amp;lt;label&amp;gt;&lt;/span&gt;&lt;span&gt;分数&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/label&amp;gt;&amp;lt;div&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;score&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      &amp;lt;div&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;stat&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&amp;lt;label&amp;gt;&lt;/span&gt;&lt;span&gt;等级&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/label&amp;gt;&amp;lt;div&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;level&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      &amp;lt;div&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;stat&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&amp;lt;label&amp;gt;&lt;/span&gt;&lt;span&gt;下一个&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/label&amp;gt;&amp;lt;canvas&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; width&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; height&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&amp;lt;/canvas&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      &amp;lt;div&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;stat controls&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        &amp;lt;kbd&amp;gt;&lt;/span&gt;&lt;span&gt;←&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/kbd&amp;gt;&amp;lt;kbd&amp;gt;&lt;/span&gt;&lt;span&gt;→&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/kbd&amp;gt;&lt;/span&gt;&lt;span&gt; 移动&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;br&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        &amp;lt;kbd&amp;gt;&lt;/span&gt;&lt;span&gt;↑&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/kbd&amp;gt;&lt;/span&gt;&lt;span&gt; 旋转&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;br&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        &amp;lt;kbd&amp;gt;&lt;/span&gt;&lt;span&gt;↓&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/kbd&amp;gt;&lt;/span&gt;&lt;span&gt; 软落&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;br&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        &amp;lt;kbd&amp;gt;&lt;/span&gt;&lt;span&gt;Space&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/kbd&amp;gt;&lt;/span&gt;&lt;span&gt; 硬落&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;br&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        &amp;lt;kbd&amp;gt;&lt;/span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/kbd&amp;gt;&lt;/span&gt;&lt;span&gt; 暂停&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      &amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    &amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  &amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  &amp;lt;div&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;overlay&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;overlay&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    &amp;lt;h1&amp;gt;&lt;/span&gt;&lt;span&gt;游戏结束&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    &amp;lt;button&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; onclick&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&amp;quot;&lt;/span&gt;&lt;span&gt;location&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;reload&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;再来一局&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  &amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  &amp;lt;script&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    const&lt;/span&gt;&lt;span&gt; COLS&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; ROWS&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 20&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; CELL&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 30&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    const&lt;/span&gt;&lt;span&gt; SHAPES&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;      I&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span&gt;]]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;      O&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span&gt;]]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;      T&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span&gt;]]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;      S&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span&gt;]]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;      Z&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span&gt;]]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;      L&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span&gt;]]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;      J&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; [[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span&gt;]]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    const&lt;/span&gt;&lt;span&gt; COLORS&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;      I&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;--piece-I&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; O&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;--piece-O&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; T&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;--piece-T&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; S&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;--piece-S&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;      Z&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;--piece-Z&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; L&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;--piece-L&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; J&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;--piece-J&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    const&lt;/span&gt;&lt;span&gt; SCORE_TABLE&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 100&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 300&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 500&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 800&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    const&lt;/span&gt;&lt;span&gt; SPEEDS&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;800&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 650&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 500&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 400&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 300&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 200&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 150&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 100&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 80&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 50&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    const&lt;/span&gt;&lt;span&gt; board&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; document&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getElementById&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;board&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    const&lt;/span&gt;&lt;span&gt; ctx&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; board&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getContext&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;2d&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    const&lt;/span&gt;&lt;span&gt; nextCanvas&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; document&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getElementById&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    const&lt;/span&gt;&lt;span&gt; nextCtx&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; nextCanvas&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getContext&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;2d&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    let&lt;/span&gt;&lt;span&gt; grid&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; piece&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; next&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; score&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; level&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; lines&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; dropTimer&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; dropInterval&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; paused&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; gameOver&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; randomPiece&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; ()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; Object&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;keys&lt;/span&gt;&lt;span&gt;(SHAPES)[Math&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;floor&lt;/span&gt;&lt;span&gt;(Math&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;random&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 7&lt;/span&gt;&lt;span&gt;)]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    function&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; newPiece&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      const&lt;/span&gt;&lt;span&gt; t&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; type&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; randomPiece&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      const&lt;/span&gt;&lt;span&gt; cells&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; SHAPES[t]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;map&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;([&lt;/span&gt;&lt;span&gt;dx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; dy&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;])&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; x&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span&gt; dx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; y&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; dy&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      return&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; t&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; cells&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    function&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; collides&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;cells&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      return&lt;/span&gt;&lt;span&gt; cells&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;some&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;({&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; })&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        x&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ||&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt;=&lt;/span&gt;&lt;span&gt; COLS&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ||&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt;=&lt;/span&gt;&lt;span&gt; ROWS&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ||&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        (y&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span&gt; grid[y][x])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      )&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    function&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; merge&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;piece&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      piece&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;cells&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;forEach&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;({&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; })&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; if&lt;/span&gt;&lt;span&gt; (y&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span&gt;) grid[y][x]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; piece&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    function&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; clearLines&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      let&lt;/span&gt;&lt;span&gt; cleared&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; ROWS&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;--&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span&gt; (grid[y]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;every&lt;/span&gt;&lt;span&gt;(c&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; c))&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          grid&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;splice&lt;/span&gt;&lt;span&gt;(y&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          grid&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;unshift&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Array&lt;/span&gt;&lt;span&gt;(COLS)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;fill&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;null&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          cleared&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          y&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; // 重检&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      if&lt;/span&gt;&lt;span&gt; (cleared)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        lines&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +=&lt;/span&gt;&lt;span&gt; cleared&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        score&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +=&lt;/span&gt;&lt;span&gt; (SCORE_TABLE[cleared]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; *&lt;/span&gt;&lt;span&gt; level&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        level&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; Math&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;floor&lt;/span&gt;&lt;span&gt;(lines&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; /&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        dropInterval&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; SPEEDS[Math&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;min&lt;/span&gt;&lt;span&gt;(level&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; SPEEDS&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;length&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span&gt;)]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    function&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; rotate&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;piece&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; times&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      let&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; piece&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span&gt; times&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        const&lt;/span&gt;&lt;span&gt; cx&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;cells&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;reduce&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; s&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; /&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;cells&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;length&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        const&lt;/span&gt;&lt;span&gt; cy&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;cells&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;reduce&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; s&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; /&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;cells&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;length&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        const&lt;/span&gt;&lt;span&gt; rotated&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;          ...&lt;/span&gt;&lt;span&gt;result&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;          cells&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;cells&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;map&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;({&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; })&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;            x&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; Math&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;round&lt;/span&gt;&lt;span&gt;(cx&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span&gt; (y&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; -&lt;/span&gt;&lt;span&gt; cy))&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;            y&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; Math&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;round&lt;/span&gt;&lt;span&gt;(cy&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; -&lt;/span&gt;&lt;span&gt; (x&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; -&lt;/span&gt;&lt;span&gt; cx))&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;          }&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // 简化 wall kick：±1, ±2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        let&lt;/span&gt;&lt;span&gt; ok&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = !&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;collides&lt;/span&gt;&lt;span&gt;(rotated&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;cells)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ?&lt;/span&gt;&lt;span&gt; rotated&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; : null;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;!&lt;/span&gt;&lt;span&gt;ok)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;          for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;const&lt;/span&gt;&lt;span&gt; dx&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; of&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;2&lt;/span&gt;&lt;span&gt;])&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            const&lt;/span&gt;&lt;span&gt; kicked&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ...&lt;/span&gt;&lt;span&gt;rotated&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; cells&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; rotated&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;cells&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;map&lt;/span&gt;&lt;span&gt;(c&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; x&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span&gt; dx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; y&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;collides&lt;/span&gt;&lt;span&gt;(kicked&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;cells))&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; ok&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; kicked&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;; break;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;          }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        result&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; ok&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ||&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; // 失败保持&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      return&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    function&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; move&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;dx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; dy&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      const&lt;/span&gt;&lt;span&gt; moved&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ...&lt;/span&gt;&lt;span&gt;piece&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; cells&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; piece&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;cells&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;map&lt;/span&gt;&lt;span&gt;(c&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; x&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span&gt; dx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; y&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span&gt; dy&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;collides&lt;/span&gt;&lt;span&gt;(moved&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;cells)) piece&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; moved&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    function&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; softDrop&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;() {&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; move&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    function&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; hardDrop&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      while&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;collides&lt;/span&gt;&lt;span&gt;(piece&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;cells&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;map&lt;/span&gt;&lt;span&gt;(c&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; x&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; y&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;span&gt;))))&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        piece&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;cells&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; piece&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;cells&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;map&lt;/span&gt;&lt;span&gt;(c&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; x&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; y&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        score&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;      lockPiece&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    function&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; lockPiece&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;      merge&lt;/span&gt;&lt;span&gt;(piece)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;      clearLines&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      piece&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; next&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      next&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; newPiece&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;collides&lt;/span&gt;&lt;span&gt;(piece&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;cells)) gameOver&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = true;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    function&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; tick&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      if&lt;/span&gt;&lt;span&gt; (paused&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ||&lt;/span&gt;&lt;span&gt; gameOver)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;      move&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; lockPiece&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      if&lt;/span&gt;&lt;span&gt; (gameOver) document&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getElementById&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;overlay&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;classList&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;add&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;show&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    function&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; drawCell&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; ctxRef&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      const&lt;/span&gt;&lt;span&gt; color&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; getComputedStyle&lt;/span&gt;&lt;span&gt;(document&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;documentElement)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        .&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getPropertyValue&lt;/span&gt;&lt;span&gt;(COLORS[c])&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;trim&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      ctxRef&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;fillStyle&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; color&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      ctxRef&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;fillRect&lt;/span&gt;&lt;span&gt;(x&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; *&lt;/span&gt;&lt;span&gt; CELL&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; *&lt;/span&gt;&lt;span&gt; CELL&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; CELL&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; CELL&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    function&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; render&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;fillStyle&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; getComputedStyle&lt;/span&gt;&lt;span&gt;(document&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;documentElement)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getPropertyValue&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;--panel&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;fillRect&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; board&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;width&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; board&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;height)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;      // 网格&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;strokeStyle&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; getComputedStyle&lt;/span&gt;&lt;span&gt;(document&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;documentElement)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getPropertyValue&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;--grid-line&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;=&lt;/span&gt;&lt;span&gt; COLS&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;beginPath&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;moveTo&lt;/span&gt;&lt;span&gt;(x&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; *&lt;/span&gt;&lt;span&gt; CELL&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;lineTo&lt;/span&gt;&lt;span&gt;(x&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; *&lt;/span&gt;&lt;span&gt; CELL&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; ROWS&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; *&lt;/span&gt;&lt;span&gt; CELL)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;stroke&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;=&lt;/span&gt;&lt;span&gt; ROWS&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;beginPath&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;moveTo&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; *&lt;/span&gt;&lt;span&gt; CELL)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;lineTo&lt;/span&gt;&lt;span&gt;(COLS&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; *&lt;/span&gt;&lt;span&gt; CELL&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; *&lt;/span&gt;&lt;span&gt; CELL)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;stroke&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;      // 已锁定方块&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span&gt; ROWS&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span&gt; COLS&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;          if&lt;/span&gt;&lt;span&gt; (grid[y][x])&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; drawCell&lt;/span&gt;&lt;span&gt;(grid[y][x]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; y)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;      // 当前 piece&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      piece&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;cells&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;forEach&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;({&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; })&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; drawCell&lt;/span&gt;&lt;span&gt;(piece&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; y))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;      // ghost&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      const&lt;/span&gt;&lt;span&gt; ghost&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; cells&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; piece&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;cells&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;map&lt;/span&gt;&lt;span&gt;(c&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ...&lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      while&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;collides&lt;/span&gt;&lt;span&gt;(ghost&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;cells&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;map&lt;/span&gt;&lt;span&gt;(c&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ...&lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; y&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;span&gt;))))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ghost&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;cells&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; ghost&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;cells&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;map&lt;/span&gt;&lt;span&gt;(c&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ...&lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; y&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;globalAlpha&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0.2&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      ghost&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;cells&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;forEach&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;({&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; })&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; drawCell&lt;/span&gt;&lt;span&gt;(piece&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; y))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;globalAlpha&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;      // 下一个&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      nextCtx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;clearRect&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 100&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 100&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      SHAPES[next&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;type]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;forEach&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;([&lt;/span&gt;&lt;span&gt;dx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; dy&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;])&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; drawCell&lt;/span&gt;&lt;span&gt;(next&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; dx&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; dy&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; nextCtx))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      document&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getElementById&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;score&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;textContent&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; score&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      document&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getElementById&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;level&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;textContent&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; level&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    function&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; init&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      grid&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; Array&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;from&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; length&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; ROWS&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }, ()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Array&lt;/span&gt;&lt;span&gt;(COLS)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;fill&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;null&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      score&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; level&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; lines&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      dropInterval&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; SPEEDS[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; paused&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = false;&lt;/span&gt;&lt;span&gt; gameOver&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = false;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      piece&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; newPiece&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      next&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; newPiece&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      document&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getElementById&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;overlay&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;classList&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;remove&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;show&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    document&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;addEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;keydown&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span&gt; e&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      if&lt;/span&gt;&lt;span&gt; (gameOver)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      if&lt;/span&gt;&lt;span&gt; (e&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ===&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ||&lt;/span&gt;&lt;span&gt; e&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ===&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;P&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; paused&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = !&lt;/span&gt;&lt;span&gt;paused&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;; return;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      if&lt;/span&gt;&lt;span&gt; (paused)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;      switch&lt;/span&gt;&lt;span&gt; (e&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;key)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        case&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;ArrowLeft&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; move&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;; break;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        case&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;ArrowRight&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; move&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;; break;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        case&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;ArrowDown&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; move&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; score&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++; break;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        case&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;ArrowUp&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;:&lt;/span&gt;&lt;span&gt; piece&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; rotate&lt;/span&gt;&lt;span&gt;(piece&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;; break;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        case&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39; &amp;#39;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; hardDrop&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; e&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;preventDefault&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;; break;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    init&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    setInterval&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; tick&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; render&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; },&lt;/span&gt;&lt;span&gt; dropInterval)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  &amp;lt;/script&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以直接 &lt;code&gt;python3 -m http.server&lt;/code&gt; 跑起来玩。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;liu-gen-zhi-jie-dui-hua-de-chai-bie&quot;&gt;六、跟直接对话的差别&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;维度&lt;/th&gt;&lt;th&gt;直接对话&lt;/th&gt;&lt;th&gt;opencode + agent-skills&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;需求对齐&lt;/td&gt;&lt;td&gt;“做个俄罗斯方块”&lt;/td&gt;&lt;td&gt;spec-driven-development：先 6 个 Q 对齐，规格写下来&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;任务拆分&lt;/td&gt;&lt;td&gt;一次性写完&lt;/td&gt;&lt;td&gt;planning-and-task-breakdown：9 个 ticket + 依赖图&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;实现节奏&lt;/td&gt;&lt;td&gt;一把梭&lt;/td&gt;&lt;td&gt;incremental-implementation：按拓扑序一个个 ticket 做&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;质量保证&lt;/td&gt;&lt;td&gt;靠运气&lt;/td&gt;&lt;td&gt;TDD 红绿循环 + code review&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;浏览器验证&lt;/td&gt;&lt;td&gt;不一定有&lt;/td&gt;&lt;td&gt;DevTools 实际截图、检查 console&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Bug 修复&lt;/td&gt;&lt;td&gt;头疼医头&lt;/td&gt;&lt;td&gt;debugging-and-error-recovery：复现 → 隔离 → 假设 → 验证&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;知识沉淀&lt;/td&gt;&lt;td&gt;散在对话里&lt;/td&gt;&lt;td&gt;spec + tickets + 测试，都是 git 里的资产&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;最后一个尤其重要。直接对话做完，AI 走了，所有“为什么这么设计“的决策也跟着走了。Skill 流程做完，每一步的决策都在文档里——下次有人接手或者新 session 续上，照着 spec 和 tickets 就能复现。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;qi-shen-me-shi-hou-bu-yong-skill-liu&quot;&gt;七、什么时候&lt;strong&gt;不&lt;/strong&gt;用 Skill 流&lt;/h2&gt;
&lt;p&gt;Ponytail 一回：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;临时改一行&lt;/strong&gt;：直接说“把这个变量名改了“，开 skill 是杀鸡用牛刀&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;一次性脚本&lt;/strong&gt;：用完就丢的代码，质量门控的成本高于价值&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;明确只是问个问题&lt;/strong&gt;：“CSS Grid 和 Flex 怎么选”——不是任务，是请教&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;判断标准：&lt;strong&gt;这个产出会不会进 git、会不会被未来的我（或别人）读到？&lt;/strong&gt; 会，就走 skill 流；不会，直接聊。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;ba-gen-matt-pocock-na-tao-de-dui-bi&quot;&gt;八、跟 Matt Pocock 那套的对比&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;Matt Pocock skills&lt;/th&gt;&lt;th&gt;addyosmani/agent-skills&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;触发方式&lt;/td&gt;&lt;td&gt;斜杠命令 &lt;code&gt;/grill-with-docs&lt;/code&gt;&lt;/td&gt;&lt;td&gt;自然语言，AGENTS.md 引导自动调&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Skill 数量&lt;/td&gt;&lt;td&gt;~10 个&lt;/td&gt;&lt;td&gt;24 个&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;阶段划分&lt;/td&gt;&lt;td&gt;自定义（grill / spec / tickets / implement）&lt;/td&gt;&lt;td&gt;6 阶段生命周期（Define / Plan / Build / Verify / Review / Ship）&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;适用 agent&lt;/td&gt;&lt;td&gt;Matt Pocock 自己的 CLI&lt;/td&gt;&lt;td&gt;opencode + Claude Code + Cursor + 70+ agent&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;风格&lt;/td&gt;&lt;td&gt;严格按阶段走&lt;/td&gt;&lt;td&gt;按意图匹配，自由组合&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;学习曲线&lt;/td&gt;&lt;td&gt;高（要记命令）&lt;/td&gt;&lt;td&gt;低（说人话就行）&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;两套都很好。如果你想严格按流程走、不让 AI 跑偏，选 Matt Pocock。如果你想轻量、让 agent 自由发挥但有 skill 兜底，选 addyosmani/agent-skills。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;can-kao&quot;&gt;参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/addyosmani/agent-skills&quot;&gt;agent-skills GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://opencode.ai/&quot;&gt;opencode 官网&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/anomalyco/opencode&quot;&gt;opencode GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;上一篇文章：&lt;a href=&quot;/blog/skill-system-2048-full-demo/&quot;&gt;用 Skill 系统开发 2048：完整的工程流程演示&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;原理篇：&lt;a href=&quot;/blog/deep-dive-into-agent-skills/&quot;&gt;彻底搞懂 Agent Skills：从原理到实践&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>向经典致敬：用大师的提问艺术驯服大模型</title>
        <published>2026-01-05T00:00:00+00:00</published>
        <updated>2026-01-05T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/efficient-llm-dialogue-with-classic-books/"/>
        <id>https://scp.net.cn/blog/efficient-llm-dialogue-with-classic-books/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/efficient-llm-dialogue-with-classic-books/">&lt;p&gt;在 AI 时代，“Prompt Engineering”（提示词工程）似乎成了一门显学。但剥去技术的外衣，其内核依然是人类几千年来不断探索的**“提问的艺术”**。&lt;/p&gt;
&lt;p&gt;与其在网上搜寻零散的“咒语”或模板，不如回归经典。本文基于 10 本关于提问与思考的经典著作，探讨如何将其中的智慧迁移到与大模型（LLM）的对话中，实现真正的高效交互。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;yi-ji-chu-pian-gou-jian-hao-wen-ti-de-gu-jia&quot;&gt;一、基础篇：构建“好问题”的骨架&lt;/h2&gt;
&lt;p&gt;很多时候，AI 回答不好，是因为我们问得太“随意”。这一阶段的目标是&lt;strong&gt;消除歧义&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&quot;1-shi-bie-jia-she-yu-bian-jie-xue-hui-ti-wen&quot;&gt;1. 识别假设与边界 ——《学会提问》&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;原著精华&lt;/strong&gt;：
Neil Browne 在书中提出了“海绵式思维”与“淘金式思维”的区别。关键在于识别&lt;strong&gt;价值观假设&lt;/strong&gt;（Value Assumptions）和&lt;strong&gt;描述性假设&lt;/strong&gt;（Descriptive Assumptions）。很多争论无果，是因为双方预设的前提不同。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AI 对话迁移&lt;/strong&gt;：
大模型本质上是一个巨大的“补全机器”，它会倾向于顺从用户的隐含假设，哪怕这个假设是错的（这常导致幻觉）。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;核心策略&lt;/strong&gt;：&lt;strong&gt;显性化假设（Make Assumptions Explicit）&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;实战案例&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;❌ &lt;strong&gt;Bad Prompt&lt;/strong&gt;: “为什么 Java 比 Go 慢？”
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;问题&lt;/em&gt;：隐含了“Java 一定慢”的描述性假设，迫使 AI 寻找证据支持这个偏见。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Good Prompt&lt;/strong&gt;: “在&lt;strong&gt;高并发微服务&lt;/strong&gt;场景下（场景边界），请从&lt;strong&gt;启动时间、吞吐量、内存占用&lt;/strong&gt;三个维度（评价标准），客观对比 Java 21（虚拟线程）与 Go 1.22 的性能差异。请列出支持 Java 性能更优的反直觉场景。”
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;优化点&lt;/em&gt;：移除了偏见，设定了版本和场景，甚至利用“淘金式思维”要求 AI 提供反例。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;2-pi-pan-xing-si-wei-de-di-ceng-pi-pan-xing-si-wei&quot;&gt;2. 批判性思维的底层 ——《批判性思维》&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;原著精华&lt;/strong&gt;：
Richard Paul 提出了“思维的八要素”：目的、问题、信息、概念、假设、意涵、观点、推论。一个严谨的思维过程必须覆盖这些维度。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AI 对话迁移&lt;/strong&gt;：
不要只给 AI 一个关键词，要给它一个完整的“思考框架”。这对应了 Prompt Engineering 中的 &lt;strong&gt;Context（背景）&lt;/strong&gt; 和 &lt;strong&gt;Constraints（约束）&lt;/strong&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;核心策略&lt;/strong&gt;：&lt;strong&gt;结构化指令（Structured Prompting）&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;实战案例&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;❌ &lt;strong&gt;Bad Prompt&lt;/strong&gt;: “帮我写一个贪吃蛇游戏。”&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Good Prompt&lt;/strong&gt;:&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Purpose (目的)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;创建一个适合 Python 初学者学习的贪吃蛇游戏示例。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Concepts (核心概念)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;使用 Pygame 库，面向对象编程 (OOP) 风格。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Constraints (约束)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; 代码必须有详细的中文注释。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; 游戏结束时显示“再来一局”按钮。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; 不要使用复杂的的高级特性，保持代码可读性。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Output (输出)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;请提供完整的 .py 文件代码，并附带依赖安装说明。&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;er-jin-jie-pian-wen-ti-de-chai-jie-yu-lu-jing&quot;&gt;二、进阶篇：问题的拆解与路径&lt;/h2&gt;
&lt;p&gt;当你面对一个复杂任务时，直接丢给 AI 往往得不到满意的结果。你需要学会“教”AI 拆解问题。&lt;/p&gt;
&lt;h3 id=&quot;3-tong-yong-jie-ti-lu-jing-ru-he-jie-jue-wen-ti&quot;&gt;3. 通用解题路径 ——《如何解决问题》&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;原著精华&lt;/strong&gt;：
数学家 George Pólya 提出的解题四部曲是工程思维的基石：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;理解问题&lt;/strong&gt;（未知量是什么？已知数据是什么？）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;制定计划&lt;/strong&gt;（你见过类似的问题吗？能通过辅助线解决吗？）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;执行计划&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;回顾&lt;/strong&gt;（能检验结果吗？）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;AI 对话迁移&lt;/strong&gt;：
这完全对应了 &lt;strong&gt;思维链（Chain of Thought, CoT）&lt;/strong&gt; 技术。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;核心策略&lt;/strong&gt;：&lt;strong&gt;分步推理（Step-by-Step Reasoning）&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;实战案例&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;任务&lt;/strong&gt;：设计一个高可用分布式的 ID 生成器。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prompt&lt;/strong&gt;:
&lt;blockquote&gt;
&lt;p&gt;请基于《如何解决问题》的四步法来辅助我设计：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;理解阶段&lt;/strong&gt;：请先向我提问，确认我对 QPS、有序性、长度等具体需求。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;计划阶段&lt;/strong&gt;：对比 UUID、Snowflake、数据库号段模式的优劣，推荐一个方案。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;执行阶段&lt;/strong&gt;：给出推荐方案的核心伪代码。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;回顾阶段&lt;/strong&gt;：指出该方案在时钟回拨或多机房同步时的潜在风险。&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;4-fa-xian-zhen-zheng-de-wen-ti-wen-ti-de-ben-zhi&quot;&gt;4. 发现真正的问题 ——《问题的本质》&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;原著精华&lt;/strong&gt;：
书中强调“关注缺失的信息”（Noticing what is not there）。多数人失败不是因为找不到答案，而是一开始就解决了一个错误的问题（Type III Error）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AI 对话迁移&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;核心策略&lt;/strong&gt;：&lt;strong&gt;元提问（Meta-Prompting）&lt;/strong&gt;，让 AI 充当“红队”或“质疑者”。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;实战案例&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Prompt&lt;/strong&gt;: “我打算开发一个针对大学生的社交 App，主打匿名吐槽。请不要直接生成方案，先作为&lt;strong&gt;风控专家&lt;/strong&gt;和&lt;strong&gt;产品战略顾问&lt;/strong&gt;，分析这个想法在 2025 年面临的 3 个最大‘隐形’风险（非显而易见的技术问题，而是监管、心理或市场层面的黑天鹅）。”&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;san-xin-fa-pian-dui-hua-zhong-de-bo-yi-yu-yin-dao&quot;&gt;三、心法篇：对话中的博弈与引导&lt;/h2&gt;
&lt;p&gt;与 AI 对话，本质上也是一种沟通。虽然它没有情感，但它会模拟人类的沟通模式。&lt;/p&gt;
&lt;h3 id=&quot;5-ming-que-yi-tu-yu-yu-jing-guan-jian-dui-hua&quot;&gt;5. 明确意图与语境 ——《关键对话》&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;原著精华&lt;/strong&gt;：
在高风险对话中，首先要&lt;strong&gt;建立安全感&lt;/strong&gt;（Make it Safe），并明确&lt;strong&gt;共同目的&lt;/strong&gt;（Shared Purpose）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AI 对话迁移&lt;/strong&gt;：
当 AI 触发安全拦截（Refusal）或回答跑偏时，不要在那一刻强行对抗。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;核心策略&lt;/strong&gt;：&lt;strong&gt;语境重构（Context Reframing）&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;实战案例&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;场景&lt;/em&gt;：你想了解 SQL 注入原理以进行防御，但 AI 拒绝回答“如何攻击”。&lt;/li&gt;
&lt;li&gt;❌ &lt;strong&gt;Bad Prompt&lt;/strong&gt;: “快告诉我怎么攻击这个数据库！”（触发攻击性检测）&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Good Prompt&lt;/strong&gt;: “我是一名网络安全讲师（Persona），正在编写企业的安全防御手册（Shared Purpose）。为了演示漏洞的危害性，我需要一个用于教学环境的 SQL 注入原理示例（Safe Context），请重点解释该漏洞产生的原因及修复代码。”&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;6-yin-dao-er-fei-dui-kang-fei-bao-li-gou-tong&quot;&gt;6. 引导而非对抗 ——《非暴力沟通》&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;原著精华&lt;/strong&gt;：
沟通四要素：&lt;strong&gt;观察（Observation）、感受（Feeling）、需要（Needs）、请求（Requests）&lt;/strong&gt;。重点在于区分“观察”（事实）与“评论”（主观），以及提出“具体的请求”。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AI 对话迁移&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;核心策略&lt;/strong&gt;：&lt;strong&gt;正向且具体的指令（Positive &amp;amp; Specific Constraints）&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;实战案例&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;❌ &lt;strong&gt;Bad Prompt&lt;/strong&gt; (评论式): “这代码写得太烂了，乱七八糟，改一下。”&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Good Prompt&lt;/strong&gt; (观察+需求): “我注意到这段代码中有 3 层嵌套循环（观察），导致可读性较差。我需要提升它的维护性（需要）。请将其重构为函数式写法，或将内部逻辑提取为独立方法（具体请求）。”&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;si-si-xiang-pian-su-ge-la-di-shi-de-zhui-wen&quot;&gt;四、思想篇：苏格拉底式的追问&lt;/h2&gt;
&lt;h3 id=&quot;7-zhui-wen-de-yi-shu-bo-la-tu-dui-hua-lu-su-ge-la-di-shi-ti-wen-fa&quot;&gt;7. 追问的艺术 —— 柏拉图对话录 /《苏格拉底式提问法》&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;原著精华&lt;/strong&gt;：
“产婆术”（Maieutics）：不直接给答案，而是通过连续追问，让对方自己发现逻辑矛盾，从而逼近真理。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AI 对话迁移&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;核心策略&lt;/strong&gt;：&lt;strong&gt;反向辅导（Flip the Interaction）&lt;/strong&gt;。让 AI 当老师，你当学生；或者让 AI 当苏格拉底，审视你的观点。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;实战案例&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Prompt&lt;/strong&gt;: “我正在构思一篇关于‘Web3 的未来’的文章。请扮演苏格拉底，不要直接给我大纲。请阅读我的核心论点：[插入观点]，然后向我提出 3 个尖锐的质疑，指出我逻辑中的漏洞，迫使我通过回答来完善论证。”&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;wu-ren-zhi-sheng-ji-dui-kang-da-nao-de-tou-lan&quot;&gt;五、认知升级：对抗大脑的偷懒&lt;/h2&gt;
&lt;h3 id=&quot;8-qi-dong-xi-tong-2-si-kao-kuai-yu-man&quot;&gt;8. 启动系统 2 ——《思考，快与慢》&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;原著精华&lt;/strong&gt;：
丹尼尔·卡尼曼指出大脑有两套系统：&lt;strong&gt;系统 1&lt;/strong&gt;（快、直觉、无意识、易出错）和 &lt;strong&gt;系统 2&lt;/strong&gt;（慢、理性、逻辑、费力）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AI 对话迁移&lt;/strong&gt;：
LLM 的“下一个词预测”机制天然类似于“系统 1”，它倾向于给出概率最高的平庸回答。你需要通过 Prompt 强制唤醒它的“系统 2”。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;核心策略&lt;/strong&gt;：&lt;strong&gt;强制慢思考（Force System 2）&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;实战案例&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Prompt&lt;/strong&gt;: “在回答这个问题之前，请先列出 5 个可能的解决方案，并构建一个评分矩阵，从成本、时间、风险三个维度打分。最后，基于总分最高的方案给出详细建议。&lt;strong&gt;请深吸一口气，一步步来。&lt;/strong&gt;”&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;9-duo-mo-xing-si-wei-qiong-cha-li-bao-dian&quot;&gt;9. 多模型思维 ——《穷查理宝典》&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;原著精华&lt;/strong&gt;：
查理·芒格的“Lollapalooza 效应”：当你通过多个学科（心理学、经济学、物理学）的视角同时审视一个问题时，会产生叠加效应。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AI 对话迁移&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;核心策略&lt;/strong&gt;：&lt;strong&gt;多专家混合（Mixture of Experts Prompting）&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;实战案例&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Prompt&lt;/strong&gt;: “请分别扮演&lt;strong&gt;行为经济学家&lt;/strong&gt;（考虑非理性）、&lt;strong&gt;演化生物学家&lt;/strong&gt;（考虑生存竞争）和&lt;strong&gt;科幻小说家&lt;/strong&gt;（考虑未来可能性）三个角色，以此探讨‘人工智能对人类就业的长期影响’。最后，请综合这三个视角，写一份总结报告。”&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;liu-zong-jie-gei-ai-kai-fa-zhe-de-shu-dan-zu-he&quot;&gt;六、总结：给 AI 开发者的书单组合&lt;/h2&gt;
&lt;p&gt;如果只能选 3 本书来提升你的 Prompt 能力，我推荐这个“最优组合”：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;入门：《学会提问》&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;作用&lt;/em&gt;：帮你识别偏见，写出逻辑严密、没有歧义的基础 Prompt。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;方法：《如何解决问题》&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;作用&lt;/em&gt;：教你掌握 CoT（思维链），学会拆解复杂任务，构建 Agent 的工作流。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;境界：柏拉图《对话录》&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;作用&lt;/em&gt;：学会迭代与追问，从“问出答案”进阶到“问出本质”。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;记住：真正的提问高手，不是问题多，而是能快速排除 80% 无意义问题的人。&lt;/strong&gt; 好的 Prompt，就是帮 AI 排除干扰，直击靶心。&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>彻底搞懂 Agent Skills：从原理到实践</title>
        <published>2026-01-04T00:00:00+00:00</published>
        <updated>2026-01-04T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/deep-dive-into-agent-skills/"/>
        <id>https://scp.net.cn/blog/deep-dive-into-agent-skills/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/deep-dive-into-agent-skills/">&lt;p&gt;随着 AI Agent 生态的演进，Anthropic 最近推出了 &lt;strong&gt;Agent Skills&lt;/strong&gt;（智能体技能）。这不仅仅是一个新功能，更是一种让 AI 更加专业化、标准化的新范式。&lt;/p&gt;
&lt;p&gt;很多开发者容易将 Skills 与 MCP（Model Context Protocol）混淆。本文将结合官方文档与实战经验，带你彻底搞懂 Agent Skill 的本质、使用方法、背后的设计哲学以及它与 MCP 的根本区别。&lt;/p&gt;
&lt;h2 id=&quot;1-agent-skill-de-ben-zhi-shi-shen-me&quot;&gt;1. Agent Skill 的本质是什么？&lt;/h2&gt;
&lt;p&gt;简单来说，&lt;strong&gt;Agent Skill 是一个包含指令的 Markdown 文件，它教会 Claude 如何完成特定的任务。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;如果把 AI 比作一个新入职的员工：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Prompt&lt;/strong&gt; 是你临时的一句话命令。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Memory&lt;/strong&gt; 是他的记事本。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MCP&lt;/strong&gt; 是你给他配的电脑、数据库权限和 API 工具。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Skill&lt;/strong&gt; 则是你发给他的&lt;strong&gt;员工手册&lt;/strong&gt;或&lt;strong&gt;SOP（标准作业程序）&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Skill 赋予了 AI “专业知识”和“流程规范”。它不是工具本身，而是关于&lt;strong&gt;如何使用工具&lt;/strong&gt;以及&lt;strong&gt;遵循什么标准&lt;/strong&gt;的知识。&lt;/p&gt;
&lt;p&gt;例如，你可以创建一个 Skill 来教 Claude：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;按照团队特定的代码规范审查 Pull Request。&lt;/li&gt;
&lt;li&gt;生成符合公司格式的 Git Commit Message。&lt;/li&gt;
&lt;li&gt;查询数据库时优先使用特定的优化 SQL 模式。&lt;/li&gt;
&lt;li&gt;使用 Python 脚本生成符合 Slack 限制的 GIF 动图。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本质上，Skill 是&lt;strong&gt;结构化的上下文注入&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id=&quot;2-agent-skill-de-shi-yong-fang-fa&quot;&gt;2. Agent Skill 的使用方法&lt;/h2&gt;
&lt;p&gt;使用 Skill 非常简单，核心在于创建一个 &lt;code&gt;SKILL.md&lt;/code&gt; 文件。&lt;/p&gt;
&lt;h3 id=&quot;2-1-wen-jian-jie-gou&quot;&gt;2.1 文件结构&lt;/h3&gt;
&lt;p&gt;一个最简单的 Skill 只需要一个文件夹和一个 &lt;code&gt;SKILL.md&lt;/code&gt; 文件：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;my-skill/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;└── SKILL.md&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;SKILL.md&lt;/code&gt; 由两部分组成：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;YAML Frontmatter&lt;/strong&gt;：元数据，告诉 Claude 这个技能叫什么，什么时候用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Markdown 内容&lt;/strong&gt;：具体的指令和示例。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;2-2-bian-xie-shi-li&quot;&gt;2.2 编写示例&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; code-reviewer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;description&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 当用户请求审查代码或 PR 时使用此技能。它定义了团队的代码审查标准。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Code Reviewer Skill&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;##&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; 审查标准&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;1.&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;font-weight: bold;&quot;&gt; **&lt;/span&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;命名规范&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;font-weight: bold;&quot;&gt;**&lt;/span&gt;&lt;span&gt;：确保所有变量使用驼峰命名法 (camelCase)。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;2.&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;font-weight: bold;&quot;&gt; **&lt;/span&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;错误处理&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;font-weight: bold;&quot;&gt;**&lt;/span&gt;&lt;span&gt;：所有外部调用必须包含 try-catch 块。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;3.&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;font-weight: bold;&quot;&gt; **&lt;/span&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;注释&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;font-weight: bold;&quot;&gt;**&lt;/span&gt;&lt;span&gt;：公共方法必须有 Javadoc/Docstring。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;##&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; 步骤&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;1.&lt;/span&gt;&lt;span&gt; 阅读代码变更。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;2.&lt;/span&gt;&lt;span&gt; 检查是否符合上述标准。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;3.&lt;/span&gt;&lt;span&gt; 输出 Markdown 格式的审查报告。&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;2-3-cun-fang-wei-zhi&quot;&gt;2.3 存放位置&lt;/h3&gt;
&lt;p&gt;Claude 会根据存放位置决定 Skill 的生效范围：&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;位置&lt;/th&gt;&lt;th style=&quot;text-align: left&quot;&gt;路径&lt;/th&gt;&lt;th style=&quot;text-align: left&quot;&gt;适用范围&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;项目级&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;code&gt;.claude/skills/&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;仅当前项目可用，适合项目特定的规范&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;个人级&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;code&gt;~/.claude/skills/&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;跨项目可用，适合个人的工作流偏好&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;企业级&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;(托管配置)&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;组织内所有成员可用&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3 id=&quot;2-4-zi-dong-hong-fa&quot;&gt;2.4 自动触发&lt;/h3&gt;
&lt;p&gt;你&lt;strong&gt;不需要&lt;/strong&gt;显式调用 Skill（如 &lt;code&gt;/review-code&lt;/code&gt;）。当你的 Prompt 意图与 Skill 的 &lt;code&gt;description&lt;/code&gt; 匹配时，Claude 会自动加载并应用该 Skill。&lt;/p&gt;
&lt;h3 id=&quot;2-5-shi-zhan-yan-shi-gou-jian-svg-tu-biao-sheng-cheng-zhu-shou&quot;&gt;2.5 实战演示：构建“SVG 图标生成助手”&lt;/h3&gt;
&lt;p&gt;让我们构建一个更实用的 Skill，教 Claude 如何生成风格统一的 SVG 图标。这个例子展示了 Skill 如何结合外部文件来增强能力。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;目录结构：&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;.claude/skills/svg-icon-generator/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── SKILL.md&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;└── palette.json  # 存储品牌配色方案&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;文件内容 (&lt;code&gt;SKILL.md&lt;/code&gt;)：&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; svg-icon-generator&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;description&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 当用户需要创建、设计或生成 SVG 图标/图像时使用。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; SVG Icon Generator&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;##&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; 任务目标&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;生成符合 Material Design 风格的 SVG 代码。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;##&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; 设计约束&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;1.&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;font-weight: bold;&quot;&gt; **&lt;/span&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;尺寸&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;font-weight: bold;&quot;&gt;**&lt;/span&gt;&lt;span&gt;：默认 24x24 viewBox。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;2.&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;font-weight: bold;&quot;&gt; **&lt;/span&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;颜色&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;font-weight: bold;&quot;&gt;**&lt;/span&gt;&lt;span&gt;：必须优先从 &lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;`palette.json`&lt;/span&gt;&lt;span&gt; 中读取品牌色。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;3.&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;font-weight: bold;&quot;&gt; **&lt;/span&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;结构&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;font-weight: bold;&quot;&gt;**&lt;/span&gt;&lt;span&gt;：尽量使用 &lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;`&amp;lt;path&amp;gt;`&lt;/span&gt;&lt;span&gt; 元素，保持代码精简。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;##&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; 执行步骤&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;1.&lt;/span&gt;&lt;span&gt; 读取 &lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;`palette.json`&lt;/span&gt;&lt;span&gt; 获取允许的颜色列表。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;2.&lt;/span&gt;&lt;span&gt; 根据用户描述设计图标几何形状。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;3.&lt;/span&gt;&lt;span&gt; 输出完整的 &lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;`&amp;lt;svg&amp;gt;`&lt;/span&gt;&lt;span&gt; 代码块。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;4.&lt;/span&gt;&lt;span&gt; 验证 SVG 是否闭合且无语法错误。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;##&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; 示例&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;font-weight: bold;&quot;&gt;**&lt;/span&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;用户&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;font-weight: bold;&quot;&gt;**&lt;/span&gt;&lt;span&gt;：&amp;quot;画一个红色的删除按钮&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;font-weight: bold;&quot;&gt;**&lt;/span&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;行为&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;font-weight: bold;&quot;&gt;**&lt;/span&gt;&lt;span&gt;：读取调色板找到 &amp;quot;danger-red&amp;quot; (#FF5252)，生成一个带 &amp;quot;X&amp;quot; 符号的圆形图标。&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通过这个结构，Claude 不仅学会了“怎么画”，还学会了“用什么颜色画”，确保了输出的一致性。&lt;/p&gt;
&lt;h2 id=&quot;3-jian-jin-shi-pi-lu-ji-zhi-progressive-disclosure&quot;&gt;3. 渐进式披露机制 (Progressive Disclosure)&lt;/h2&gt;
&lt;p&gt;这是 Agent Skill 设计中最精妙的地方。&lt;/p&gt;
&lt;p&gt;你可能会担心：&lt;em&gt;“如果我定义了 100 个 Skills，每次对话都把它们全部塞进 Context，Token 不就爆炸了吗？”&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;答案是&lt;strong&gt;不会&lt;/strong&gt;。Agent Skills 使用了一种**渐进式披露（Progressive Disclosure）**机制。&lt;/p&gt;
&lt;h3 id=&quot;ji-zhi-liu-cheng&quot;&gt;机制流程&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;扫描与索引&lt;/strong&gt;：在会话开始时，Claude 仅读取所有可用 Skills 的 &lt;strong&gt;YAML Frontmatter&lt;/strong&gt;（主要是 &lt;code&gt;name&lt;/code&gt; 和 &lt;code&gt;description&lt;/code&gt;）。这只占用极少的 Token。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;意图匹配&lt;/strong&gt;：当你发出指令（例如“帮我生成个 GIF”）时，Claude 根据 &lt;code&gt;description&lt;/code&gt; 判断哪个 Skill 相关。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;按需加载&lt;/strong&gt;：一旦命中某个 Skill，Claude 才会读取该 Skill 的 &lt;code&gt;SKILL.md&lt;/code&gt; 完整内容（指令、步骤、示例）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;延迟加载支持文件&lt;/strong&gt;：如果 Skill 非常复杂，包含大量的文档或脚本，你可以将它们放在单独的文件中，并在 &lt;code&gt;SKILL.md&lt;/code&gt; 中引用。Claude 只有在真正需要阅读细节时，才会去读取这些支持文件。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;价值&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Token 效率极高&lt;/strong&gt;：你可以拥有成百上千个 Skills，但只会消耗命中技能的 Token。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;专注度&lt;/strong&gt;：避免无关的指令干扰 AI 的注意力。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;4-agent-skill-vs-mcp-dao-di-xuan-na-ge&quot;&gt;4. Agent Skill vs MCP：到底选哪个？&lt;/h2&gt;
&lt;p&gt;这是开发者最容易困惑的问题。两者看似都扩展了 AI 的能力，但侧重点完全不同。&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;维度&lt;/th&gt;&lt;th style=&quot;text-align: left&quot;&gt;Agent Skill&lt;/th&gt;&lt;th style=&quot;text-align: left&quot;&gt;MCP (Model Context Protocol)&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;核心定义&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Knowledge (知识/流程)&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Tool / Capability (工具/能力)&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;作用&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;教 AI &lt;strong&gt;“如何做”&lt;/strong&gt; (How to do)&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;给 AI &lt;strong&gt;“用什么”&lt;/strong&gt; (What to use)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;实现方式&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Markdown 文件 (文本指令)&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Server/Client 协议 (代码/API)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;依赖环境&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;依赖现有的计算环境 (如本地 Shell, Python)&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;依赖外部服务的连接 (如 Postgres, Slack API)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;典型场景&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;代码规范、最佳实践、复杂任务的SOP&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;读取数据库、访问文件系统、调用 SaaS API&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3 id=&quot;jue-ce-zhi-nan&quot;&gt;决策指南&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;选择 MCP，如果：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;你需要让 AI 连接到一个外部系统（如数据库、Jira、GitHub、Slack）。&lt;/li&gt;
&lt;li&gt;你需要执行 AI 无法通过写代码直接完成的操作（如读取私有云日志）。&lt;/li&gt;
&lt;li&gt;你在构建通用的工具能力。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;选择 Skill，如果：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;你想规范 AI 的输出格式（如特定的 Commit 格式）。&lt;/li&gt;
&lt;li&gt;你想固化某种工作流（如“发布前的检查清单”）。&lt;/li&gt;
&lt;li&gt;你想让 AI 学会使用现有的工具（例如，你已经装了 &lt;code&gt;ffmpeg&lt;/code&gt;，写一个 Skill 教 AI 如何组合参数来处理视频）。&lt;/li&gt;
&lt;li&gt;你需要复用一组复杂的 Prompt 提示词。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;xie-tong-gong-zuo&quot;&gt;协同工作&lt;/h3&gt;
&lt;p&gt;最强大的模式是 &lt;strong&gt;Skill + MCP&lt;/strong&gt; 结合使用：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MCP&lt;/strong&gt; 提供“查询数据库”的能力。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Skill&lt;/strong&gt; 提供“查询数据库时必须遵循的表结构规范和安全准则”。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;zong-jie&quot;&gt;总结&lt;/h2&gt;
&lt;p&gt;Agent Skill 是 AI 时代的“岗位培训手册”。它利用&lt;strong&gt;渐进式披露&lt;/strong&gt;机制，以极低的成本赋予了 AI 专业的领域知识和流程规范。&lt;/p&gt;
&lt;p&gt;与 MCP 提供的“硬连接”能力不同，Skill 专注于“软实力”——即如何正确、优雅地使用工具。对于希望构建高质量、标准化 AI 辅助工作流的开发者来说，掌握 Agent Skill 的编写是必修课。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;em&gt;参考资料：&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://code.claude.com/docs/en/skills&quot;&gt;Claude Code Docs: Agent Skills&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://simonwillison.net/2025/Oct/16/claude-skills/&quot;&gt;Simon Willison: Claude Skills are awesome&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>现代 malloc 库核心内存管理策略</title>
        <published>2025-12-26T10:00:00+08:00</published>
        <updated>2025-12-26T10:00:00+08:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/modern-malloc-core-strategies/"/>
        <id>https://scp.net.cn/blog/modern-malloc-core-strategies/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/modern-malloc-core-strategies/">&lt;p&gt;内存分配器（Memory Allocator）是所有非托管语言（如 C/C++、Rust）程序的基石，也是许多托管语言（如 Java、Go）运行时的底层依赖。随着多核处理器的普及和云计算场景下对高并发、低延迟的极致追求，传统的 glibc &lt;code&gt;ptmalloc&lt;/code&gt; 在某些场景下逐渐显露出扩展性不足和碎片化的问题。&lt;/p&gt;
&lt;p&gt;本文将深入探讨现代主流 malloc 库（如 jemalloc、tcmalloc、mimalloc）背后的核心内存管理策略，看看它们是如何在速度、空间利用率和多线程扩展性之间找到平衡的。&lt;/p&gt;
&lt;h2 id=&quot;1-wei-shen-me-wo-men-xu-yao-xian-dai-fen-pei-qi&quot;&gt;1. 为什么我们需要现代分配器？&lt;/h2&gt;
&lt;p&gt;在单核时代，内存分配主要关注的是“如何找到一块大小合适的空闲内存”以及“如何减少碎片”。但在多核高并发时代，&lt;strong&gt;锁竞争（Lock Contention）&lt;/strong&gt; 成为了性能杀手。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ptmalloc&lt;/code&gt; 虽然引入了 per-thread arenas 来减少竞争，但在极高并发下，频繁的锁操作和缓存一致性流量（Cache Coherence Traffic）依然会导致显著的性能下降。此外，随着内存容量的增加，内存碎片（Fragmentation）带来的空间浪费成本也越来越高。&lt;/p&gt;
&lt;p&gt;现代分配器（Modern Allocators）通常致力于解决以下三个核心问题：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;多线程扩展性&lt;/strong&gt;：在分配和释放的“快路径”上尽可能做到无锁（Lock-free）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;缓存局部性（Cache Locality）&lt;/strong&gt;：让连续分配的对象在物理内存上也尽可能连续，提高 CPU 缓存命中率。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;内存利用率&lt;/strong&gt;：通过精细的 Size Class 划分和及时的内存归还策略，降低碎片率和 RSS（Resident Set Size）。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;2-he-xin-she-ji-ce-lue&quot;&gt;2. 核心设计策略&lt;/h2&gt;
&lt;p&gt;尽管 jemalloc、tcmalloc 和 mimalloc 的具体实现细节不同，但它们在宏观架构上惊人地相似。我们可以将其归纳为以下几个通用策略：&lt;/p&gt;
&lt;h3 id=&quot;2-1-thread-local-cache-tlc-xiao-chu-suo-jing-zheng&quot;&gt;2.1 Thread Local Cache (TLC) —— 消除锁竞争&lt;/h3&gt;
&lt;p&gt;这是现代分配器最重要的优化手段。每个线程都维护一份私有的缓存（Thread Local Cache），用于满足绝大多数的小对象分配需求。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;分配（Malloc）&lt;/strong&gt;：线程直接从自己的 TLC 中获取内存块，无需加锁，仅需简单的指针操作。这是“快路径”。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;释放（Free）&lt;/strong&gt;：如果对象属于当前线程管理，直接放回 TLC，同样无需加锁。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;只有当 TLC 耗尽（需要从全局获取）或 TLC 塞满（需要归还给全局）时，才会进入“慢路径”，涉及到全局锁或原子操作。&lt;/p&gt;
&lt;h3 id=&quot;2-2-size-classes-ge-chi-yu-dui-qi&quot;&gt;2.2 Size Classes —— 隔离与对齐&lt;/h3&gt;
&lt;p&gt;为了避免外碎片（External Fragmentation）并简化管理，分配器不会按用户请求的任意字节数分配，而是将大小向上取整到最近的 &lt;strong&gt;Size Class&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;例如，请求 12 字节，可能会分配 16 字节（属于 16-byte class）；请求 40 字节，分配 48 字节。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Segregated Free Lists（隔离空闲链表）&lt;/strong&gt;：每个 Size Class 都有自己独立的空闲链表。分配时只需从对应链表头部取下一个节点即可，复杂度为 O(1)。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;减少元数据开销&lt;/strong&gt;：同属一个 Page/Block 的对象通常大小相同，因此不需要在每个对象头部存储大小信息（Header），通过地址偏移即可计算出所属的 Size Class。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;2-3-duo-ji-huan-cun-jia-gou-hierarchical-caching&quot;&gt;2.3 多级缓存架构 (Hierarchical Caching)&lt;/h3&gt;
&lt;p&gt;为了在“独占”与“共享”之间取得平衡，现代分配器通常采用三级架构：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Thread Local Cache&lt;/strong&gt;：第一级，完全无锁，速度最快。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Central Cache / Arena&lt;/strong&gt;：第二级，共享资源。当 TLC 不足时，从这里批量获取对象；当 TLC 过大时，将对象批量归还于此。通常需要加锁（或使用细粒度锁）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Page Heap&lt;/strong&gt;：第三级，直接管理操作系统的大块内存（Pages/Spans）。当 Central Cache 不足时，向 Page Heap 申请新的页；当内存长期空闲时，将页归还给 OS。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;2-4-page-guan-li-yu-span&quot;&gt;2.4 Page 管理与 Span&lt;/h3&gt;
&lt;p&gt;分配器通常以 &lt;strong&gt;Page&lt;/strong&gt;（通常是 4KB 或更大）的倍数向 OS 申请内存。多个连续的 Page 组成一个 &lt;strong&gt;Span&lt;/strong&gt;（或 Run）。&lt;/p&gt;
&lt;p&gt;一个 Span 通常被切割成多个相同大小的小对象（属于同一个 Size Class）。这种设计使得分配器可以很容易地判断一个指针属于哪个 Span，进而知道它的大小和状态。&lt;/p&gt;
&lt;h2 id=&quot;3-zhu-liu-fen-pei-qi-an-li-fen-xi&quot;&gt;3. 主流分配器案例分析&lt;/h2&gt;
&lt;h3 id=&quot;3-1-tcmalloc-google&quot;&gt;3.1 tcmalloc (Google)&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;tcmalloc (Thread-Caching Malloc)&lt;/strong&gt; 是现代分配器架构的奠基者之一。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;架构&lt;/strong&gt;：Thread Cache -&amp;gt; Central Cache -&amp;gt; Page Heap。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;特点&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;小对象&lt;/strong&gt;：通过 Thread Cache 分配，无锁。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;中对象&lt;/strong&gt;：直接从 Page Heap 分配 Span。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Span 管理&lt;/strong&gt;：使用 Radix Tree 将地址映射到 Span 元数据，查找速度快。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;优势&lt;/strong&gt;：非常适合多线程环境，性能稳定，被广泛用于 C++ 服务端开发。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;3-2-jemalloc-freebsd-facebook&quot;&gt;3.2 jemalloc (FreeBSD, Facebook)&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;jemalloc&lt;/strong&gt; 最初为 FreeBSD 开发，后被 Firefox、Facebook、Rust（曾用）等广泛采用。它在减少内存碎片方面表现优异。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;核心概念&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Arena&lt;/strong&gt;：为了减少锁竞争，jemalloc 将内存划分为多个 Arena，每个线程绑定一个 Arena。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Chunk/Run/Region&lt;/strong&gt;：内存分层管理。Chunk 是大块内存，Run 是 Chunk 中的一部分，Region 是分配给用户的小对象。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Decay&lt;/strong&gt;：jemalloc 有非常智能的脏页清理（Decay）机制，能够平滑地将不再使用的 dirty pages 归还给 OS，避免 RSS 暴涨。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;优势&lt;/strong&gt;：在长时间运行的服务中，内存碎片控制得非常好，且具备强大的 Profiling 功能（jeprof）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;3-3-mimalloc-microsoft&quot;&gt;3.3 mimalloc (Microsoft)&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;mimalloc&lt;/strong&gt; 是微软研究院推出的新一代分配器，以极致的性能和安全性著称。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;创新点&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Free List Sharding&lt;/strong&gt;：它不仅有 Thread Local allocation，还支持 &lt;strong&gt;Thread Local free&lt;/strong&gt;。即使是其他线程释放了当前线程分配的内存，也不会产生复杂的锁竞争，而是放入一个特定的“分片”队列中。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mimalloc Pages&lt;/strong&gt;：它将 Page 的元数据直接存储在 Page 的头部，利用对齐特性快速访问，减少了 cache miss。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;优势&lt;/strong&gt;：在许多 benchmark 中性能超越 jemalloc 和 tcmalloc，且代码库相对精简，易于集成。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;4-kuai-su-shang-shou-demo&quot;&gt;4. 快速上手 Demo&lt;/h2&gt;
&lt;p&gt;大多数情况下，使用这些现代分配器&lt;strong&gt;不需要修改任何业务代码&lt;/strong&gt;。你只需要在编译时链接相应的库，或者在运行时通过 &lt;code&gt;LD_PRELOAD&lt;/code&gt; 环境变量进行替换即可。&lt;/p&gt;
&lt;p&gt;以下是一个简单的 C++ 测试程序 &lt;code&gt;main.cpp&lt;/code&gt;，我们将用它来演示如何切换不同的分配器：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;cpp&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5E81AC;font-weight: bold;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;iostream&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5E81AC;font-weight: bold;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;vector&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5E81AC;font-weight: bold;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;thread&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5E81AC;font-weight: bold;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;chrono&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; stress_test&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;int&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 100000&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;; ++&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        std&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;::&lt;/span&gt;&lt;span&gt;vector&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; v&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; // 频繁分配与释放&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; main&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    auto&lt;/span&gt;&lt;span&gt; start&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; std&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;::&lt;/span&gt;&lt;span&gt;chrono&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;::&lt;/span&gt;&lt;span&gt;high_resolution_clock&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;now&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    std&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;::&lt;/span&gt;&lt;span&gt;vector&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;std&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;::&lt;/span&gt;&lt;span&gt;thread&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; threads&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;int&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 8&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;; ++&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        threads&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;emplace_back&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;stress_test&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;auto&amp;amp;&lt;/span&gt;&lt;span&gt; t&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; :&lt;/span&gt;&lt;span&gt; threads&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span&gt; t&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;join&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    auto&lt;/span&gt;&lt;span&gt; end&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; std&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;::&lt;/span&gt;&lt;span&gt;chrono&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;::&lt;/span&gt;&lt;span&gt;high_resolution_clock&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;now&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    std&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;::&lt;/span&gt;&lt;span&gt;chrono&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;::&lt;/span&gt;&lt;span&gt;duration&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; diff&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; end&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; -&lt;/span&gt;&lt;span&gt; start&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    std&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;::&lt;/span&gt;&lt;span&gt;cout&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Time taken: &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span&gt; diff&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;count&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; s&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span&gt; std&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;::&lt;/span&gt;&lt;span&gt;endl&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;4-1-shi-yong-tcmalloc-gperftools&quot;&gt;4.1 使用 tcmalloc (gperftools)&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;安装&lt;/strong&gt;：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# Ubuntu/Debian&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; apt-get install google-perftools libgoogle-perftools-dev&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# macOS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;brew&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; install gperftools&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;运行方式 1：LD_PRELOAD (无需重新编译)&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# Linux 示例路径&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;LD_PRELOAD&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;/usr/lib/x86_64-linux-gnu/libtcmalloc.so.4&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; ./main&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;运行方式 2：编译链接&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;g++&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; main.cpp -o main -ltcmalloc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;./main&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;4-2-shi-yong-jemalloc&quot;&gt;4.2 使用 jemalloc&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;安装&lt;/strong&gt;：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# Ubuntu/Debian&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; apt-get install libjemalloc-dev&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# macOS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;brew&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; install jemalloc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;运行方式 1：LD_PRELOAD&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# Linux 示例路径&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;LD_PRELOAD&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;/usr/lib/x86_64-linux-gnu/libjemalloc.so.2&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; ./main&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;运行方式 2：编译链接&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;g++&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; main.cpp -o main -ljemalloc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;./main&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;进阶：打印内存统计信息&lt;/strong&gt;
jemalloc 提供了强大的自省功能。你可以在代码中调用 &lt;code&gt;malloc_stats_print&lt;/code&gt;（需要包含 &lt;code&gt;&amp;lt;jemalloc/jemalloc.h&amp;gt;&lt;/code&gt; 并链接库）：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;cpp&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 在程序结束前调用，将统计信息输出到 stderr&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// malloc_stats_print(NULL, NULL, NULL); &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;4-3-shi-yong-mimalloc&quot;&gt;4.3 使用 mimalloc&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;安装&lt;/strong&gt;：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 源码编译安装或使用包管理器 (archlinux 等)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; clone https://github.com/microsoft/mimalloc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; mimalloc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; mkdir&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; build&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; cd&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; build&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;cmake&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; ..&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; make&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; sudo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; make install&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;运行方式 1：LD_PRELOAD&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# mimalloc 提供了方便的覆盖动态库&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;LD_PRELOAD&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;/usr/local/lib/libmimalloc.so&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; ./main&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;运行方式 2：编译链接&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;g++&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; main.cpp -o main -lmimalloc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;./main&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;5-zong-jie-yu-xuan-xing-jian-yi&quot;&gt;5. 总结与选型建议&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;特性&lt;/th&gt;&lt;th style=&quot;text-align: left&quot;&gt;glibc (ptmalloc)&lt;/th&gt;&lt;th style=&quot;text-align: left&quot;&gt;tcmalloc&lt;/th&gt;&lt;th style=&quot;text-align: left&quot;&gt;jemalloc&lt;/th&gt;&lt;th style=&quot;text-align: left&quot;&gt;mimalloc&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;设计目标&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;通用性、兼容性&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;高并发吞吐&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;低碎片、低延迟&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;极致性能、安全&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;核心机制&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Per-thread arenas&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Thread Cache + Central Heap&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Arenas + Decay&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Free List Sharding&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;碎片控制&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;一般&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;较好&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;优秀&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;优秀&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;适用场景&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;默认系统环境&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;高频小对象分配&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;内存敏感型服务 (如 Redis)&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;新兴高性能项目&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;对于大多数应用程序，&lt;strong&gt;jemalloc&lt;/strong&gt; 目前是一个非常均衡且成熟的选择，特别是当你关注长期运行服务的内存占用时（Redis 默认就使用 jemalloc）。如果你追求极致的吞吐量或者正在开发新的高性能组件，&lt;strong&gt;mimalloc&lt;/strong&gt; 值得一试。而 &lt;strong&gt;tcmalloc&lt;/strong&gt; 依然是许多 C++ 大型系统的稳健之选。&lt;/p&gt;
&lt;p&gt;理解这些底层策略，不仅有助于我们选择合适的库，更能帮助我们在编写高性能代码时，更有意识地规划内存的使用模式。&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>高性能开发参考手册</title>
        <published>2025-12-13T00:00:00+00:00</published>
        <updated>2025-12-13T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/high-performance-low-latency-handbook/"/>
        <id>https://scp.net.cn/blog/high-performance-low-latency-handbook/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/high-performance-low-latency-handbook/">&lt;h2 id=&quot;he-xin-yuan-ze&quot;&gt;核心原则&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;明确目标：以端到端延迟、99/99.9 分位、吞吐、稳定性为一等指标，避免只优化平均值。&lt;/li&gt;
&lt;li&gt;数据驱动：先度量后优化，建立可复现的基准与环境隔离，避免“改参数碰运气”。&lt;/li&gt;
&lt;li&gt;贴近瓶颈：围绕 CPU、内存、锁、I/O、网络、存储逐层定位，逐个消除；不要平均用力。&lt;/li&gt;
&lt;li&gt;简化路径：减少层次、减少拷贝、减少分配、减少上下文切换、减少序列化复杂度。&lt;/li&gt;
&lt;li&gt;面向故障设计：考虑抖动、拥塞、反压、尾延迟的治理与保护带（降级、限流、超时）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;jia-gou-yu-mo-shi&quot;&gt;架构与模式&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;零拷贝与最少拷贝：&lt;code&gt;sendfile&lt;/code&gt;、&lt;code&gt;splice&lt;/code&gt;、&lt;code&gt;mmap&lt;/code&gt;；缓冲复用与批处理（batching）。&lt;/li&gt;
&lt;li&gt;内存池与对象复用：绕过频繁 &lt;code&gt;malloc/free&lt;/code&gt;，用 slab/pool、arena（&lt;code&gt;jemalloc&lt;/code&gt;/&lt;code&gt;tcmalloc&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;无锁与低锁：无锁环形队列、读写锁分离、分段锁、尽量使用原子与 CAS。&lt;/li&gt;
&lt;li&gt;异步与事件驱动：&lt;code&gt;io_uring&lt;/code&gt;、&lt;code&gt;epoll&lt;/code&gt;、&lt;code&gt;kqueue&lt;/code&gt;、AIO；避免阻塞调用和线程爆炸。&lt;/li&gt;
&lt;li&gt;数据面/控制面分离：热路径最短化，慢路径（日志、遥测、管理）异步或旁路。&lt;/li&gt;
&lt;li&gt;背压与负载整形：生产者-消费者配额、漏桶/令牌桶、优雅丢弃（tail-drop）与降级策略。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;yu-yan-yu-yun-xing-shi&quot;&gt;语言与运行时&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;C/C++：
&lt;ul&gt;
&lt;li&gt;使用 &lt;code&gt;-O2/-O3&lt;/code&gt;、&lt;code&gt;-march=native&lt;/code&gt;、&lt;code&gt;-flto&lt;/code&gt;；热点用 &lt;code&gt;restrict&lt;/code&gt;/&lt;code&gt;constexpr&lt;/code&gt;/&lt;code&gt;inline&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;明确对象生命周期，避免小对象频繁分配；内联小函数，消除虚调用开销。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Rust：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;no_std&lt;/code&gt; 场景下最短路径；&lt;code&gt;tokio&lt;/code&gt;/&lt;code&gt;monoio&lt;/code&gt; 选择基于工作负载；善用 &lt;code&gt;#[inline]&lt;/code&gt; 与 &lt;code&gt;Pin&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;使用 &lt;code&gt;tracing&lt;/code&gt; 收敛热路径指标；&lt;code&gt;bytes&lt;/code&gt;/&lt;code&gt;smallvec&lt;/code&gt; 降低分配。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Go：
&lt;ul&gt;
&lt;li&gt;减少逃逸与分配；控制 &lt;code&gt;GOMAXPROCS&lt;/code&gt;；用 &lt;code&gt;pprof&lt;/code&gt;/&lt;code&gt;trace&lt;/code&gt; 定位 GC 与调度热点。&lt;/li&gt;
&lt;li&gt;大量并发时首选通道背压或工作池；避免每请求起新 goroutine。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Java/JVM：
&lt;ul&gt;
&lt;li&gt;选择适合延迟目标的 GC（G1/ZGC/Shenandoah）；合理 &lt;code&gt;Xms=Xmx&lt;/code&gt;、&lt;code&gt;MaxGCPauseMillis&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;直堆外内存 &lt;code&gt;DirectByteBuffer&lt;/code&gt;/&lt;code&gt;Netty&lt;/code&gt; &lt;code&gt;PooledByteBufAllocator&lt;/code&gt;；避免对象风暴。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;nei-cun-yu-dui-xiang-guan-li&quot;&gt;内存与对象管理&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;分配器：&lt;code&gt;jemalloc&lt;/code&gt;/&lt;code&gt;tcmalloc&lt;/code&gt; 替换系统 &lt;code&gt;malloc&lt;/code&gt;，降低碎片与锁争用。&lt;/li&gt;
&lt;li&gt;NUMA 与局部性：&lt;code&gt;numactl --cpunodebind --membind&lt;/code&gt;；尽量让线程与数据同节点。&lt;/li&gt;
&lt;li&gt;缓存友好：紧凑结构体、消除 false-sharing（使用 &lt;code&gt;cacheline&lt;/code&gt; 对齐）；预取 &lt;code&gt;__builtin_prefetch&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;批处理：批量分配/释放、批量序列化；减少系统调用次数与锁进入次数。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;bing-fa-yu-suo&quot;&gt;并发与锁&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;尽量用无锁结构：环形缓冲、MPSC/MCSP 队列；热点读路径用 RCU/版本号。&lt;/li&gt;
&lt;li&gt;降低锁粒度：分段锁、局部计数、跨线程通信用消息传递代替共享状态。&lt;/li&gt;
&lt;li&gt;自旋与阻塞平衡：短临界区自旋，长临界区阻塞；避免在热路径打印日志或做 I/O。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;i-o-yu-wang-luo&quot;&gt;I/O 与网络&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;网络栈：
&lt;ul&gt;
&lt;li&gt;优先 &lt;code&gt;epoll&lt;/code&gt;/&lt;code&gt;kqueue&lt;/code&gt;/&lt;code&gt;io_uring&lt;/code&gt;；减少阻塞套接字；禁用 Nagle（&lt;code&gt;TCP_NODELAY&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;调优 &lt;code&gt;SO_RCVBUF/SO_SNDBUF&lt;/code&gt;、&lt;code&gt;TCP_QUICKACK&lt;/code&gt;；根据场景考虑 &lt;code&gt;busy-poll&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;协议设计：
&lt;ul&gt;
&lt;li&gt;序列化选择以延迟为先：&lt;code&gt;flatbuffers&lt;/code&gt;/&lt;code&gt;capnproto&lt;/code&gt;/自定义紧凑二进制；避免深层嵌套 JSON。&lt;/li&gt;
&lt;li&gt;明确超时、重试与幂等；避免惊群（accept 多线程）与 head-of-line 阻塞。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;工具与压测：&lt;code&gt;wrk&lt;/code&gt;/&lt;code&gt;fortio&lt;/code&gt;/&lt;code&gt;iperf3&lt;/code&gt;/&lt;code&gt;tc&lt;/code&gt;；使用 &lt;code&gt;flamegraph&lt;/code&gt; 识别热函数。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;cun-chu-yu-chi-jiu-hua&quot;&gt;存储与持久化&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;日志落盘：异步、批量、顺序写；日志与数据面分离磁盘或队列。&lt;/li&gt;
&lt;li&gt;数据库：选择适合延迟目标的引擎（LSM vs B-Tree），按工作负载调优写放大与缓存命中。&lt;/li&gt;
&lt;li&gt;缓存层：本地 LRU/LFU、跨节点一致性哈希；避免穿透与雪崩（限流、预热、降级）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;cao-zuo-xi-tong-yu-nei-he&quot;&gt;操作系统与内核&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;进程/线程：合理 &lt;code&gt;taskset&lt;/code&gt; 绑核，降低迁移；为关键线程提升调度类与优先级。&lt;/li&gt;
&lt;li&gt;文件与磁盘：&lt;code&gt;O_DIRECT&lt;/code&gt;/&lt;code&gt;O_NONBLOCK&lt;/code&gt; 场景化选择；I/O 调度器选择 &lt;code&gt;none&lt;/code&gt;/&lt;code&gt;mq-deadline&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;网络设备：&lt;code&gt;ethtool&lt;/code&gt; 关闭不必要的 offload，按负载调节 &lt;code&gt;RPS/RFS/XPS&lt;/code&gt; 与队列并行度。&lt;/li&gt;
&lt;li&gt;系统参数：&lt;code&gt;sysctl&lt;/code&gt; 中 &lt;code&gt;net.core.*&lt;/code&gt;、&lt;code&gt;net.ipv4.*&lt;/code&gt; 根据并发与突发特性进行整形。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;ke-guan-ce-xing-yu-fen-xi&quot;&gt;可观测性与分析&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;采样与火焰图：&lt;code&gt;perf&lt;/code&gt;/&lt;code&gt;bcc&lt;/code&gt;/&lt;code&gt;async-profiler&lt;/code&gt;/&lt;code&gt;pprof&lt;/code&gt;；以采样证据驱动优化。&lt;/li&gt;
&lt;li&gt;端到端追踪：&lt;code&gt;OpenTelemetry&lt;/code&gt;/&lt;code&gt;Jaeger&lt;/code&gt;；记录关键自定义 span 和业务标签。&lt;/li&gt;
&lt;li&gt;指标分位：暴露 &lt;code&gt;p50/p95/p99/p99.9&lt;/code&gt; 与队列深度、等待时间、批量大小、重试次数。&lt;/li&gt;
&lt;li&gt;压测分层：协议层、业务层、系统层分别压测；构建稳定、可复现的基准环境。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;you-hua-liu-cheng-jian-yi&quot;&gt;优化流程（建议）&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;建立基准：选定代表性负载与数据规模，固定环境变量与参数快照。&lt;/li&gt;
&lt;li&gt;定位瓶颈：用火焰图/追踪对齐指标（CPU、GC、锁、I/O）；画出关键路径图。&lt;/li&gt;
&lt;li&gt;设计改动：优先零拷贝、批处理、对象复用、减少锁与系统调用；明确风险与回滚。&lt;/li&gt;
&lt;li&gt;渐进验证：小步提交，灰度发布；以分位数回归标准判断有效性。&lt;/li&gt;
&lt;li&gt;持续监控：上线后观察尾延迟与抖动，必要时加保护带（限流/降级/重试退避）。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;chang-jian-xian-jing&quot;&gt;常见陷阱&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;只看平均值不看分位尾巴，导致生产抖动被忽视。&lt;/li&gt;
&lt;li&gt;大量细粒度 goroutine/线程造成调度震荡与上下文切换风暴。&lt;/li&gt;
&lt;li&gt;对象风暴与无界队列，GC 或 OOM 尾延迟飙升。&lt;/li&gt;
&lt;li&gt;过度序列化/反序列化与拷贝；日志同步写阻塞热路径。&lt;/li&gt;
&lt;li&gt;盲目调大缓冲与并发，反而引起排队与头阻塞。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;su-cha-qing-dan&quot;&gt;速查清单&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;CPU：绑定热点线程、减少分支与虚调用、提升缓存命中。&lt;/li&gt;
&lt;li&gt;内存：池化与批量、NUMA 亲和、消除 false-sharing。&lt;/li&gt;
&lt;li&gt;锁：热点读路径无锁或读写锁、缩短临界区、用消息传递代替共享。&lt;/li&gt;
&lt;li&gt;I/O：异步化、批处理、零拷贝、合理超时与背压。&lt;/li&gt;
&lt;li&gt;网络：&lt;code&gt;TCP_NODELAY&lt;/code&gt;、合理缓冲、避免惊群、压测与火焰图定位。&lt;/li&gt;
&lt;li&gt;存储：顺序写、异步刷盘、缓存命中、写放大控制。&lt;/li&gt;
&lt;li&gt;观测：&lt;code&gt;p99/p99.9&lt;/code&gt; 指标、端到端追踪；压测稳定可复现。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;can-kao-zi-liao&quot;&gt;参考资料&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Patterns 与资源集合：https://github.com/penberg/awesome-low-latency&lt;/li&gt;
&lt;li&gt;Linux 性能工具：&lt;code&gt;perf&lt;/code&gt;、&lt;code&gt;bcc&lt;/code&gt;、&lt;code&gt;sysstat&lt;/code&gt;、&lt;code&gt;flamegraph&lt;/code&gt;、&lt;code&gt;async-profiler&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;压测工具：&lt;code&gt;wrk&lt;/code&gt;、&lt;code&gt;fortio&lt;/code&gt;、&lt;code&gt;hey&lt;/code&gt;、&lt;code&gt;iperf3&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;序列化：&lt;code&gt;flatbuffers&lt;/code&gt;、&lt;code&gt;capnproto&lt;/code&gt;、&lt;code&gt;protobuf&lt;/code&gt;（谨慎考虑层级与可选字段）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;（本文根据业界低延迟与高性能实践汇总，结合工程经验提炼为可操作的手册式清单，可作为团队性能优化与系统设计的参考。）&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Redis vs. Valkey：2025年技术选型深度指南</title>
        <published>2025-12-07T08:30:00+08:00</published>
        <updated>2025-12-07T08:30:00+08:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/valkey-vs-redis-technical-comparison/"/>
        <id>https://scp.net.cn/blog/valkey-vs-redis-technical-comparison/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/valkey-vs-redis-technical-comparison/">&lt;p&gt;2024年初，Redis 宣布修改其开源协议，这一举动在开源社区引发了巨大的震动，也直接促成了 Valkey 的诞生。如今一年过去，随着 Redis 8.0 和 Valkey 8.0/8.1 的相继发布，这场“分叉“已经不仅仅是关于许可证的争论，更演变成了两种不同技术理念和架构路线的较量。&lt;/p&gt;
&lt;p&gt;本文将基于最新的技术资料，深入对比这两个项目的现状，帮助开发者在 2025 年做出明智的技术选型。&lt;/p&gt;
&lt;h2 id=&quot;1-he-xin-chai-yi-gai-lan-cong-dna-dao-fen-dao-yang-biao&quot;&gt;1. 核心差异概览：从 DNA 到分道扬镳&lt;/h2&gt;
&lt;p&gt;Valkey 最初是作为 Redis 7.2.4 的直接 Fork 诞生的，因此它们共享着相同的 DNA：基于内存的键值存储、支持丰富的数据结构、Lua 脚本以及主从复制架构。然而，随着时间的推移，两者在发展方向上展现出了明显的差异。&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;特性&lt;/th&gt;&lt;th style=&quot;text-align: left&quot;&gt;Redis (8.0+)&lt;/th&gt;&lt;th style=&quot;text-align: left&quot;&gt;Valkey (8.0/8.1+)&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;许可证&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;RSALv2 / SSPLv1 (非 OSI 认可开源)&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;BSD 3-Clause (完全开源，Linux 基金会托管)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;治理模式&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;商业公司主导 (Redis Inc.)&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;社区驱动 (AWS, Google, Oracle, Snap 等支持)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;核心架构&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;保守改进，集成 Stack 模块&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;激进优化，重构核心 I/O 和内存管理&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;生态定位&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;更加封闭的商业生态，强调集成体验&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;坚持开放标准，兼容现有 Redis 生态&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;2-jia-gou-yu-xing-neng-duo-xian-cheng-de-jiao-liang&quot;&gt;2. 架构与性能：多线程的较量&lt;/h2&gt;
&lt;p&gt;线程模型的演进是本次对比的重头戏。长期以来，Redis 的单线程模型既是其简单高效的秘诀，也是其在大核服务器上的性能瓶颈。&lt;/p&gt;
&lt;h3 id=&quot;redis-8-0-wen-jian-de-duo-xian-cheng-i-o&quot;&gt;Redis 8.0：稳健的多线程 I/O&lt;/h3&gt;
&lt;p&gt;Redis 在 6.0 引入了多线程 I/O，但核心命令执行依然是单线程的。Redis 8.0 进一步优化了这一模型。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;改进点&lt;/strong&gt;：Redis 8.0 的新 I/O 线程模型允许将更多网络读写和协议解析工作卸载给辅助线程。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;性能表现&lt;/strong&gt;：在多核 Intel CPU 上，开启 &lt;code&gt;io-threads&lt;/code&gt; 后，吞吐量相比旧版本提升了约 &lt;strong&gt;112%&lt;/strong&gt;。但其核心依然受到主线程处理能力的限制。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;valkey-8-0-ji-jin-de-yi-bu-i-o-jia-gou&quot;&gt;Valkey 8.0：激进的异步 I/O 架构&lt;/h3&gt;
&lt;p&gt;Valkey 采取了更为激进的策略。虽然为了保持原子性，命令执行仍为单线程，但 Valkey 8.0 引入了&lt;strong&gt;增强型异步 I/O 线程&lt;/strong&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;架构革新&lt;/strong&gt;：Valkey 现在可以并行处理网络读取、解析以及响应写入，同时还能基于实时负载智能地将 I/O 任务分发到多个核心。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;百万级 RPS&lt;/strong&gt;：Benchmark 显示，在 AWS c7g.4xlarge (16 vCPU) 实例上，Valkey 8.0 达到了惊人的 &lt;strong&gt;119 万 RPS&lt;/strong&gt; (Requests Per Second)，相比 7.2 版本提升了 &lt;strong&gt;230%&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;实战反馈&lt;/strong&gt;：Linux 内核开发者 Dirk Hohndel 报告称，在处理大规模数据流时，Valkey 带来了约 3 倍的性能提升。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;结论&lt;/strong&gt;：在现代多核服务器上，Valkey 展现出了更高的垂直扩展能力（Scale-up），能够更榨干硬件性能。&lt;/p&gt;
&lt;h2 id=&quot;3-nei-cun-xiao-lu-mei-zi-jie-du-suan-shu&quot;&gt;3. 内存效率：每字节都算数&lt;/h2&gt;
&lt;p&gt;对于内存数据库而言，内存效率直接等同于金钱。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Valkey 的 Swiss Tables 优化&lt;/strong&gt;：Valkey 8.1 受 Google Abseil “Swiss Tables” 的启发，彻底重写了底层的哈希表实现。这一改变使得每个键值对的内存开销减少了约 20 字节。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;实际收益&lt;/strong&gt;：对于包含数亿个小 Key 的大规模数据集，这意味着最高可达 &lt;strong&gt;20% 的内存节省&lt;/strong&gt;。在大规模集群中，这直接转化为显著的成本降低。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Redis&lt;/strong&gt;：虽然也有内存驱逐策略的优化，但在核心数据结构的内存紧凑性上，近期未见如此幅度的底层重构。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;4-ke-kao-xing-yu-fu-zhi-gao-bie-fork-feng-bao&quot;&gt;4. 可靠性与复制：告别 Fork 风暴&lt;/h2&gt;
&lt;p&gt;Redis 的持久化（RDB/AOF）和全量复制一直依赖 &lt;code&gt;fork()&lt;/code&gt; 系统调用。在拥有大内存（如 &amp;gt;50GB）的实例上，&lt;code&gt;fork()&lt;/code&gt; 不仅耗时，还会通过 Copy-on-Write (COW) 机制消耗大量额外内存，甚至导致性能抖动。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Redis 8.0 的双流复制&lt;/strong&gt;：引入了双流机制，一个流传 RDB，另一个流传增量数据，使得同步速度提升了约 18%。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Valkey 的双通道复制&lt;/strong&gt;：Valkey 同样实现了类似的双通道复制架构。更重要的是，Valkey 针对 &lt;code&gt;fork()&lt;/code&gt; 的开销进行了深度优化，在重读场景下的全量同步时间最高减少了 &lt;strong&gt;50%&lt;/strong&gt;，极大缓解了节点故障恢复时的集群压力。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;5-gong-neng-ji-da-er-quan-vs-zhuan-er-jing&quot;&gt;5. 功能集：大而全 vs 专而精&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Redis&lt;/strong&gt; 的策略是“开箱即用“的丰富度。Redis 8.0 将之前的 Redis Stack 模块及其功能直接吸收到核心发行版中：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;原生 JSON 支持&lt;/strong&gt;：无需插件，直接操作 JSON 文档。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;向量搜索 (Vector Search)&lt;/strong&gt;：面向 AI 应用，支持高维向量相似度搜索。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;时间序列 &amp;amp; 概率数据结构&lt;/strong&gt;：内置 Bloom Filter 等。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Valkey&lt;/strong&gt; 则专注于核心数据库的能力，但追赶速度极快：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;JSON 支持&lt;/strong&gt;：Valkey 8.1 已经引入了 JSON 数据类型支持。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bloom Filter&lt;/strong&gt;：同样在 8.1 中加入。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;缺失项&lt;/strong&gt;：目前 Valkey 在向量搜索（Vector Search）方面尚未原生集成，这对于需要构建 RAG（检索增强生成）应用的开发者来说是一个重要的考量点。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;zong-jie-ru-he-xuan-ze&quot;&gt;总结：如何选择？&lt;/h2&gt;
&lt;p&gt;2025年的选择逻辑比以往清晰：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;选择 Redis 8.0 如果…&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;你需要&lt;strong&gt;官方企业级支持&lt;/strong&gt;和商业合规背书。&lt;/li&gt;
&lt;li&gt;你的应用深度依赖 &lt;strong&gt;Redis Stack&lt;/strong&gt; 的高级功能，特别是 &lt;strong&gt;Vector Search&lt;/strong&gt; 进行 AI 开发。&lt;/li&gt;
&lt;li&gt;你更看重全家桶式的集成体验（如 Redis Insight, Redis Copilot）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;选择 Valkey 8.1 如果…&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;你坚定支持&lt;strong&gt;完全开源 (Open Source)&lt;/strong&gt; 协议，避免许可证风险。&lt;/li&gt;
&lt;li&gt;你的场景是&lt;strong&gt;极致的高并发&lt;/strong&gt;，需要单节点承载百万级 QPS。&lt;/li&gt;
&lt;li&gt;你拥有&lt;strong&gt;海量小数据&lt;/strong&gt;，20% 的内存节省对成本至关重要。&lt;/li&gt;
&lt;li&gt;你希望紧跟 Linux 基金会及 AWS/Google 等大厂主导的开放技术栈。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Valkey 已经证明了它不仅仅是一个“抗议的 Fork“，而是一个在性能和架构上敢于革新的强大竞争者。对于大多数纯缓存和基础 KV 存储场景，Valkey 如今无疑是更具吸引力的选择。&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Linux TC 进阶：一行命令实现特定流量延迟</title>
        <published>2025-12-04T12:13:32+05:30</published>
        <updated>2025-12-04T12:13:32+05:30</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/a-tc-commond-intro/"/>
        <id>https://scp.net.cn/blog/a-tc-commond-intro/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/a-tc-commond-intro/">&lt;p&gt;本文将详细解析一行复杂的 &lt;code&gt;tc&lt;/code&gt; (Traffic Control) 命令。这行命令通常用于混沌工程（Chaos Engineering）或网络模拟测试中，目的是&lt;strong&gt;在不影响其他流量的情况下，精准地对特定数据包施加延迟&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id=&quot;ming-ling-quan-mao&quot;&gt;命令全貌&lt;/h2&gt;
&lt;p&gt;为了方便理解，我们先将这行命令还原为标准的 Shell 脚本格式（假设设备为 &lt;code&gt;eth0&lt;/code&gt;，延迟为 &lt;code&gt;100ms&lt;/code&gt;，标记为 &lt;code&gt;123&lt;/code&gt;）：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 1. 创建优先队列&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; qdisc add dev eth0 root handle 1:0 prio bands&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 2. 在第4个频带添加延迟&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; qdisc add dev eth0 parent 1:4 netem delay 100ms&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 3. 添加过滤器，将标记为 123 的流量导向第4个频带&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; filter add dev eth0 parent 1:0 prio&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; protocol ip handle&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 123&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; fw flowid 1:4&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在 Go 语言项目中，它通常以字符串格式化的形式出现：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cmdString&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; :=&lt;/span&gt;&lt;span&gt; fmt&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Sprintf&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(`&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;tc qdisc add dev &lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;%s&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; root handle 1:0 prio bands 4 &amp;amp;&amp;amp;\&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;            tc qdisc add dev &lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;%s&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; parent 1:4 netem delay &lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;%s&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;ms &amp;amp;&amp;amp;\&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;            tc filter add dev &lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;%s&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; parent 1:0 prio 4 protocol ip handle &lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;%s&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; fw flowid 1:4&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;`,&lt;/span&gt;&lt;span&gt; dev&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; dev&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; delayTime&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; dev&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; mark&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;he-xin-mu-biao&quot;&gt;核心目标&lt;/h2&gt;
&lt;p&gt;这组命令的&lt;strong&gt;核心目标&lt;/strong&gt;是：&lt;strong&gt;在指定的网络设备（如 &lt;code&gt;eth0&lt;/code&gt;）上，仅对携带特定防火墙标记（fwmark）的数据包施加延迟，而让其他数据包保持原有的转发速度。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;它利用 &lt;code&gt;iptables&lt;/code&gt; 打标和 &lt;code&gt;tc&lt;/code&gt; 分流的配合来实现这一精确控制。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;ming-ling-chai-jie-fen-xi&quot;&gt;命令拆解分析&lt;/h2&gt;
&lt;p&gt;这行长命令实际上是由三个独立的 &lt;code&gt;tc&lt;/code&gt; 子命令通过 &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; 连接而成的。我们逐一拆解：&lt;/p&gt;
&lt;h3 id=&quot;1-jian-li-fen-liu-shu-niu-prio-diao-du-qi&quot;&gt;1. 建立分流枢纽：&lt;code&gt;prio&lt;/code&gt; 调度器&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; qdisc add dev %s root handle 1:0 prio bands&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 4&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;tc qdisc add&lt;/code&gt;&lt;/strong&gt;: 添加一个队列规则（Queueing Discipline）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;dev %s&lt;/code&gt;&lt;/strong&gt;: 指定操作的网卡设备。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;root&lt;/code&gt;&lt;/strong&gt;: 挂载到根节点，接管该设备的所有出口流量。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;handle 1:0&lt;/code&gt;&lt;/strong&gt;: 给这个规则分配句柄 ID &lt;code&gt;1:0&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;prio bands 4&lt;/code&gt;&lt;/strong&gt;: 使用 &lt;code&gt;prio&lt;/code&gt;（优先级）调度器，并创建 4 个频道（bands，编号 0-3）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;作用&lt;/strong&gt;：在网卡出口建立一个拥有 4 条车道的“交通枢纽”。默认情况下，流量会根据优先级进入不同的车道，但我们稍后会强制指定某些流量的去向。&lt;/p&gt;
&lt;h3 id=&quot;2-zhi-zao-yong-du-lu-duan-netem-yan-chi-dui-lie&quot;&gt;2. 制造拥堵路段：&lt;code&gt;netem&lt;/code&gt; 延迟队列&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; qdisc add dev %s parent 1:4 netem delay %sms&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;parent 1:4&lt;/code&gt;&lt;/strong&gt;: 关键点！将新规则挂载到刚才 &lt;code&gt;prio&lt;/code&gt; 调度器的第 4 个频道（Band 3，ID 为 &lt;code&gt;1:4&lt;/code&gt;）上。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;netem delay %sms&lt;/code&gt;&lt;/strong&gt;: 使用 &lt;code&gt;netem&lt;/code&gt;（网络模拟器）规则，增加 &lt;code&gt;%s&lt;/code&gt; 毫秒的延迟。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;作用&lt;/strong&gt;：将第 4 条车道改造成“拥堵路段”。任何进入这条车道的数据包，都必须等待指定时间才能通过。&lt;/p&gt;
&lt;h3 id=&quot;3-she-zhi-jiao-tong-jing-cha-filter-guo-lu-qi&quot;&gt;3. 设置交通警察：&lt;code&gt;filter&lt;/code&gt; 过滤器&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; filter add dev %s parent 1:0 prio&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; protocol ip handle %s fw flowid 1:4&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;parent 1:0&lt;/code&gt;&lt;/strong&gt;: 过滤器挂载在主枢纽 &lt;code&gt;1:0&lt;/code&gt; 上。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;protocol ip&lt;/code&gt;&lt;/strong&gt;: 仅处理 IP 协议包。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;handle %s fw&lt;/code&gt;&lt;/strong&gt;: 匹配规则。&lt;code&gt;fw&lt;/code&gt; 代表根据防火墙标记（Firewall Mark）匹配，&lt;code&gt;%s&lt;/code&gt; 是具体的标记值（如 &lt;code&gt;123&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;flowid 1:4&lt;/code&gt;&lt;/strong&gt;: 动作。匹配中的数据包被强制导向 ID 为 &lt;code&gt;1:4&lt;/code&gt; 的队列（即我们的延迟队列）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;作用&lt;/strong&gt;：在枢纽入口设置“交警”。交警检查数据包的标记，如果发现标记匹配，就强制指挥该数据包走第 4 条“拥堵车道”。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;wan-zheng-gong-zuo-liu&quot;&gt;完整工作流&lt;/h2&gt;
&lt;p&gt;要让这套机制生效，还需要 &lt;code&gt;iptables&lt;/code&gt; 的配合。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;打标 (&lt;code&gt;iptables&lt;/code&gt;)&lt;/strong&gt;:
在数据包离开机器前，用 &lt;code&gt;iptables&lt;/code&gt; 给特定流量打上标记。例如，给发往 80 端口的 TCP 包打上标记 &lt;code&gt;123&lt;/code&gt;：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -t mangle -A OUTPUT -p tcp --dport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 80&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -j MARK --set-mark&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 123&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;分流 (&lt;code&gt;tc&lt;/code&gt;)&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;普通流量&lt;/strong&gt;：没有标记 &lt;code&gt;123&lt;/code&gt;，经过 &lt;code&gt;prio&lt;/code&gt; 调度器时，按默认策略（通常走 Band 1 或 Band 2），&lt;strong&gt;无额外延迟&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;目标流量&lt;/strong&gt;：带有标记 &lt;code&gt;123&lt;/code&gt;，被过滤器捕获，强制送入 Band 3 (&lt;code&gt;1:4&lt;/code&gt;)，经过 &lt;code&gt;netem&lt;/code&gt; 增加延迟，&lt;strong&gt;实现慢速传输&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;qian-zai-feng-xian-yu-fu-zuo-yong&quot;&gt;潜在风险与副作用&lt;/h2&gt;
&lt;p&gt;这是一个经常被忽视但至关重要的问题：&lt;strong&gt;这组命令会影响其他未被标记的流量吗？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;答案是肯定的。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;当你执行 &lt;code&gt;tc qdisc add dev eth0 root ...&lt;/code&gt; 时，你&lt;strong&gt;替换了&lt;/strong&gt;网卡默认的队列调度器（通常是 &lt;code&gt;fq_codel&lt;/code&gt; 或 &lt;code&gt;pfifo_fast&lt;/code&gt;）。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;默认调度器 (&lt;code&gt;fq_codel&lt;/code&gt;)&lt;/strong&gt;：非常智能，能保证不同连接间的公平性，有效抑制缓冲区膨胀。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;当前调度器 (&lt;code&gt;prio&lt;/code&gt;)&lt;/strong&gt;：简单的优先级调度。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;后果&lt;/strong&gt;：
未被标记的普通流量虽然不会经过延迟队列，但它们现在由 &lt;code&gt;prio&lt;/code&gt; 调度器管理。这意味着它们失去了 &lt;code&gt;fq_codel&lt;/code&gt; 提供的公平性保障。在高负载下，某些流量可能会“饿死”其他流量，或者整体网络抖动变大。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;结论&lt;/strong&gt;：此方案非常适合&lt;strong&gt;测试环境&lt;/strong&gt;或&lt;strong&gt;故障模拟&lt;/strong&gt;，但在生产环境长期运行时需谨慎评估对整体网络模型的影响。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;jin-jie-tan-tao-guan-yu-bands-shu-liang-de-xuan-ze&quot;&gt;进阶探讨：关于 Bands 数量的选择&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;疑问&lt;/strong&gt;：如果我们将 &lt;code&gt;bands 4&lt;/code&gt; 改为 &lt;code&gt;bands 64&lt;/code&gt;，是否能获得更精细的控制？&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;回答&lt;/strong&gt;：技术上可行，但通常&lt;strong&gt;没有必要&lt;/strong&gt;，甚至会增加维护成本。&lt;/p&gt;
&lt;p&gt;简单来说，&lt;strong&gt;你会成功创建一个拥有 64 个优先级队列的调度器，但默认情况下，其中绝大多数队列将是空的，不会被系统自动使用。&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;1-ji-shu-yuan-li&quot;&gt;1. 技术原理&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;prio&lt;/code&gt; 调度器根据数据包的优先级将其分类到不同的 band 中。默认情况下，这个“优先级”来自于 IP 头中的 &lt;strong&gt;&lt;code&gt;TOS&lt;/code&gt; (Type of Service) 字段&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;Linux 内核内置的 &lt;code&gt;priomap&lt;/code&gt; 映射表非常简单，它只有效地使用了少数几个 band（通常是 Band 0, 1, 2）。&lt;/p&gt;
&lt;h3 id=&quot;2-shi-ji-xing-wei&quot;&gt;2. 实际行为&lt;/h3&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;TOS 值 (含义)&lt;/th&gt;&lt;th style=&quot;text-align: left&quot;&gt;对应的 Band (索引)&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;code&gt;0x10&lt;/code&gt; (最小延迟, SSH)&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;1&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;code&gt;0x08&lt;/code&gt; (最大吞吐, FTP)&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;2&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;&lt;code&gt;0x00&lt;/code&gt; (普通服务, HTTP)&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;2&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;结论&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;绝大多数普通流量&lt;/strong&gt;（TOS 为 0）都会自动进入 &lt;strong&gt;Band 2&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;如果你创建了 64 个 band，&lt;strong&gt;Band 3 到 Band 63 将会是完全空的&lt;/strong&gt;，除非你手动为每一个 band 添加过滤器规则。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;3-wei-shen-me-bu-tui-jian-bands-64&quot;&gt;3. 为什么不推荐 Bands 64？&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;资源浪费&lt;/strong&gt;：创建大量未使用的队列。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;配置复杂&lt;/strong&gt;：要想利用这些队列，你需要维护海量的 &lt;code&gt;tc filter&lt;/code&gt; 规则。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;替代方案&lt;/strong&gt;：在需要复杂 QoS 的场景下（如 ISP 或数据中心），通常会使用更高级的 &lt;strong&gt;&lt;code&gt;HTB&lt;/code&gt; (Hierarchical Token Bucket)&lt;/strong&gt; 调度器，而不是简单的 &lt;code&gt;prio&lt;/code&gt;。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;对于本文的目标——&lt;strong&gt;隔离特定流量&lt;/strong&gt;——使用默认的 &lt;code&gt;bands 3&lt;/code&gt; 或 &lt;code&gt;bands 4&lt;/code&gt; 已经绰绰有余：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Band 0-2&lt;/strong&gt;: 处理系统默认流量。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Band 3&lt;/strong&gt;: 专用作延迟队列。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;qing-li-yu-huan-yuan&quot;&gt;清理与还原&lt;/h2&gt;
&lt;p&gt;测试完成后，务必清理规则，恢复网络原状。&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 1. 清理 tc 规则 (删除 root qdisc 会自动清除所有子 qdisc 和 filter)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; qdisc del dev eth0 root&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 2. 清理 iptables 规则 (确保与添加时的参数一致，将 -A 换成 -D)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 例如：&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -t mangle -D OUTPUT -p tcp --dport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 80&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -j MARK --set-mark&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 123&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content>
        
    </entry>
    <entry xml:lang="en">
        <title>大模型提示词工程：从入门到精通</title>
        <published>2025-11-13T00:00:00+00:00</published>
        <updated>2025-11-13T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/prompt-engineering-from-entry-to-master/"/>
        <id>https://scp.net.cn/blog/prompt-engineering-from-entry-to-master/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/prompt-engineering-from-entry-to-master/">&lt;p&gt;大语言模型（LLM）已成为通用智能应用的核心能力。从软件开发到知识管理、从教育到企业流程自动化，LLM 的价值往往取决于人与模型的“对话界面”质量——&lt;strong&gt;提示词（Prompt）&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;提示词工程（Prompt Engineering）就是围绕这一界面进行系统化设计、编排、优化与评估的技术与方法论。本文将以体系化的方式，带你从零开始掌握这项核心技能。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;di-yi-bu-fen-he-xin-gai-nian-yu-ji-zhi&quot;&gt;第一部分：核心概念与机制&lt;/h2&gt;
&lt;h3 id=&quot;shen-me-shi-ti-shi-ci&quot;&gt;什么是提示词？&lt;/h3&gt;
&lt;p&gt;提示词是&lt;strong&gt;赋予模型任务与边界的指令&lt;/strong&gt;。它不仅是简单的问题，更是包含角色设定、目标描述、输入数据、约束条件、输出格式与评估标准的完整上下文。&lt;/p&gt;
&lt;h3 id=&quot;zuo-yong-ji-zhi&quot;&gt;作用机制&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;引导（Guidance）&lt;/strong&gt;：明确任务目标、范围与风格，降低模型自由度，减少跑偏。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;结构化（Structuring）&lt;/strong&gt;：通过分步骤或模块化描述任务，提升可解释性与稳定性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;约束（Constraint）&lt;/strong&gt;：通过输出格式、长度限制、成文风格等约束提升一致性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;上下文供给（Context）&lt;/strong&gt;：输入必要背景、术语定义、数据片段或检索知识，提高准确性。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;tong-yong-ti-shi-ci-gu-jia-the-framework&quot;&gt;通用提示词骨架 (The Framework)&lt;/h3&gt;
&lt;p&gt;一个高质量的提示词通常包含以下要素（可按需裁剪）：&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;要素&lt;/th&gt;&lt;th style=&quot;text-align: left&quot;&gt;说明&lt;/th&gt;&lt;th style=&quot;text-align: left&quot;&gt;示例&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Role (角色)&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;指定模型身份&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;“你是资深 Java 架构师…”&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Goal (目标)&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;明确产出指标&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;“审查代码并提出性能优化建议…”&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Context (背景)&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;提供必要信息&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;“这段代码运行在高并发场景下…”&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Input (输入)&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;待处理的数据&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;(代码片段 / 文本 / 问题)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Steps (步骤)&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;过程与思维链&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;“1. 分析复杂度; 2. 识别瓶颈; 3. 给出方案”&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Constraints (约束)&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;风格与边界&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;“不改变原有逻辑，仅优化性能，使用中文回答”&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Output (输出)&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;格式协议&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;“Markdown 列表” 或 &lt;code&gt;JSON&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;di-er-bu-fen-ru-men-ji-qiao-qing-xi-yu-gui-fan&quot;&gt;第二部分：入门技巧 —— 清晰与规范&lt;/h2&gt;
&lt;p&gt;入门阶段的核心是&lt;strong&gt;把话说明白&lt;/strong&gt;。模糊的指令产生模糊的结果，清晰的指令产生高质量的结果。&lt;/p&gt;
&lt;h3 id=&quot;1-jie-gou-hua-biao-da&quot;&gt;1. 结构化表达&lt;/h3&gt;
&lt;p&gt;使用分隔符（如 &lt;code&gt;```&lt;/code&gt;, &lt;code&gt;###&lt;/code&gt;, &lt;code&gt;&amp;lt;&amp;lt;&amp;lt; &amp;gt;&amp;gt;&amp;gt;&lt;/code&gt;）区分指令、上下文和用户输入，防止模型混淆。&lt;/p&gt;
&lt;h3 id=&quot;2-shu-chu-yue-shu&quot;&gt;2. 输出约束&lt;/h3&gt;
&lt;p&gt;明确指定输出的格式，便于后续处理（程序读取或人工阅读）。&lt;/p&gt;
&lt;h4 id=&quot;white-check-mark-shi-li-ji-chu-zhai-yao-sheng-cheng&quot;&gt;✅ 示例：基础摘要生成&lt;/h4&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Role&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;你是资深技术编辑，擅长将长文压缩为要点。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Goal&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;从输入文章中提取 5 条关键要点和 1 段摘要。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Constraints&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; 要点每条不超过 20 字&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; 摘要 120–180 字&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; 风格客观、中性、严谨&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; 输出为标准 JSON 格式&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Output Format&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &amp;quot;bullets&amp;quot;: [&amp;quot;要点1&amp;quot;, &amp;quot;要点2&amp;quot;, ...],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &amp;quot;summary&amp;quot;: &amp;quot;摘要内容...&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Input Text&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;ARTICLE&amp;gt;&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(在此处粘贴文章原文...)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;ARTICLE_END&amp;gt;&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;di-san-bu-fen-jin-jie-ji-shu-tui-li-yu-you-dao&quot;&gt;第三部分：进阶技术 —— 推理与诱导&lt;/h2&gt;
&lt;p&gt;当任务复杂度提升，简单的指令往往不够用。我们需要引入更高级的策略来引导模型进行深层思考。&lt;/p&gt;
&lt;h3 id=&quot;1-si-wei-lian-chain-of-thought-cot&quot;&gt;1. 思维链 (Chain-of-Thought, CoT)&lt;/h3&gt;
&lt;p&gt;要求模型在给出最终答案前，先展示推理过程。这能显著提升数学计算、逻辑推理和复杂分析任务的准确率。&lt;/p&gt;
&lt;h4 id=&quot;white-check-mark-shi-li-luo-ji-tui-li&quot;&gt;✅ 示例：逻辑推理&lt;/h4&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Task&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;解决下面的逻辑问题。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Instructions&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;请逐步推理（Let&amp;#39;s think step by step），先列出已知条件，推导中间结论，最后给出答案。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Question&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;甲乙丙三人，甲比乙大，丙比甲小。请问谁最小？&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Output Format&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;推理过程：...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;最终答案：...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;2-shao-yang-ben-xue-xi-few-shot-prompting&quot;&gt;2. 少样本学习 (Few-Shot Prompting)&lt;/h3&gt;
&lt;p&gt;通过提供 2-5 个高质量的“输入-输出”示例，让模型快速通过类比学习任务的模式、风格和边界。&lt;/p&gt;
&lt;h4 id=&quot;white-check-mark-shi-li-qing-gan-fen-xi-yu-gui-yin&quot;&gt;✅ 示例：情感分析与归因&lt;/h4&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Task&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;对用户评论进行情感分类，并提取原因。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Examples&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;输入：这家店服务很好，价格也合理。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;输出：{&amp;quot;label&amp;quot;: &amp;quot;positive&amp;quot;, &amp;quot;reason&amp;quot;: &amp;quot;服务好，价格合理&amp;quot;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;输入：等了很久才上菜，味道一般，而且很咸。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;输出：{&amp;quot;label&amp;quot;: &amp;quot;negative&amp;quot;, &amp;quot;reason&amp;quot;: &amp;quot;上菜慢，口味差&amp;quot;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Current Input&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;输入：虽然快递有点慢，但东西质量确实不错，超值。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;输出：&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;3-zhi-ding-tui-li-lu-jing-structured-reasoning&quot;&gt;3. 指定推理路径 (Structured Reasoning)&lt;/h3&gt;
&lt;p&gt;不仅仅是让模型“思考”，而是规定它“如何思考”。&lt;/p&gt;
&lt;h4 id=&quot;white-check-mark-shi-li-chan-pin-xu-qiu-ping-shen&quot;&gt;✅ 示例：产品需求评审&lt;/h4&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Context&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;你是一名产品经理，正在评审新的需求文档。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Steps&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;1.&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;font-weight: bold;&quot;&gt; **&lt;/span&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;完整性检查&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;font-weight: bold;&quot;&gt;**&lt;/span&gt;&lt;span&gt;：检查是否缺少用户角色、前置条件或异常流程。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;2.&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;font-weight: bold;&quot;&gt; **&lt;/span&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;风险评估&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;font-weight: bold;&quot;&gt;**&lt;/span&gt;&lt;span&gt;：指出可能得性能风险或安全隐患。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;3.&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;font-weight: bold;&quot;&gt; **&lt;/span&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;可测性分析&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;font-weight: bold;&quot;&gt;**&lt;/span&gt;&lt;span&gt;：判断需求是否具备明确的验收标准。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;4.&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;font-weight: bold;&quot;&gt; **&lt;/span&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;建议&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;font-weight: bold;&quot;&gt;**&lt;/span&gt;&lt;span&gt;：基于以上分析，给出修改建议。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Input&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(需求文档内容...)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;di-si-bu-fen-jing-tong-zhi-nan-dai-li-yu-gong-cheng-hua&quot;&gt;第四部分：精通指南 —— 代理与工程化&lt;/h2&gt;
&lt;p&gt;在生产环境中，提示词往往不是孤立存在的，而是与代码、工具和数据流结合在一起。&lt;/p&gt;
&lt;h3 id=&quot;1-rag-jian-suo-zeng-qiang-sheng-cheng&quot;&gt;1. RAG (检索增强生成)&lt;/h3&gt;
&lt;p&gt;解决模型“幻觉”和知识过时的核心手段。
&lt;strong&gt;模式&lt;/strong&gt;：Query -&amp;gt; Search -&amp;gt; Retrieve Context -&amp;gt; &lt;strong&gt;Prompt with Context&lt;/strong&gt; -&amp;gt; Generation&lt;/p&gt;
&lt;h4 id=&quot;white-check-mark-shi-li-ji-yu-wen-dang-de-wen-da&quot;&gt;✅ 示例：基于文档的问答&lt;/h4&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Role&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;你是严谨的技术顾问。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Constraints&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; 仅依据提供的[Document Chunks]回答问题。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; 如果文中未提及，直接回答“无法确定”，严禁编造。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; 引用来源，格式为 &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;doc_id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span&gt;。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Document Chunks&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;doc1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span&gt; Kubernetes 是一个开源容器编排引擎...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;doc2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span&gt; Pod 是 Kubernetes 中最小的部署单元...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Question&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Pod 和 Node 有什么关系？&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;2-han-shu-diao-yong-tool-use-function-calling&quot;&gt;2. 函数调用 (Tool Use / Function Calling)&lt;/h3&gt;
&lt;p&gt;将大模型作为路由和参数提取器，连接外部世界（API、数据库）。&lt;/p&gt;
&lt;h4 id=&quot;white-check-mark-shi-li-hui-lu-cha-xun-yi-tu-shi-bie&quot;&gt;✅ 示例：汇率查询意图识别&lt;/h4&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Tools&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;你可以调用以下函数：&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;-&lt;/span&gt;&lt;span&gt; get_exchange_rate(base_currency, target_currency)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Task&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;判断用户意图，如果涉及汇率查询，输出对应的函数调用 JSON；否则直接回答。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; User Input&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;现在 100 美元能换多少人民币？&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Output&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&amp;quot;tool&amp;quot;: &amp;quot;get_exchange_rate&amp;quot;, &amp;quot;args&amp;quot;: {&amp;quot;base_currency&amp;quot;: &amp;quot;USD&amp;quot;, &amp;quot;target_currency&amp;quot;: &amp;quot;CNY&amp;quot;}}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;3-die-dai-yu-zi-sheng-self-correction&quot;&gt;3. 迭代与自省 (Self-Correction)&lt;/h3&gt;
&lt;p&gt;让模型自己充当“评审员”，检查初稿并进行修正。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;模式&lt;/strong&gt;：Draft -&amp;gt; Critique -&amp;gt; Refine&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;di-wu-bu-fen-ping-gu-yu-mo-xing-can-shu&quot;&gt;第五部分：评估与模型参数&lt;/h2&gt;
&lt;p&gt;提示词工程不仅仅是写 prompt，还包括评估和调优。&lt;/p&gt;
&lt;h3 id=&quot;1-ping-gu-wei-du&quot;&gt;1. 评估维度&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;正确性&lt;/strong&gt;：事实是否准确，逻辑是否闭环。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;一致性&lt;/strong&gt;：相同输入下，输出格式和风格是否稳定。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;鲁棒性&lt;/strong&gt;：面对恶意输入或噪声数据的表现。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;效率&lt;/strong&gt;：Token 消耗与响应延迟。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;2-guan-jian-tui-li-can-shu-inference-parameters&quot;&gt;2. 关键推理参数 (Inference Parameters)&lt;/h3&gt;
&lt;p&gt;这些参数决定了模型的“性格”。&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;参数&lt;/th&gt;&lt;th style=&quot;text-align: left&quot;&gt;推荐值&lt;/th&gt;&lt;th style=&quot;text-align: left&quot;&gt;说明&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;code&gt;temperature&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;code&gt;0.0 - 0.3&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;严谨任务&lt;/strong&gt;（代码、抽取）。输出确定性高。&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;code&gt;0.7 - 1.0&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;创意任务&lt;/strong&gt;（写作、聊天）。输出多样性高。&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;code&gt;top_p&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;code&gt;1.0&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;通常与 Temperature 二选一调节。&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;code&gt;max_tokens&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;按需&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;防止输出过长或死循环，控制成本。&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;code&gt;stop&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;code&gt;[&quot;\n\n&quot;, &quot;```&quot;]&lt;/code&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;结构化输出神器&lt;/strong&gt;。遇到指定字符强制停止。&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;fu-lu-mo-xing-xun-lian-yu-wei-diao-ji-chu-context&quot;&gt;附录：模型训练与微调基础 (Context)&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;注：本节适用于需要进行模型微调（Fine-tuning）的进阶读者，普通提示词工程可跳过。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;如果你发现 Prompt 无法满足需求，可能需要考虑微调。以下是关键概念：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Learning Rate (学习率)&lt;/strong&gt;: 决定模型学习的步伐。微调时通常比预训练小得多（如 &lt;code&gt;1e-5&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Epochs (轮次)&lt;/strong&gt;: 数据集训练的遍数。微调通常只需 3-5 轮，过多会导致过拟合（遗忘通用能力）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Batch Size (批次大小)&lt;/strong&gt;: 影响显存占用和收敛稳定性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Optimizer&lt;/strong&gt;: 推荐 &lt;code&gt;AdamW&lt;/code&gt;，搭配 &lt;code&gt;Cosine&lt;/code&gt; 学习率调度。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;zong-jie&quot;&gt;总结&lt;/h2&gt;
&lt;p&gt;提示词工程是从“自然语言”到“机器指令”的翻译艺术。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;入门&lt;/strong&gt;：掌握结构化骨架，把任务说清楚。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;进阶&lt;/strong&gt;：用 CoT 和 Few-Shot 激发模型潜能。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;精通&lt;/strong&gt;：结合 RAG、工具调用和自动化评估，构建鲁棒的 AI 应用。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;em&gt;参考资源：&lt;a rel=&quot;external&quot; href=&quot;https://www.promptingguide.ai/&quot;&gt;Prompt Engineering Guide (dair-ai)&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Wireshark 深度解析：macOS 网络抓包与分析实战指南（含案例与过滤器）</title>
        <published>2025-11-13T00:00:00+00:00</published>
        <updated>2025-11-13T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/wireshark-macos-deep-dive/"/>
        <id>https://scp.net.cn/blog/wireshark-macos-deep-dive/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/wireshark-macos-deep-dive/">&lt;h3 id=&quot;gai-lan&quot;&gt;概览&lt;/h3&gt;
&lt;p&gt;Wireshark 是一款跨平台的网络协议分析器，用于捕获和解析网络数据包。在 macOS 环境中，它通过底层的 &lt;code&gt;dumpcap&lt;/code&gt; 组件负责数据抓取，Wireshark GUI/TShark 负责展示与分析。本指南提炼自项目内部教程并结合官方文档，围绕“抓包设置—过滤配置—分析工作流—实战案例”构建一套可落地的方法论，面向初学者与资深工程师均可读。&lt;/p&gt;
&lt;h3 id=&quot;he-xin-gong-neng-yu-macos-ying-yong-chang-jing&quot;&gt;核心功能与 macOS 应用场景&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;实时捕获与离线分析：接口选择、滚动抓包、保存为 &lt;code&gt;pcap/pcapng&lt;/code&gt;、离线复盘。&lt;/li&gt;
&lt;li&gt;协议深入解析：数百种协议（HTTP/HTTP2、TLS、DNS、TCP/UDP、ARP 等）分层展示与字段级过滤。&lt;/li&gt;
&lt;li&gt;强力过滤：捕获过滤（BPF）减少数据量；显示过滤（Wireshark 语法）精准定位问题流。&lt;/li&gt;
&lt;li&gt;工作流工具：Follow Stream、Expert Information、Conversations/Endpoints、I/O Graph、Statistics 汇总。&lt;/li&gt;
&lt;li&gt;macOS 特性：以非管理员身份运行 GUI，通过 &lt;code&gt;dumpcap&lt;/code&gt; 获取必要权限，减少高权限代码面风险。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;an-zhuang-yu-quan-xian-pei-zhi-macos&quot;&gt;安装与权限配置（macOS）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Homebrew 安装（推荐）：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;brew install --cask wireshark&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;官网 DMG：
&lt;ul&gt;
&lt;li&gt;访问 &lt;code&gt;https://www.wireshark.org/download.html&lt;/code&gt; 下载并安装。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;MacPorts：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;sudo port install wireshark&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;权限说明（抓包需特权）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;尽量避免以管理员权限运行完整 GUI；仅让 &lt;code&gt;dumpcap&lt;/code&gt; 具备抓包权限。不同安装路径中 &lt;code&gt;dumpcap&lt;/code&gt; 位置可能为 &lt;code&gt;/Applications/Wireshark.app/...&lt;/code&gt;、&lt;code&gt;/usr/local/bin&lt;/code&gt; 或 &lt;code&gt;/opt/homebrew/bin&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;如果无法抓包，可临时使用管理员运行或为 &lt;code&gt;dumpcap&lt;/code&gt; 配置权限（谨慎）：
&lt;ul&gt;
&lt;li&gt;运行时管理员：&lt;code&gt;sudo wireshark&lt;/code&gt;（不推荐，存在安全风险，官方不建议以 root 运行全部代码）&lt;/li&gt;
&lt;li&gt;设置 &lt;code&gt;dumpcap&lt;/code&gt; 特权（按官方文档原则，仅赋予抓包最小权限；路径因安装不同而异）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;参考：Wireshark 官方“Capture Privileges”与“Binary Packaging”文档（见文末引用）。&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;安全提示：所有需要提升权限的功能集中在 &lt;code&gt;dumpcap&lt;/code&gt;，不要让 Wireshark/TShark 以管理员身份常态运行。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;shi-shi-shi-li-zhua-bao-she-zhi&quot;&gt;实施示例：抓包设置&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;选择接口
&lt;ul&gt;
&lt;li&gt;打开 Wireshark，选择有流量的接口（以太网、Wi-Fi、VPN 虚拟接口）。&lt;/li&gt;
&lt;li&gt;验证接口：&lt;code&gt;ifconfig -a&lt;/code&gt; 或在界面“Interface List”观察数据速率。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Capture Options 配置
&lt;ul&gt;
&lt;li&gt;缓冲区大小、滚动写入（文件轮换）、是否启用混杂模式。&lt;/li&gt;
&lt;li&gt;可设置捕获过滤器（BPF），示例见下节。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;开始与停止
&lt;ul&gt;
&lt;li&gt;点击 &lt;code&gt;Start&lt;/code&gt; 开始；工具栏 &lt;code&gt;Stop&lt;/code&gt; 或菜单 Capture → Stop 结束。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;保存与回放
&lt;ul&gt;
&lt;li&gt;File → Save As，格式：&lt;code&gt;.pcap&lt;/code&gt;/&lt;code&gt;.pcapng&lt;/code&gt;。支持 &lt;code&gt;capinfos&lt;/code&gt; 查看摘要、&lt;code&gt;editcap&lt;/code&gt; 分割合并。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;命令行等价（TShark）：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 以接口 en0 抓取 HTTP（80）并写入文件&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tshark&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -i en0 -f&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;tcp port 80&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -w http.pcapng&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 统计文件信息&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;capinfos&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; http.pcapng&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 转换格式/切分文件&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;editcap&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -F pcapng http.pcapng http-split.pcapng&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;guo-lu-qi-pei-zhi-ji-qiao&quot;&gt;过滤器配置技巧&lt;/h3&gt;
&lt;p&gt;捕获过滤（BPF，减少采集数据量）：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 仅抓 HTTP&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tcp&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; port&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 80&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 仅抓 HTTPS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tcp&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; port&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 443&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 仅抓来源/目的为特定 IP&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;host&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 192.168.1.100&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 端口范围&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tcp&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; portrange 8000-8080&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 排除本机环回&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;not&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; host&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 127.0.0.1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 组合条件&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;host&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 192.168.1.1&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; and tcp port&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 80&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;显示过滤（Wireshark 语法，捕获后精准定位）：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 协议过滤&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;http&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;dns&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tls&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tcp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 字段过滤&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tcp.port&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 80&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;ip.addr&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 192.168.1.100&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;http.host&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; contains&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;api&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;http.request.method&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;POST&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# TLS 握手与 SNI&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tls.handshake&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tls.handshake.extensions_server_name&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; contains&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;example.com&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# TCP 握手与问题排查&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tcp.flags.syn&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; and tcp.flags.ack ==&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tcp.analysis.retransmission&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tcp.analysis.rtt&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# DNS 查询与记录类型&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;dns&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;dns.qry.name&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;www.example.com&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;dns.qry.type&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  # A&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;dns.qry.type&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 5&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  # CNAME&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;fen-xi-gong-zuo-liu-xiao-lu-ti-sheng&quot;&gt;分析工作流（效率提升）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Follow Stream：右键 → Follow → TCP/HTTP Stream，串联完整会话，适合请求/响应核对。&lt;/li&gt;
&lt;li&gt;Expert Information：Analyze → Expert Information，快速定位错误/警告（重传、握手异常、协议违规）。&lt;/li&gt;
&lt;li&gt;Statistics：
&lt;ul&gt;
&lt;li&gt;Protocol Hierarchy：各协议占比与层级结构。&lt;/li&gt;
&lt;li&gt;Conversations/Endpoints：流会话数量、字节与包统计，定位热点连接与“大流”。&lt;/li&gt;
&lt;li&gt;I/O Graph：随时间的吞吐趋势，观察峰值与抖动。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Coloring Rules：为关键协议/状态着色，提升视觉识别效率。&lt;/li&gt;
&lt;li&gt;时间列与时间基准：View → Time Display Format 选择相对/绝对时间，提高时序分析能力。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;shi-zhan-an-li-cong-wen-ti-dao-jie-lun&quot;&gt;实战案例：从问题到结论&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;排查网络连接故障（DNS 与 TCP 握手）&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;现象：应用无法访问目标域名或连接超时。&lt;/li&gt;
&lt;li&gt;步骤：
&lt;ul&gt;
&lt;li&gt;过滤 &lt;code&gt;dns&lt;/code&gt;，检查查询/响应与 &lt;code&gt;Response Code&lt;/code&gt;；定位是否 NXDOMAIN/超时。&lt;/li&gt;
&lt;li&gt;若 DNS 正常：过滤 TCP 三次握手 &lt;code&gt;tcp.flags.syn == 1 and tcp.flags.ack == 0&lt;/code&gt;，观察是否无 ACK 或重传。&lt;/li&gt;
&lt;li&gt;查看 &lt;code&gt;tcp.analysis.retransmission&lt;/code&gt; 与 &lt;code&gt;tcp.analysis.rtt&lt;/code&gt;，判断链路质量。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;结论示例：DNS 解析失败导致连接不可达；或服务器无响应引发握手失败。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;安全事件分析（异常出站与可疑域名）&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;现象：主机向未知域名/地址持续连接，或可疑 POST 上传。&lt;/li&gt;
&lt;li&gt;步骤：
&lt;ul&gt;
&lt;li&gt;过滤 &lt;code&gt;tls.handshake.extensions_server_name&lt;/code&gt;，发现非常规 SNI 或子域名；核对白名单。&lt;/li&gt;
&lt;li&gt;过滤 &lt;code&gt;http.request.method == &quot;POST&quot; and http.host contains &quot;upload&quot;&lt;/code&gt;，检查是否外泄行为。&lt;/li&gt;
&lt;li&gt;汇总出站端点：Statistics → Endpoints，锁定异常目标与端口。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;结论示例：发现指向外部的异常 SNI 连接，需配合日志与威胁情报进一步处置。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;应用性能监控（TCP/HTTP 时延与吞吐）&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;现象：页面加载慢或 API 响应抖动。&lt;/li&gt;
&lt;li&gt;步骤：
&lt;ul&gt;
&lt;li&gt;使用 &lt;code&gt;tcp.analysis.rtt&lt;/code&gt; 评估往返时延，定位高 RTT 会话。&lt;/li&gt;
&lt;li&gt;I/O Graph 观察带宽使用与峰值，识别抖动时段。&lt;/li&gt;
&lt;li&gt;Follow HTTP Stream 分析头部与响应时间，结合 &lt;code&gt;http.time&lt;/code&gt;（若提供）与服务器日志。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;结论示例：链路端拥塞导致 RTT 上升；或后端响应慢导致整体耗时增加。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;ke-shi-hua-yu-shi-li-su-cai&quot;&gt;可视化与示例素材&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;界面截图建议：
&lt;ul&gt;
&lt;li&gt;主界面（接口列表、过滤器栏、数据包列表、协议树、字节视图）。&lt;/li&gt;
&lt;li&gt;Follow Stream、Expert Information、I/O Graph、Conversations 视图。&lt;/li&gt;
&lt;li&gt;建议将截图置于 &lt;code&gt;static/images/wireshark/&lt;/code&gt;，示例路径：&lt;code&gt;/images/wireshark/interface-list.png&lt;/code&gt;、&lt;code&gt;/images/wireshark/io-graph.png&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;数据包时序示意（示例，三次握手）：&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Client                     Network                     Server&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  SYN  ----------------------------------------------&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       &amp;lt;----------------------------------------------  SYN-ACK&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ACK  ----------------------------------------------&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      [Establish TCP connection]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;jin-jie-ji-qiao-yu-dai-ma-pian-duan&quot;&gt;进阶技巧与代码片段&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;自定义着色规则：View → Coloring Rules，突出 &lt;code&gt;tcp.analysis.retransmission&lt;/code&gt;、&lt;code&gt;http.request&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;会话级提取：用 &lt;code&gt;Follow TCP Stream&lt;/code&gt; 导出负载；或 TShark 用 &lt;code&gt;-z conv,tcp&lt;/code&gt; 输出会话统计。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 导出 HTTP 请求摘要&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tshark&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -r http.pcapng -Y&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;http.request&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -T fields -e frame.time -e ip.src -e ip.dst -e http.host -e http.request.method -e http.request.uri&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 输出 TCP 会话统计&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tshark&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -r trace.pcapng -q -z conv,tcp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;chang-jian-gu-zhang-yu-pai-chu&quot;&gt;常见故障与排除&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;无法抓包：检查 &lt;code&gt;dumpcap&lt;/code&gt; 权限与接口可见性；尝试管理员运行以验证路径问题。&lt;/li&gt;
&lt;li&gt;接口不可见：在 Wi-Fi/VPN 下确认接口名（&lt;code&gt;en0/en1&lt;/code&gt; 等），使用 &lt;code&gt;networksetup -listallhardwareports&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;文件损坏：用 &lt;code&gt;capinfos&lt;/code&gt; 检查并用 &lt;code&gt;tshark -r bad.pcapng -w fixed.pcapng&lt;/code&gt; 重新导出。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;yin-yong-yu-can-kao&quot;&gt;引用与参考&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Wireshark 官方下载与文档：https://www.wireshark.org/download.html 、https://www.wireshark.org/docs/&lt;/li&gt;
&lt;li&gt;捕获权限说明（官方 Wiki）：https://wiki.wireshark.org/CaptureSetup/CapturePrivileges&lt;/li&gt;
&lt;li&gt;二进制打包与权限原则（官方文档）：https://www.wireshark.org/docs/wsdg_html_chunked/ChSrcBinary.html&lt;/li&gt;
&lt;li&gt;显示过滤器参考（手册）：https://www.wireshark.org/docs/man-pages/wireshark-filter.html&lt;/li&gt;
&lt;li&gt;捕获过滤器说明（Wiki）：https://wiki.wireshark.org/CaptureFilters&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;注：本文技术内容提炼自内部教程文件 &lt;code&gt;.trae/documents/Wireshark_Mac_Tutorial.md&lt;/code&gt; 并补充官方参考。涉及权限设置请严格遵守最小权限与安全最佳实践。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;xing-ye-jing-dian-shi-zhan-an-li-jing-xuan&quot;&gt;行业经典实战案例（精选）&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Cloudflare：HTTP/3（QUIC）上线性能对比与抓包验证（来源：Cloudflare Blog）&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;案例背景（200-300字）：Cloudflare 在全球边缘网络率先支持 HTTP/3/QUIC，并面向真实网站与浏览器开展对比测试，评估在丢包与拥塞场景下的性能改进。传统 HTTP/2 基于 TCP，易受头阻塞影响；HTTP/3 改用 QUIC（UDP），在多流并发与丢包处理上更友好。该团队以自建 WebPageTest 节点与浏览器分析工具为基础，结合抓包与日志验证协议协商与握手路径，确保量化指标具备可复现性与工程指向性。&lt;/li&gt;
&lt;li&gt;面临的挑战：
&lt;ul&gt;
&lt;li&gt;TCP 头阻塞导致多流整体被阻塞&lt;/li&gt;
&lt;li&gt;握手耗时与 0-RTT 落地效果验证&lt;/li&gt;
&lt;li&gt;丢包与拥塞控制算法对长短流影响差异&lt;/li&gt;
&lt;li&gt;跨浏览器与全球节点一致性验证&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;解决方案（分步骤）：
&lt;ul&gt;
&lt;li&gt;在边缘网络开启 HTTP/3；为测试站点开启 Alt-Svc 广告&lt;/li&gt;
&lt;li&gt;使用 WebPageTest 跨地域加载同一页面，采集 TTFB、加载耗时&lt;/li&gt;
&lt;li&gt;抓取 QUIC/HTTP3 流量并用 Wireshark 验证协商与握手（必要时用浏览器 DevTools、qlog/qvis 辅助）&lt;/li&gt;
&lt;li&gt;调整拥塞控制（如 CUBIC）并复测对大对象与有丢包链路的影响&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;实施成果（量化+定性）：
&lt;ul&gt;
&lt;li&gt;小页面示例（15KB）：HTTP/3 平均 443ms vs HTTP/2 458ms&lt;/li&gt;
&lt;li&gt;TTFB 平均：HTTP/3 176ms vs HTTP/2 201ms，提升约 12.4%&lt;/li&gt;
&lt;li&gt;图表与示意：HoL 阻塞对比图、加载时序对比、全球节点折线图（见原文）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;经验总结（核心启示）：
&lt;ul&gt;
&lt;li&gt;使用 Wireshark/qlog 验证协议协商与握手路径，确保指标可解释&lt;/li&gt;
&lt;li&gt;结合业务对象大小与链路特性选择拥塞控制并调优&lt;/li&gt;
&lt;li&gt;在真实流量与跨地域环境下复测，避免仅实验室结论&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;原始出处：
&lt;ul&gt;
&lt;li&gt;Comparing HTTP/3 vs. HTTP/2 Performance：https://blog.cloudflare.com/http-3-vs-http-2/&lt;/li&gt;
&lt;li&gt;How to test HTTP/3 and QUIC with Firefox Nightly（含 Wireshark 验证建议）：https://blog.cloudflare.com/how-to-test-http-3-and-quic-with-firefox-nightly/&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Netflix 视频流送达行为分析（第三方测试，来源：AVNetwork）&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;案例背景（200-300字）：针对 Netflix 视频流在家庭 DSL（下行 20Mb/上行 2Mb）环境的送达特性，研究者在三层交换机镜像端口旁路接入分析设备，使用 Wireshark 捕获并分析 TCP 会话与带宽占用，评估播放器缓冲填充阶段与稳态播放阶段的带宽模式。该案例聚焦实际消费网络与主流浏览器（Windows 10 + Chrome），具备代表性与可复现性，展示了用 Conversations 与 I/O Graph 快速理解流媒体流量行为的路径。&lt;/li&gt;
&lt;li&gt;面临的挑战：
&lt;ul&gt;
&lt;li&gt;初始缓冲阶段带宽快速拉升对链路的占用&lt;/li&gt;
&lt;li&gt;持续播放阶段的吞吐稳定性与丢包敏感性&lt;/li&gt;
&lt;li&gt;识别主传输会话与端口以隔离分析&lt;/li&gt;
&lt;li&gt;家庭网络镜像/旁路抓包的可见性与准确性&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;解决方案（分步骤）：
&lt;ul&gt;
&lt;li&gt;交换机配置端口镜像，旁路接入运行 Wireshark 的分析主机&lt;/li&gt;
&lt;li&gt;用 Statistics → Conversations 锁定主 TCP 会话并过滤&lt;/li&gt;
&lt;li&gt;生成 I/O Graph，观察带宽随时间的变化与缓冲阶段行为&lt;/li&gt;
&lt;li&gt;结合 &lt;code&gt;tcp.analysis.*&lt;/code&gt; 检查重传/丢包并评估播放影响&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;实施成果（量化+定性）：
&lt;ul&gt;
&lt;li&gt;前 23 秒显著占用下行带宽以快速充填缓冲&lt;/li&gt;
&lt;li&gt;随后带宽稳定在持续播放所需水平，重传低且播放稳定&lt;/li&gt;
&lt;li&gt;图表与示意：会话表（Figure 1）、I/O Graph（Figure 2）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;经验总结（核心启示）：
&lt;ul&gt;
&lt;li&gt;用会话视角与 I/O 图表能快速刻画流媒体行为&lt;/li&gt;
&lt;li&gt;初始缓冲与稳态需求不同，应分阶段评估链路容量&lt;/li&gt;
&lt;li&gt;家庭网络抓包建议使用镜像端口/TAP 提升可见性&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;原始出处：Byte-Sized Lesson: Analyzing Netflix’s Streaming Delivery：https://www.avnetwork.com/features/byte-sized-lesson-analyzing-netflixs-streaming-delivery&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;企业防火墙集群 CPHA 同步流量导致性能问题（来源：Packt 教程示例，Cisco 集群场景）&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;案例背景（200-300字）：某企业网络出现业务抖动与高负载，使用 Wireshark 的统计工具进行分层占比分析，发现大量 Check Point 高可用集群（CPHA）同步流量与业务流混行，占据链路带宽并影响生产网络性能。该场景具有代表性：安全设备的状态同步若与业务共网段，可能生成大量管理面流量导致拥塞。&lt;/li&gt;
&lt;li&gt;面临的挑战：
&lt;ul&gt;
&lt;li&gt;CPHA 同步包占比极高，压制业务流量&lt;/li&gt;
&lt;li&gt;难以从原始包列表直接识别“谁在占带宽”&lt;/li&gt;
&lt;li&gt;抓包样本需覆盖高峰时段，避免误判&lt;/li&gt;
&lt;li&gt;调整网络架构需兼顾安全与可用性&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;解决方案（分步骤）：
&lt;ul&gt;
&lt;li&gt;使用 Statistics → Protocol Hierarchy 观察各协议占比与速率&lt;/li&gt;
&lt;li&gt;用 Conversations/Endpoints 锁定高流量会话与端点&lt;/li&gt;
&lt;li&gt;依据分析结果为防火墙集群配置专用同步链路，隔离 CPHA 流&lt;/li&gt;
&lt;li&gt;复测并验证业务网段的协议占比与吞吐回归正常&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;实施成果（量化+定性）：
&lt;ul&gt;
&lt;li&gt;示例中 CPHA 占比约 74.7%（教学示例数据），隔离后业务吞吐改善&lt;/li&gt;
&lt;li&gt;图表与示意：协议层级统计、会话/端点统计与 I/O 图表&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;经验总结（核心启示）：
&lt;ul&gt;
&lt;li&gt;先用协议层级统计识别“带宽黑洞”，再定位到具体会话&lt;/li&gt;
&lt;li&gt;安全设备同步应走独立链路，避免与生产业务混行&lt;/li&gt;
&lt;li&gt;Wireshark 统计工具可快速指导网络架构整改与复核&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;原始出处：Using statistical tools in Wireshark for packet analysis（Packt）：https://www.packtpub.com/en-us/learning/how-to-tutorials/statistical-tools-in-wireshark-for-packet-analysis&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;转载授权与版权提示：以上案例均引用公开资料用于技术学习与评述。若需转载原文图片或大段内容，请依据原站点授权政策取得许可；本文已在每个案例处标注来源链接以便审阅与取证。&lt;/p&gt;
&lt;/blockquote&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>从段永平与巴菲特最新访谈：用第一性原理提炼普世智慧</title>
        <published>2025-11-12T00:00:00+00:00</published>
        <updated>2025-11-12T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/duan-buffett-first-principles-wisdom-2025/"/>
        <id>https://scp.net.cn/blog/duan-buffett-first-principles-wisdom-2025/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/duan-buffett-first-principles-wisdom-2025/">&lt;h1 id=&quot;zhai-yao&quot;&gt;摘要&lt;/h1&gt;
&lt;p&gt;以第一性原理为骨架，从段永平（浙大见面会、2025-01-05；对话方三文、2025-11-11）与巴菲特（2025-05-03 伯克希尔股东大会问答）的最新公开访谈中，抽象出可在“投资与做事”中反复使用的通用原则。全文力求简洁可执行。&lt;/p&gt;
&lt;h1 id=&quot;di-yi-xing-yuan-li-kuang-jia&quot;&gt;第一性原理框架&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;目标导向：先问“我真正要的长期结果是什么”。&lt;/li&gt;
&lt;li&gt;因果核查：对每个决策追问“为什么”，直到原因不再依赖假设。&lt;/li&gt;
&lt;li&gt;约束识别：明确边界（能力圈、风险承受、时间与资金）。&lt;/li&gt;
&lt;li&gt;长期视角：以 5–20 年衡量正确性，允许短期噪声。&lt;/li&gt;
&lt;li&gt;简单优先：优先选择少决策、可复用的简单策略。&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;lai-zi-duan-yong-ping-de-guan-jian-yao-dian-chou-xiang&quot;&gt;来自段永平的关键要点（抽象）&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;慢即是快：好投资者做得“很慢”，不在乎错过机会，重在避雷与做对事（见浙大问答）[来源1][来源2][来源3]。&lt;/li&gt;
&lt;li&gt;风险边界：敢冒险，但只冒“能承受的风险”，不可复制的“走运”不要当策略（网易、苹果案例）[来源2][来源3]。&lt;/li&gt;
&lt;li&gt;长期主义：每个决策都看 5/10/20 年以后是否仍然正确；学习与创业同理[来源1][来源2]。&lt;/li&gt;
&lt;li&gt;能力圈与理解：对生意、文化、商业模式没有深入理解，就不会长期持有[来源2][来源3]。&lt;/li&gt;
&lt;li&gt;不为创业而创业：该创业的人不需要鼓励；若无清晰要做的事，仅为“创业而创业”成功率极低[来源2][来源3]。&lt;/li&gt;
&lt;li&gt;正直与本分：做对的事情、把事情做对；选择正直可让决策更坦然、更可持续（长期文化）[来源3][来源4]。&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;lai-zi-ba-fei-te-de-guan-jian-yao-dian-chou-xiang&quot;&gt;来自巴菲特的关键要点（抽象）&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;贸易与合作：贸易不应被当作武器；国家与企业都应做“自己最擅长的事”[来源5][来源6]。&lt;/li&gt;
&lt;li&gt;现金与耐心：持有现金为“机会准备”，真正的机会来时要快速行动[来源4][来源7]。&lt;/li&gt;
&lt;li&gt;能力圈投资：买股票就是买企业的一部分；以企业长期经济特性与资产负债表为核心[来源7]。&lt;/li&gt;
&lt;li&gt;抗噪性：市场大幅波动不改变价值评估；价格是噪声、价值是航标[来源7]。&lt;/li&gt;
&lt;li&gt;文化与传承：强文化与正确的资本配置哲学比技巧更重要；传承到阿贝尔但原则不变[来源4][来源7]。&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;10-tiao-ke-zhi-xing-de-tong-yong-zhi-hui&quot;&gt;10 条可执行的通用智慧&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;定义“长期正确”：先写下 5–20 年后的期望，倒推今日行动。&lt;/li&gt;
&lt;li&gt;只做可承受损失的试错：把最大亏损当作“学费”明确标注。&lt;/li&gt;
&lt;li&gt;立足能力圈：不懂的生意不碰；少而精地研究与持有。&lt;/li&gt;
&lt;li&gt;以资产负债表看企业：现金流与资产质量优先于噪声指标。&lt;/li&gt;
&lt;li&gt;把价格当噪声、把价值当航标：用估值与竞争优势对齐持有逻辑。&lt;/li&gt;
&lt;li&gt;预置“机会现金”：平时耐心，机会来临快决策。&lt;/li&gt;
&lt;li&gt;文化优先于技巧：选择/打造正直、长期主义的环境。&lt;/li&gt;
&lt;li&gt;少做决定、做对决定：建立可复用的简单策略与清单。&lt;/li&gt;
&lt;li&gt;风险分层与边界：明确仓位上限、集中度上限、流动性底线。&lt;/li&gt;
&lt;li&gt;不为了“创业而创业”：只有当问题与解法都清楚时再下注。&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;yi-ye-qing-dan-luo-di&quot;&gt;一页清单（落地）&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;目标：写下 3 个 10 年后的“必须成立”的结果与衡量指标。&lt;/li&gt;
&lt;li&gt;能力圈：列出 2–4 个你“持续能解释的优势行业/公司”。&lt;/li&gt;
&lt;li&gt;风险边界：三条红线（最大回撤、单一标的上限、杠杆=0）。&lt;/li&gt;
&lt;li&gt;现金与耐心：设置机会资金比例；非机会期只做阅读与跟踪。&lt;/li&gt;
&lt;li&gt;决策复盘：每次买卖写 3 条因果与假设，季度复盘改错。&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;can-kao-yu-lai-yuan&quot;&gt;参考与来源&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;[来源1] 段永平浙大见面会问答（2025-01-05）｜新浪财经：https://finance.sina.com.cn/roll/2025-01-05/doc-inecxqhr2576638.shtml&lt;/li&gt;
&lt;li&gt;[来源2] 段永平浙大交流实录（要点版）｜新浪财经：https://finance.sina.com.cn/stock/stockzmt/2025-01-06/doc-inecyfep3065663.shtml&lt;/li&gt;
&lt;li&gt;[来源3] 2025年浙大演讲整理｜知乎：https://zhuanlan.zhihu.com/p/17665975415&lt;/li&gt;
&lt;li&gt;[来源4] 2025-11-11 对话方三文（视频汇编）｜B 站：https://www.bilibili.com/video/BV1xDkkBqE6U/&lt;/li&gt;
&lt;li&gt;[来源5] 2025 伯克希尔股东大会精华｜观察者网：https://www.guancha.cn/internation/2025_05_04_774565.shtml&lt;/li&gt;
&lt;li&gt;[来源6] 年会问答要点与贸易观点｜钛媒体：https://www.tmtpost.com/7555654.html&lt;/li&gt;
&lt;li&gt;[来源7] 年会问答全文要点｜新浪财经：https://finance.sina.com.cn/stock/zqgd/2025-05-04/doc-inevkfsy6079193.shtml&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;注：本文为公开信息的学习与记录，不构成任何投资建议。&lt;/p&gt;
&lt;/blockquote&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Java Double List 去除突刺点（异常值）的方法</title>
        <published>2025-11-12T00:00:00+00:00</published>
        <updated>2025-11-12T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/java-double-list-outlier-removal/"/>
        <id>https://scp.net.cn/blog/java-double-list-outlier-removal/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/java-double-list-outlier-removal/">&lt;p&gt;本文面向需要在 Java 中对 &lt;code&gt;List&amp;lt;Double&amp;gt;&lt;/code&gt; 数据做“去除突刺点（异常值）”的工程实践，给出 4 类常用方法（统计学、移动窗口、相邻点距离与多方法融合），并提供完整可运行的代码与 JUnit 测试示例，帮助你在不同业务场景下快速选择与落地。&lt;/p&gt;
&lt;p&gt;注意：异常值并非总是“错误”。许多业务的“尖峰”有可能是合理的事件。本文更像一套工具箱，你需要结合业务知识合理使用与调参。&lt;/p&gt;
&lt;h2 id=&quot;1-ji-yu-tong-ji-xue-fang-fa-de-yi-chang-zhi-jian-ce&quot;&gt;1. 基于统计学方法的异常值检测&lt;/h2&gt;
&lt;h3 id=&quot;z-score-fang-fa&quot;&gt;Z-Score 方法&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;思想：计算全局均值 &lt;code&gt;μ&lt;/code&gt; 与标准差 &lt;code&gt;σ&lt;/code&gt;，当某点 &lt;code&gt;x&lt;/code&gt; 满足 &lt;code&gt;| (x-μ) / σ | &amp;gt; k&lt;/code&gt;（常用阈值 &lt;code&gt;k=3&lt;/code&gt;）时，判为异常。&lt;/li&gt;
&lt;li&gt;适用：近似正态分布、峰值显著偏离整体均值的场景。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;iqr-si-fen-wei-ju-fang-fa&quot;&gt;IQR (四分位距) 方法&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;思想：计算 Q1、Q3 与 IQR=&lt;code&gt;Q3-Q1&lt;/code&gt;，当点落在 &lt;code&gt;[Q1 - α·IQR, Q3 + α·IQR]&lt;/code&gt; 之外（常用 &lt;code&gt;α=1.5&lt;/code&gt; 或 &lt;code&gt;3.0&lt;/code&gt;）判为异常。&lt;/li&gt;
&lt;li&gt;适用：偏态分布或存在重尾时较稳健（受极端值影响较小）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;2-ji-yu-yi-dong-chuang-kou-de-yi-chang-zhi-jian-ce&quot;&gt;2. 基于移动窗口的异常值检测&lt;/h2&gt;
&lt;h3 id=&quot;hua-dong-chuang-kou-z-score&quot;&gt;滑动窗口 Z-Score&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;思想：用邻域窗口的均值与标准差代替全局统计，适合非平稳或趋势性数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;yi-dong-ping-jun-fa&quot;&gt;移动平均法&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;思想：用窗口均值/中位数做局部“期望值”，当当前点偏离窗口均值超过一定阈值即判异常。&lt;/li&gt;
&lt;li&gt;常见阈值：绝对差超过 &lt;code&gt;β·σ_window&lt;/code&gt; 或超过固定常数 &lt;code&gt;δ&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;3-ji-yu-xiang-lin-dian-ju-chi-de-yi-chang-zhi-jian-ce&quot;&gt;3. 基于相邻点距离的异常值检测&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;思想：突刺常表现为与相邻点差值显著增大。可用固定阈值或鲁棒阈值（如差值的 &lt;code&gt;MAD&lt;/code&gt; 或四分位距）来判断。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;4-zong-he-duo-chong-fang-fa-de-yi-chang-zhi-jian-ce&quot;&gt;4. 综合多种方法的异常值检测&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;思想：多模型投票或加权融合。只有当多个方法一致判定为异常时才去除，可降低误杀风险。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;5-wan-zheng-dai-ma-outlierdetectors-java-ke-zhi-jie-fu-zhi-shi-yong&quot;&gt;5. 完整代码：OutlierDetectors.java（可直接复制使用）&lt;/h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; java&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;util&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; java&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;util&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;stream&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;public final class&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; OutlierDetectors&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; OutlierDetectors&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;() {}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // ===================== 公共工具与预处理 =====================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public static&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; dropNullAndNaN&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;data &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;== null&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return&lt;/span&gt;&lt;span&gt; Collections&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;emptyList&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; cleaned&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; ArrayList&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;())&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        for&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span&gt; d&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; :&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;d &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;!= null &amp;amp;&amp;amp; !&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;isNaN&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;amp;&amp;amp; !&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;isInfinite&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                cleaned&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return&lt;/span&gt;&lt;span&gt; cleaned&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public static double&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; mean&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;isEmpty&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;())&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0.0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        double&lt;/span&gt;&lt;span&gt; s&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0.0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        for&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;double&lt;/span&gt;&lt;span&gt; v&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; :&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span&gt; s &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;+=&lt;/span&gt;&lt;span&gt; v&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return&lt;/span&gt;&lt;span&gt; s &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;/&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 样本标准差（n-1），窗口过小则回退为 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public static double&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; sampleStd&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        int&lt;/span&gt;&lt;span&gt; n&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;n &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0.0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        double&lt;/span&gt;&lt;span&gt; mu&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; mean&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        double&lt;/span&gt;&lt;span&gt; sumSq&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0.0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        for&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;double&lt;/span&gt;&lt;span&gt; v&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; :&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            double&lt;/span&gt;&lt;span&gt; d&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; v &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&lt;/span&gt;&lt;span&gt; mu&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            sumSq &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;+=&lt;/span&gt;&lt;span&gt; d &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span&gt; d&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return&lt;/span&gt;&lt;span&gt; Math&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sqrt&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;sumSq &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;n &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public static double&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; median&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;isEmpty&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;())&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0.0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; sorted&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; ArrayList&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Collections&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sort&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;sorted&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        int&lt;/span&gt;&lt;span&gt; n&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; sorted&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;n &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return&lt;/span&gt;&lt;span&gt; sorted&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;n &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;sorted&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;n &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span&gt; sorted&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;n &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; /&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2.0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public static double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[]&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; quartiles&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // 简单实现，适用于一般场景；严谨场景可使用更精细的分位数算法&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; sorted&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; ArrayList&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Collections&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sort&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;sorted&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        int&lt;/span&gt;&lt;span&gt; n&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; sorted&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;n &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return new double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[]{&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        double&lt;/span&gt;&lt;span&gt; q2&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; median&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;sorted&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; lower&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; sorted&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;subList&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; n &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; upper&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; sorted&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;subList&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;((&lt;/span&gt;&lt;span&gt;n &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ?&lt;/span&gt;&lt;span&gt; n &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; :&lt;/span&gt;&lt;span&gt; n &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;),&lt;/span&gt;&lt;span&gt; n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        double&lt;/span&gt;&lt;span&gt; q1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; median&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;lower&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        double&lt;/span&gt;&lt;span&gt; q3&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; median&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;upper&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return new double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[]{&lt;/span&gt;&lt;span&gt;q1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; q2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; q3&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public static double&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; mad&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        double&lt;/span&gt;&lt;span&gt; med&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; median&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; dev&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;stream&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;v &lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt; Math&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;abs&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;v &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&lt;/span&gt;&lt;span&gt; med&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)).&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;collect&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;Collectors&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;toList&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;())&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; median&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;dev&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 根据掩码移除异常值&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public static&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; removeByMask&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Boolean&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; isOutlier&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; out&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; ArrayList&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;())&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        for&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;int&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;!&lt;/span&gt;&lt;span&gt;isOutlier&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span&gt; out&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return&lt;/span&gt;&lt;span&gt; out&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // ===================== 1) 统计学：Z-Score =====================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public static&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Boolean&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; detectByZScore&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; double&lt;/span&gt;&lt;span&gt; k&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; cleaned&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; dropNullAndNaN&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        double&lt;/span&gt;&lt;span&gt; mu&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; mean&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;cleaned&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        double&lt;/span&gt;&lt;span&gt; std&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; sampleStd&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;cleaned&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;std &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;            // 如果方差为 0，则所有值都相同；默认无异常&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            return&lt;/span&gt;&lt;span&gt; Collections&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;nCopies&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(),&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; false&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Boolean&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; mask&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; ArrayList&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;())&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        for&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; :&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            boolean&lt;/span&gt;&lt;span&gt; out&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;x &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;== null ||&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;isNaN&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ||&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;isInfinite&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;())&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ? true :&lt;/span&gt;&lt;span&gt; Math&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;abs&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;((&lt;/span&gt;&lt;span&gt;x &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&lt;/span&gt;&lt;span&gt; mu&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; /&lt;/span&gt;&lt;span&gt; std&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span&gt; k&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            mask&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;out&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return&lt;/span&gt;&lt;span&gt; mask&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public static&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; removeByZScore&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; double&lt;/span&gt;&lt;span&gt; k&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; removeByMask&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; detectByZScore&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; k&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // ===================== 1) 统计学：IQR =====================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public static&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Boolean&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; detectByIQR&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; double&lt;/span&gt;&lt;span&gt; alpha&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; cleaned&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; dropNullAndNaN&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;cleaned&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;isEmpty&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;())&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return&lt;/span&gt;&lt;span&gt; Collections&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;nCopies&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(),&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; false&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[]&lt;/span&gt;&lt;span&gt; qs&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; quartiles&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;cleaned&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        double&lt;/span&gt;&lt;span&gt; q1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; qs&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;],&lt;/span&gt;&lt;span&gt; q3 &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt; qs&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        double&lt;/span&gt;&lt;span&gt; iqr&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; q3 &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&lt;/span&gt;&lt;span&gt; q1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        double&lt;/span&gt;&lt;span&gt; lo&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; q1 &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&lt;/span&gt;&lt;span&gt; alpha &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span&gt; iqr&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        double&lt;/span&gt;&lt;span&gt; hi&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; q3 &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;+&lt;/span&gt;&lt;span&gt; alpha &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span&gt; iqr&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Boolean&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; mask&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; ArrayList&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;())&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        for&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; :&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            boolean&lt;/span&gt;&lt;span&gt; out&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;x &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;== null ||&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;isNaN&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ||&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;isInfinite&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;())&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ? true :&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;x &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; lo &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;||&lt;/span&gt;&lt;span&gt; x &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; hi&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            mask&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;out&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return&lt;/span&gt;&lt;span&gt; mask&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public static&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; removeByIQR&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; double&lt;/span&gt;&lt;span&gt; alpha&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; removeByMask&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; detectByIQR&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; alpha&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // ===================== 2) 滑动窗口 Z-Score =====================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public static&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Boolean&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; detectBySlidingZScore&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; int&lt;/span&gt;&lt;span&gt; window&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; double&lt;/span&gt;&lt;span&gt; k&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        int&lt;/span&gt;&lt;span&gt; n&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Boolean&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; mask&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; ArrayList&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span&gt;Collections&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;nCopies&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; false&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        for&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;int&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; n&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            int&lt;/span&gt;&lt;span&gt; start&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; Math&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;max&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&lt;/span&gt;&lt;span&gt; window&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            int&lt;/span&gt;&lt;span&gt; end&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; Math&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;min&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;+&lt;/span&gt;&lt;span&gt; window &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;            List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; neigh&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; ArrayList&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&amp;gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            for&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;int&lt;/span&gt;&lt;span&gt; j&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; start&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; j &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; end&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; j&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;                Double&lt;/span&gt;&lt;span&gt; v&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;j&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;                if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;v &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;!= null &amp;amp;&amp;amp; !&lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;isNaN&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;amp;&amp;amp; !&lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;isInfinite&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;())&lt;/span&gt;&lt;span&gt; neigh&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            double&lt;/span&gt;&lt;span&gt; mu&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; mean&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;neigh&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            double&lt;/span&gt;&lt;span&gt; std&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; sampleStd&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;neigh&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;            Double&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            boolean&lt;/span&gt;&lt;span&gt; out&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;x &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;== null ||&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;isNaN&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ||&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;isInfinite&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;())&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ? true :&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;std &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0.0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ? false :&lt;/span&gt;&lt;span&gt; Math&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;abs&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;((&lt;/span&gt;&lt;span&gt;x &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&lt;/span&gt;&lt;span&gt; mu&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; /&lt;/span&gt;&lt;span&gt; std&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span&gt; k&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            mask&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; out&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return&lt;/span&gt;&lt;span&gt; mask&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public static&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; removeBySlidingZScore&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; int&lt;/span&gt;&lt;span&gt; window&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; double&lt;/span&gt;&lt;span&gt; k&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; removeByMask&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; detectBySlidingZScore&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; window&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; k&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // ===================== 2) 移动平均法 =====================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public static&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Boolean&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; detectByMovingAverage&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; int&lt;/span&gt;&lt;span&gt; window&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; double&lt;/span&gt;&lt;span&gt; beta&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        int&lt;/span&gt;&lt;span&gt; n&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Boolean&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; mask&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; ArrayList&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span&gt;Collections&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;nCopies&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; false&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        for&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;int&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; n&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            int&lt;/span&gt;&lt;span&gt; start&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; Math&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;max&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&lt;/span&gt;&lt;span&gt; window&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            int&lt;/span&gt;&lt;span&gt; end&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; Math&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;min&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;+&lt;/span&gt;&lt;span&gt; window &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;            List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; neigh&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; ArrayList&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&amp;gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            for&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;int&lt;/span&gt;&lt;span&gt; j&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; start&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; j &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; end&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; j&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;                Double&lt;/span&gt;&lt;span&gt; v&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;j&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;                if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;v &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;!= null &amp;amp;&amp;amp; !&lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;isNaN&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;amp;&amp;amp; !&lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;isInfinite&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;())&lt;/span&gt;&lt;span&gt; neigh&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            double&lt;/span&gt;&lt;span&gt; mu&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; mean&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;neigh&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            double&lt;/span&gt;&lt;span&gt; std&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; sampleStd&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;neigh&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;            Double&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            boolean&lt;/span&gt;&lt;span&gt; out&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;x &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;== null ||&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;isNaN&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ||&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;isInfinite&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;())&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ? true :&lt;/span&gt;&lt;span&gt; Math&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;abs&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;x &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&lt;/span&gt;&lt;span&gt; mu&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span&gt; beta &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;std &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0.0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ?&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1.0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; :&lt;/span&gt;&lt;span&gt; std&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            mask&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; out&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return&lt;/span&gt;&lt;span&gt; mask&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public static&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; removeByMovingAverage&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; int&lt;/span&gt;&lt;span&gt; window&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; double&lt;/span&gt;&lt;span&gt; beta&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; removeByMask&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; detectByMovingAverage&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; window&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; beta&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // ===================== 3) 相邻点距离 =====================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public static&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Boolean&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; detectByNeighborDistance&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; double&lt;/span&gt;&lt;span&gt; threshold&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; boolean&lt;/span&gt;&lt;span&gt; robust&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        int&lt;/span&gt;&lt;span&gt; n&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;n &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return&lt;/span&gt;&lt;span&gt; Collections&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;emptyList&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; diffs&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; ArrayList&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&amp;gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        for&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;int&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; n&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;            Double&lt;/span&gt;&lt;span&gt; a&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;),&lt;/span&gt;&lt;span&gt; b &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;a &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;== null ||&lt;/span&gt;&lt;span&gt; b &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;== null ||&lt;/span&gt;&lt;span&gt; a&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;isNaN&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ||&lt;/span&gt;&lt;span&gt; b&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;isNaN&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ||&lt;/span&gt;&lt;span&gt; a&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;isInfinite&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ||&lt;/span&gt;&lt;span&gt; b&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;isInfinite&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;())&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; continue;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            diffs&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;Math&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;abs&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;b &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&lt;/span&gt;&lt;span&gt; a&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        double&lt;/span&gt;&lt;span&gt; base&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;robust&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            double&lt;/span&gt;&lt;span&gt; m&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; median&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;diffs&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            double&lt;/span&gt;&lt;span&gt; mdev&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; mad&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;diffs&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            base &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt; m &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 3.0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;mdev &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0.0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ?&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1.0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; :&lt;/span&gt;&lt;span&gt; mdev&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; else&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            base &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt; diffs&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;isEmpty&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ?&lt;/span&gt;&lt;span&gt; threshold &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; mean&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;diffs&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 3.0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; sampleStd&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;diffs&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        double&lt;/span&gt;&lt;span&gt; th&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; Math&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;max&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;threshold&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; base&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; // 使用用户阈值与数据驱动阈值的较大者&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Boolean&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; mask&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; ArrayList&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span&gt;Collections&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;nCopies&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; false&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        for&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;int&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; n&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;            Double&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;x &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;== null ||&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;isNaN&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ||&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;isInfinite&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()) {&lt;/span&gt;&lt;span&gt; mask&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;; continue;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            double&lt;/span&gt;&lt;span&gt; left&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; != null &amp;amp;&amp;amp; !&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;isNaN&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;amp;&amp;amp; !&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;isInfinite&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;())&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ?&lt;/span&gt;&lt;span&gt; Math&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;abs&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;x &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0.0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            double&lt;/span&gt;&lt;span&gt; right&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; n &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; != null &amp;amp;&amp;amp; !&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;isNaN&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;amp;&amp;amp; !&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;isInfinite&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;())&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ?&lt;/span&gt;&lt;span&gt; Math&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;abs&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;x &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0.0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            boolean&lt;/span&gt;&lt;span&gt; out&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; left &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; th &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span&gt; right &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; th&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; // 两侧距离都大更像“尖刺”&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            mask&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; out&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return&lt;/span&gt;&lt;span&gt; mask&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public static&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; removeByNeighborDistance&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; double&lt;/span&gt;&lt;span&gt; threshold&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; boolean&lt;/span&gt;&lt;span&gt; robust&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; removeByMask&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; detectByNeighborDistance&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; threshold&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; robust&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // ===================== 4) 多方法融合（投票） =====================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public static class&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; CombinedParams&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        public double&lt;/span&gt;&lt;span&gt; zK&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 3.0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;            // 全局 Z-Score 阈值&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        public double&lt;/span&gt;&lt;span&gt; iqrAlpha&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1.5&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;      // IQR 系数&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        public int&lt;/span&gt;&lt;span&gt; slideWindow&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 5&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // 滑动窗口大小（左右各 window）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        public double&lt;/span&gt;&lt;span&gt; slideK&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 3.0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // 滑动 Z-Score 阈值&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        public double&lt;/span&gt;&lt;span&gt; maBeta&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 3.0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // 移动均值偏差倍数&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        public double&lt;/span&gt;&lt;span&gt; neighborThreshold&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0.0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; // 最小固定距离阈值&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        public boolean&lt;/span&gt;&lt;span&gt; neighborRobust&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = true;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  // 使用鲁棒阈值&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        public int&lt;/span&gt;&lt;span&gt; votesRequired&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;      // 至少多少方法判为异常&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public static&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Boolean&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; detectByCombined&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; CombinedParams&lt;/span&gt;&lt;span&gt; p&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Boolean&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; m1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; detectByZScore&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; p&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;zK&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Boolean&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; m2&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; detectByIQR&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; p&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;iqrAlpha&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Boolean&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; m3&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; detectBySlidingZScore&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; p&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;slideWindow&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; p&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;slideK&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Boolean&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; m4&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; detectByMovingAverage&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; p&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;slideWindow&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; p&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;maBeta&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Boolean&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; m5&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; detectByNeighborDistance&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; p&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;neighborThreshold&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; p&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;neighborRobust&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        int&lt;/span&gt;&lt;span&gt; n&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Boolean&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; out&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; ArrayList&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span&gt;Collections&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;nCopies&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; false&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        for&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;int&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; n&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            int&lt;/span&gt;&lt;span&gt; votes&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;m1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span&gt; votes&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;m2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span&gt; votes&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;m3&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span&gt; votes&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;m4&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span&gt; votes&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;m5&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span&gt; votes&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            out&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; votes &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;=&lt;/span&gt;&lt;span&gt; p&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;votesRequired&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return&lt;/span&gt;&lt;span&gt; out&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public static&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; removeByCombined&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; CombinedParams&lt;/span&gt;&lt;span&gt; p&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; removeByMask&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; detectByCombined&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; p&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // ===================== 5) 演示用主程序 =====================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public static void&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; main&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[]&lt;/span&gt;&lt;span&gt; args&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; raw&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; Arrays&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;asList&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;                10.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10.5&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10.2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 9.9&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10.1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;                45.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; // 突刺&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;                10.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 9.8&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10.3&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10.2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;                -&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;30.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; // 负向突刺&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;                10.1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 9.9&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        )&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        System&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;out&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;原始数据:  &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span&gt; raw&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        System&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;out&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Z-Score 清洗: &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; removeByZScore&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;raw&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 3.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        System&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;out&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;IQR 清洗:     &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; removeByIQR&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;raw&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1.5&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        System&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;out&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;滑动Z 清洗:   &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; removeBySlidingZScore&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;raw&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 3.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        System&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;out&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;移动均值 清洗: &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; removeByMovingAverage&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;raw&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 3.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        System&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;out&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;相邻距离 清洗: &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; removeByNeighborDistance&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;raw&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        CombinedParams&lt;/span&gt;&lt;span&gt; p&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; CombinedParams&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        p&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;votesRequired&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; // 至少两种方法判为异常才移除&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        System&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;out&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;融合清洗:     &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; removeByCombined&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;raw&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; p&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;6-ce-shi-yong-li-junit-5&quot;&gt;6. 测试用例（JUnit 5）&lt;/h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; org&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;junit&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;jupiter&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;api&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Test&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import static&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; org&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;junit&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;jupiter&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;api&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Assertions&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; java&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;util&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;public class&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; OutlierDetectorsTest&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    @&lt;/span&gt;&lt;span style=&quot;color: #D08770;&quot;&gt;Test&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    void&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; zscore_removes_spikes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; Arrays&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;asList&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;10.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10.2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10.1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 50.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 9.9&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; cleaned&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; OutlierDetectors&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;removeByZScore&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 3.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;        assertFalse&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;cleaned&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;contains&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;50.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;        assertTrue&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;cleaned&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    @&lt;/span&gt;&lt;span style=&quot;color: #D08770;&quot;&gt;Test&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    void&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; iqr_handles_skewed&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; Arrays&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;asList&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1.1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1.2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 5.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0.9&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; cleaned&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; OutlierDetectors&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;removeByIQR&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1.5&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;        assertFalse&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;cleaned&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;contains&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;5.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    @&lt;/span&gt;&lt;span style=&quot;color: #D08770;&quot;&gt;Test&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    void&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; sliding_zscore_detects_local_spike&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; Arrays&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;asList&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;10.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10.1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 30.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10.2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10.1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; cleaned&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; OutlierDetectors&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;removeBySlidingZScore&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2.5&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;        assertFalse&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;cleaned&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;contains&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;30.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    @&lt;/span&gt;&lt;span style=&quot;color: #D08770;&quot;&gt;Test&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    void&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; moving_average_removes_outliers&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; Arrays&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;asList&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;100.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 100.1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 99.9&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 400.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 100.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; cleaned&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; OutlierDetectors&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;removeByMovingAverage&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 3.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;        assertFalse&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;cleaned&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;contains&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;400.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    @&lt;/span&gt;&lt;span style=&quot;color: #D08770;&quot;&gt;Test&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    void&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; neighbor_distance_catches_spike_between_flat_values&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; Arrays&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;asList&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;10.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 50.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; cleaned&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; OutlierDetectors&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;removeByNeighborDistance&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;        assertFalse&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;cleaned&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;contains&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;50.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    @&lt;/span&gt;&lt;span style=&quot;color: #D08770;&quot;&gt;Test&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    void&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; combined_voting_is_conservative&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; Arrays&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;asList&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;10.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10.1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 11.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10.2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        OutlierDetectors&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;CombinedParams&lt;/span&gt;&lt;span&gt; p&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span&gt; OutlierDetectors&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;CombinedParams&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        p&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;votesRequired&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; cleaned&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; OutlierDetectors&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;removeByCombined&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; p&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // 11.0 不一定被去除（取决于窗口与阈值），这里检查不发生误杀（示例）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;        assertTrue&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;cleaned&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;contains&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;11.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;7-shi-ji-ying-yong-shi-li&quot;&gt;7. 实际应用示例&lt;/h2&gt;
&lt;p&gt;例如 IoT 设备的温度读数，每分钟一个点，偶尔出现硬件抖动导致的尖峰。建议：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;先用“滑动窗口 Z-Score（window=5，k=3）”检测局部异常。&lt;/li&gt;
&lt;li&gt;再用“相邻点距离（robust=true）”做二次确认。&lt;/li&gt;
&lt;li&gt;两者都判异常才移除（&lt;code&gt;votesRequired=2&lt;/code&gt;）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这样可以兼顾对局部突变的敏感性与稳健性，降低误杀风险。&lt;/p&gt;
&lt;h2 id=&quot;8-xing-neng-you-hua-jian-yi&quot;&gt;8. 性能优化建议&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;预计算滚动均值/方差（O(n)），避免重复遍历。&lt;/li&gt;
&lt;li&gt;大数据量时优先选用 IQR/MAD 等一次扫描算法。&lt;/li&gt;
&lt;li&gt;使用并行流或分块处理提升吞吐（注意线程安全）。&lt;/li&gt;
&lt;li&gt;对近似实时流，优先滑窗方法，避免全量重算。&lt;/li&gt;
&lt;li&gt;对多次查询的静态数据，缓存中间统计结果。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;9-zhu-yi-shi-xiang-qiang-lie-tui-jian-shi-jian&quot;&gt;9. 注意事项（强烈推荐实践）&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;数据预处理：在检测异常值之前，先过滤掉 NULL 值和 NaN 值。&lt;/li&gt;
&lt;li&gt;参数选择：根据具体业务场景调整阈值（如 Z-Score 的 k、IQR 的 α、滑窗大小、β 等）。&lt;/li&gt;
&lt;li&gt;数据分布：考虑数据分布特性，正态更适合 Z-Score，偏态/重尾用 IQR/MAD 更稳健。&lt;/li&gt;
&lt;li&gt;性能考虑：大数据量时使用近似方法或并行处理；滚动统计更高效。&lt;/li&gt;
&lt;li&gt;业务逻辑：结合业务知识判断哪些“异常值”实际上是合理的事件，不要轻易删除。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;10-dai-ma-yun-xing-shuo-ming-ke-xuan&quot;&gt;10. 代码运行说明（可选）&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;复制 &lt;code&gt;OutlierDetectors.java&lt;/code&gt; 与测试到你的工程。&lt;/li&gt;
&lt;li&gt;使用 Maven/Gradle 引入 JUnit 5 后运行测试。&lt;/li&gt;
&lt;li&gt;或直接 &lt;code&gt;javac OutlierDetectors.java&lt;/code&gt; 后运行 &lt;code&gt;java OutlierDetectors&lt;/code&gt; 查看演示输出。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以上方法可根据你的具体需求进行选择和调整，以有效去除 Double 列表中的突刺点。&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>林园投资理念全景：30年访谈与王洪著作的系统化梳理（含可操作手册）</title>
        <published>2025-11-12T00:00:00+00:00</published>
        <updated>2025-11-12T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/linyuan-30years-investment-handbook/"/>
        <id>https://scp.net.cn/blog/linyuan-30years-investment-handbook/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/linyuan-30years-investment-handbook/">&lt;h3 id=&quot;lin-yuan-de-he-xin-tou-zi-si-xiang&quot;&gt;林园的核心投资思想&lt;/h3&gt;
&lt;p&gt;林园作为中国价值投资的代表人物，从1989年以8000元起步，历经30多年股市沉浮，构建了一套以“确定性”为基石的投资体系。他的思想深受巴菲特和芒格影响，但更注重中国市场的本土化应用，强调长期持有、复利增长和人性博弈。以下是从其访谈记录（如北大演讲、2023-2025年媒体对话）和王洪著作（如《林园炒股秘籍》、《复合增长》、《激荡投资30年》）中提炼的核心思想，使用列表形式呈现：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;确定性原则&lt;/strong&gt;：投资的核心是“不见兔子不撒鹰”，优先选择未来盈利高度确定的公司。规避不确定性（如科技股、新兴品牌），因为不确定即风险。判断标准包括财务硬指标（如高毛利率、净资产收益率、利润总额），但需灵活结合行业趋势。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“行业 + 垄断 + 成瘾”黄金三角&lt;/strong&gt;：选股铁律。选择大行业（如消费、健康）中具有垄断地位（定价权、无竞争对手）的公司，产品需具备成瘾性（重复消费、刚需）。例如，白酒（如茅台）满足“成瘾+垄断”，医药（如慢性病药物）满足“行业增长+刚需”。远离竞争激烈的领域，拥抱“闭着眼睛都能赚钱”的企业。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“嘴巴生意”与大健康导向&lt;/strong&gt;：以人为本，聚焦人类基本需求。看好“嘴巴相关”（食品饮料、酒类）和“老人经济”（老龄化驱动的大健康，如糖尿病、心脏病、高血压药物）。从人口结构看，2024年中国65岁及以上人口约2.20亿、占比15.6%（国家统计局，2025-01-17），到2050年预计增至约3.6亿、占比约26%—30%（联合国《世界人口展望2024修订》；Peking University–Lancet 委员会报告）。需求侧的长期扩张为医药与健康相关消费提供持续的确定性（数据来源见文末“引用与资料来源”）。强调情绪价值（如白酒的“小酌怡情”）在AI时代更稀缺。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;长期持有与复利效应&lt;/strong&gt;：赚“长期的钱、成长的钱、正道的钱”。买了不卖，终身持有优秀公司，让时间和复利制造财富。优质股票如“金子”，价格下跌也不卖；伟大企业的收益会迟到但不会缺席。分散投资导致平庸，重仓集中于少数确定性标的（平均持有超6年）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;前瞻性与风险控制&lt;/strong&gt;：赚未来的钱，看人口趋势与基本面数据（如老龄化带来的医疗与护理需求增量）。风险在源头规避，通过调研（每月跟踪重仓公司）和能力圈限制（不投科技、券商）。以股息率与现金流折现为估值抓手，当股息率显著高于长期无风险收益率区间时加仓（如近年10年期国债收益率约2%—3%的环境中，持续现金分红的高股息公司更具吸引力）。坚持“不择时、不卖出”的长期主义。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;人性与心理管理&lt;/strong&gt;：投资像龟兔赛跑，孤独但靠时间取胜。第一个100万难赚，改变命运需15年（前11-12年可能无感）。抵抗贪婪，避免中途变卦；出资人与管理人互相选择，但合同绑定。股市如“骗子”，需坚守常识，不信“市梦率”。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些思想在王洪的书籍中被系统化呈现：《林园炒股秘籍》聚焦实战案例和分红复利；《复合增长》强调复利、垄断与成瘾；《激荡投资30年》回顾熊牛更替，剖析投机智慧与价值融合。&lt;/p&gt;
&lt;h3 id=&quot;zui-jin-30nian-de-tou-zi-shi-cao-zhi-nan-1995-2025&quot;&gt;最近30年的投资实操指南（1995-2025）&lt;/h3&gt;
&lt;p&gt;基于林园的投资思想，这份指南模拟其风格应用于中国股市过去30年（从早期发展到2025年成熟阶段）。中国股市经历了多轮牛熊转换：1995-2000年基础建设期、2001-2005年熊市、2006-2007年大牛市、2008年金融危机、2009-2014年波动、2015年股灾、2016-2020年结构性行情、2021-2022年调整、2023-2025年政策驱动反弹。林园风格强调不择时、长期持有，聚焦确定性刚需领域，避免泡沫。指南分为通用原则和分阶段操作，使用表格呈现关键点。&lt;/p&gt;
&lt;h4 id=&quot;tong-yong-yuan-ze&quot;&gt;通用原则&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;选股&lt;/strong&gt;：筛选“行业+垄断+成瘾”标的。优先医药（慢性病药）、白酒（高端龙头）、食品（必需消费）。调研每月进行，关注经销商和竞争对手。财务门槛：毛利率&amp;gt;50%、ROE&amp;gt;15%、分红率&amp;gt;长期债利率。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;建仓与持有&lt;/strong&gt;：低估值时分批建仓（3-10年过程），买了不卖。重仓比例70%以上于核心标的，利用复利滚雪球。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;风险控制&lt;/strong&gt;：能力圈内操作，不投科技/新能源。市场下跌视作机会，股息率&amp;gt;5%时加仓。心理管理：15年为周期，熬过前10年无感期。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;退出&lt;/strong&gt;：极少卖出，仅当公司垄断地位丧失或需求趋势逆转。赚取复合增长，非短期波动。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;普通投资者建议&lt;/strong&gt;：资产多元化但集中核心，终身持有分红股。相信需求端（如老龄化），忽略政策噪音。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;fen-jie-duan-shi-cao-zhi-nan&quot;&gt;分阶段实操指南&lt;/h4&gt;
&lt;p&gt;以下表格按时间段划分，列出基于林园思想的建议投资重点、关键行动和历史验证（参考其实际持仓如茅台、五粮液、中药股）。&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;时间段&lt;/th&gt;&lt;th&gt;市场背景&lt;/th&gt;&lt;th&gt;投资重点（林园风格）&lt;/th&gt;&lt;th&gt;关键行动&lt;/th&gt;&lt;th&gt;历史验证与教训&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;1995-2000：早期市场发展，国企改革启动&lt;/td&gt;&lt;td&gt;股市基础建设，波动大，蓝筹初现。&lt;/td&gt;&lt;td&gt;基础消费与医药刚需，如早期白酒（贵州茅台上市前布局）和中药股。聚焦“嘴巴生意”起步。&lt;/td&gt;&lt;td&gt;以小资金试水，选垄断初现公司（如区域性消费品）。建仓期3-5年，观察需求增长。&lt;/td&gt;&lt;td&gt;林园早期波段深发展获利，后转向价值。教训：避开投机股，转向确定性，避免1997亚洲危机损失。&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2001-2005：熊市调整，入世后经济转型&lt;/td&gt;&lt;td&gt;长期熊市，估值低迷，供给过剩。&lt;/td&gt;&lt;td&gt;加仓高股息消费股，如白酒和慢性病药。利用低估值建安全垫。&lt;/td&gt;&lt;td&gt;不卖出，视下跌为机会。调研人口需求（如老龄化初期）。&lt;/td&gt;&lt;td&gt;林园避开熊市，持有白酒类获复利。教训：分散不如集中，2005年转牛前重仓改变命运。&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2006-2010：大牛市后金融危机&lt;/td&gt;&lt;td&gt;2006-07牛市泡沫，2008全球危机，2009刺激反弹。&lt;/td&gt;&lt;td&gt;重仓白酒（如茅台、五粮液）和医药（如心脏病药）。避开地产/金融泡沫。&lt;/td&gt;&lt;td&gt;牛市不追高，危机中加仓垄断股。持有穿越熊牛。&lt;/td&gt;&lt;td&gt;林园2006成立机构，重仓消费获丰厚回报。教训：2008不卖，复利放大收益；科技泡沫易爆。&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2011-2015：波动与股灾&lt;/td&gt;&lt;td&gt;结构性行情，2015杠杆牛后股灾。&lt;/td&gt;&lt;td&gt;深化大健康布局，如糖尿病/高血压药。补充养老相关股。&lt;/td&gt;&lt;td&gt;股灾不慌，视作加仓时。强调成瘾性消费。&lt;/td&gt;&lt;td&gt;林园持仓穿越股灾，医药股需求刚性护盘。教训：杠杆放大风险，确定性胜过投机。&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2016-2020：结构性牛市，疫情冲击&lt;/td&gt;&lt;td&gt;白马股崛起，2020疫情后医药爆发。&lt;/td&gt;&lt;td&gt;加大老人经济投资，如肾透析/辅助生殖。白酒作为核心配置。&lt;/td&gt;&lt;td&gt;疫情中调研需求爆发，终身持有。&lt;/td&gt;&lt;td&gt;林园看好老龄化，医药股翻倍。教训：避开新能源泡沫，专注刚需。&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2021-2025：调整后政策反弹&lt;/td&gt;&lt;td&gt;2021-22调整，2023-25政策刺激，高股息流行。&lt;/td&gt;&lt;td&gt;70%仓位重仓老龄化医药（如三大病相关），白酒辅助。看好分红率&amp;gt;6%股。&lt;/td&gt;&lt;td&gt;当前牛市起点（4000点仅上半场），不卖，加仓便宜资产。调研未来趋势（如孩子稀缺）。&lt;/td&gt;&lt;td&gt;林园视2025为转折年，医药需求增10倍。教训：乐观持有，2026迎全面牛市。&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;此指南非林园本人直接输出，而是基于其思想的提炼应用。实际操作需结合个人风险承受力，建议调研最新数据。林园强调：投资是马拉松，15年为门槛，成功源于坚持确定性而非运气。&lt;/p&gt;
&lt;h3 id=&quot;wei-lai-30nian-de-tou-zi-shi-cao-zhi-nan-2026-2055&quot;&gt;未来30年的投资实操指南（2026-2055）&lt;/h3&gt;
&lt;p&gt;基于林园的投资思想，这份指南延伸其对未来趋势的预判，特别是人口老龄化作为最大确定性机会，推动大健康和“嘴巴生意”领域的长期增长。中国人口老龄化将加速：到2050年，65岁及以上人口预计约3.6—3.95亿，占比约26%—30%（联合国《世界人口展望2024修订》；Peking University–Lancet 委员会报告）；2024年当前基线为65岁及以上占比15.6%（国家统计局）。健康相关支出与产业规模在政策推动下持续扩张（“健康中国2030”、养老与长期护理政策等），结构性机会集中于慢性病用药、康养服务、营养保健与健康科技。林园强调，股票作为最具长期增值潜力的资产，应聚焦医药（如三大慢性病药物）和白酒等刚需垄断领域，靠复利与长期持有获取较高回报空间（风险提示见文末）。&lt;/p&gt;
&lt;h4 id=&quot;tong-yong-yuan-ze-yan-xu-guo-qu&quot;&gt;通用原则（延续过去）&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;选股&lt;/strong&gt;：深化“行业+垄断+成瘾”，优先老龄化驱动的大健康（如糖尿病、高血压、心脏病药物、养老服务、营养保健品）、白酒（高端品牌）和新兴健康科技（可穿戴设备、AI辅助医疗）。财务门槛：毛利率&amp;gt;50%、ROE&amp;gt;20%、分红率&amp;gt;长期债利率+2%。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;建仓与持有&lt;/strong&gt;：低估值时分批建仓（5-15年过程），终身持有。重仓80%以上于核心标的，利用复利和需求爆发滚雪球。相信人口趋势胜过政策波动。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;风险控制&lt;/strong&gt;：规避不确定性（如纯AI/新能源泡沫），每月跟踪实际需求与现金流质量。股息率&amp;gt;6%时加仓。心理管理：30年为周期，前15年可能波动大，坚持乐观。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;退出&lt;/strong&gt;：仅当需求逆转（如重大医疗突破消除慢性病）或垄断丧失。赚取复合增长，非短期投机。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;普通投资者建议&lt;/strong&gt;：指数化投资大健康ETF，结合白酒分红股。关注银发经济（如助行器、心理健康服务），忽略短期噪音。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;fen-jie-duan-shi-cao-zhi-nan-1&quot;&gt;分阶段实操指南&lt;/h4&gt;
&lt;p&gt;以下表格按5年期划分，列出基于林园思想的建议投资重点、关键行动和未来预判（参考人口、经济趋势和林园观点，如老龄化是朝阳行业，白酒需求稳定）。&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;时间段&lt;/th&gt;&lt;th&gt;市场/社会背景预判&lt;/th&gt;&lt;th&gt;投资重点（林园风格）&lt;/th&gt;&lt;th&gt;关键行动&lt;/th&gt;&lt;th&gt;预判验证与教训&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2026-2030：老龄化加速，健康消费扩张&lt;/td&gt;&lt;td&gt;老龄化率向20%附近抬升的路径下，医疗与护理需求显著增加（联合国与国家统计局数据基线）；政策促进健康服务供给与支付体系完善。&lt;/td&gt;&lt;td&gt;重仓慢性病医药（如糖尿病、心脏病药）和白酒龙头。补充营养保健和健康科技股。&lt;/td&gt;&lt;td&gt;低估值加仓（股息率&amp;gt;6%），调研老龄需求（如体重管理、肠道健康）。持有穿越波动。&lt;/td&gt;&lt;td&gt;结构性成长兑现；教训：避开短期政策噪音，专注刚需如三大病药物。&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2031-2035：人口总量峰值后下降，老龄率跃升&lt;/td&gt;&lt;td&gt;人口在2021-2022年已见峰值后缓降（联合国WPP2024），老龄化率继续上升至约23%—26%；康养产业扩张，心理健康与科技辅助需求显著。&lt;/td&gt;&lt;td&gt;深化大健康布局（如高血压药、养老服务、AI医疗设备）。白酒作为稳定配置。&lt;/td&gt;&lt;td&gt;复利滚动，调研新兴趋势（如健康数据分享）。不卖，视调整为机会。&lt;/td&gt;&lt;td&gt;银发经济扩张；教训：集中垄断股，分散导致平庸。&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2036-2040：老龄人口高速增长，产业成熟&lt;/td&gt;&lt;td&gt;老龄人口年均增500万+，率达25-27%；健康消费成刚需，特医食品突破800亿。&lt;/td&gt;&lt;td&gt;聚焦老人经济（如康复辅具、情绪健康产品）和慢性病垄断股。白酒需求难替代。&lt;/td&gt;&lt;td&gt;加仓高分红股，跟踪人口结构（如70-75岁组最多）。终身持有。&lt;/td&gt;&lt;td&gt;10倍股机会显现；教训：相信需求端，忽略经济下行噪音。&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2041-2045：老龄化率接近峰值，需求饱和前高潮&lt;/td&gt;&lt;td&gt;老龄人口近3亿，率27-29%；健康产业超20万亿，科技融合（如可穿戴监测）。&lt;/td&gt;&lt;td&gt;重仓创新健康（如心理健康服务、营养品）和白酒品牌。避开饱和子行业。&lt;/td&gt;&lt;td&gt;评估垄断地位，调研竞争变化。坚持复利，不择时。&lt;/td&gt;&lt;td&gt;赚取成长钱；教训：前15年熬过，改变命运需耐心。&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2046-2050：老龄人口逼近峰值，产业转型&lt;/td&gt;&lt;td&gt;65岁及以上人口接近3.6亿、占比约26%—30%（联合国WPP2024、Lancet）；健康科技与长期护理体系成为支柱。&lt;/td&gt;&lt;td&gt;优化大健康组合（如心脏病药、养老科技）。白酒作为防御。&lt;/td&gt;&lt;td&gt;估值回归期加仓，关注低生育率背景下的辅助生殖与母婴健康。&lt;/td&gt;&lt;td&gt;复合增长高峰；教训：成瘾+垄断与定价权决定长期胜率。&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2051-2055：老龄峰值3.6亿，率稳定上升&lt;/td&gt;&lt;td&gt;老龄人口峰值后降，但率继续升；产业成熟，全球第一老龄大国。&lt;/td&gt;&lt;td&gt;终身持有核心医药和白酒。探索后老龄时代（如长寿科技）。&lt;/td&gt;&lt;td&gt;风险控制，调研逆转因素（如医疗突破）。乐观持有。&lt;/td&gt;&lt;td&gt;100倍回报兑现；教训：投资马拉松，坚持确定性。&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;此指南为基于林园思想的未来推断，实际需动态调整。林园视老龄化为朝阳岗位，需求驱动一切，未来股市几万点可期。&lt;/p&gt;
&lt;h3 id=&quot;yin-yong-yu-zi-liao-lai-yuan&quot;&gt;引用与资料来源&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;联合国《世界人口展望2024修订》数据门户（人口年龄结构与长期预测）：https://population.un.org/wpp/&lt;/li&gt;
&lt;li&gt;联合国新闻稿与概要（中国人口峰值与长期趋势）：https://www.un.org/en/UN-projects-world-population-to-peak-within-this-century&lt;/li&gt;
&lt;li&gt;国家统计局《2024年人口数据情况》发布（2025-01-17）：https://www.stats.gov.cn/xxgk/jd/sjjd2020/202501/t20250117_1958337.html&lt;/li&gt;
&lt;li&gt;世界银行 WDI 中国总和生育率（SP.DYN.TFRT.IN）：https://data.worldbank.org/indicator/SP.DYN.TFRT.IN?locations=CN&lt;/li&gt;
&lt;li&gt;Peking University–Lancet 委员会报告（中国至2050年65岁及以上人口约3.66亿）：https://pmc.ncbi.nlm.nih.gov/articles/PMC9801271/&lt;/li&gt;
&lt;li&gt;《林园炒股秘籍》（王洪著，林园投资思想访谈与实战梳理）：https://weread.qq.com/web/bookDetail/cba32a90811e752d5g0125c3&lt;/li&gt;
&lt;li&gt;《复合增长》（王洪著，林园长期主义与复利方法论）：https://weread.qq.com/web/bookDetail/93c32890811e36e74g010ce3&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;注：本文为公开信息的学习与记录，不构成任何投资建议。引用均附权威链接，视频与演讲在后续数据库中将补充具体时间戳标注。&lt;/p&gt;
&lt;/blockquote&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>JVM 问题定位与性能调优实战经验</title>
        <published>2025-10-25T10:00:00+08:00</published>
        <updated>2025-10-25T10:00:00+08:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/jvm-troubleshooting-and-performance-tuning-practices/"/>
        <id>https://scp.net.cn/blog/jvm-troubleshooting-and-performance-tuning-practices/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/jvm-troubleshooting-and-performance-tuning-practices/">&lt;h1 id=&quot;yin-yan&quot;&gt;引言&lt;/h1&gt;
&lt;p&gt;JVM 是 Java 应用的运行时基石，性能与稳定性直接决定服务的可靠性与体验。生产中常见问题包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Full GC 频繁导致请求卡顿或超时&lt;/li&gt;
&lt;li&gt;内存泄漏引发 OOM/频繁 GC、吞吐骤降&lt;/li&gt;
&lt;li&gt;线程阻塞/死锁导致吞吐下降、响应延迟拉高&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本文结合真实生产案例，总结定位方法、调优参数与验证路径，覆盖 JDK8/11 差异与 Spring 框架特例，给出可复制的命令与配置示例。&lt;/p&gt;
&lt;p&gt;原理示意（简化）：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;请求流量 -&amp;gt; 线程池处理 -&amp;gt; 对象分配/回收 -&amp;gt; GC 与停顿 -&amp;gt; 状态观测与调优&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;               |            |           ^            |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;               |            v           |            v&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;           分配速率     老年代晋升   暂停时间     指标与日志&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&quot;li-lun-ji-chu&quot;&gt;理论基础&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;JVM 内存模型（简化）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;年轻代（Eden + Survivor）：新对象分配与 Minor GC&lt;/li&gt;
&lt;li&gt;老年代：长寿命对象、晋升与 Full GC&lt;/li&gt;
&lt;li&gt;元空间（JDK8+）：类元数据；JDK7 及之前为永久代（PermGen）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;垃圾回收机制&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;JDK8 默认 Parallel GC（也常见 CMS），JDK11 默认 G1 GC&lt;/li&gt;
&lt;li&gt;G1：分区化区域、预测停顿；支持 &lt;code&gt;MaxGCPauseMillis&lt;/code&gt; 与并发标记&lt;/li&gt;
&lt;li&gt;ZGC/Shenandoah（新 GC）：极低停顿，适合大堆，需更高版本支持与评估&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;统一日志&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;JDK8：&lt;code&gt;-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:gc.log&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;JDK11：&lt;code&gt;-Xlog:gc*,safepoint=info:file=gc.log:time,uptime,level,tags&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;背景知识&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;理解堆分区与 GC 日志是定位停顿与吞吐问题的基础；JDK8/11 的日志语法不同但目标一致：还原 GC 事件时间线与影响因素&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;实现原理&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;年轻代 Minor GC 触发于 Eden 满载；幸存者区（S0/S1）年龄达到阈值晋升老年代；老年代达到阈值触发并发标记与回收（G1），或 Full GC&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;实际应用场景&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在线服务需控制 p95/p99 停顿；批处理关注吞吐与回收效率；大堆（&amp;gt;8G）倾向选 G1/ZGC，结合对象存活曲线评估&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;配图示意：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;JVM 内存模型：&lt;img src=&quot;/jvm-memory-model-diagram.svg&quot; alt=&quot;JVM 内存模型&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/li&gt;
&lt;li&gt;GC 生命周期与路径：&lt;img src=&quot;/jvm-gc-flow-diagram.svg&quot; alt=&quot;GC 流程示意&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h1 id=&quot;shi-zhan-an-li-yi-dian-shang-xi-tong-full-gc-pin-fan-dao-zhi-fu-wu-qia-dun&quot;&gt;实战案例一：电商系统 Full GC 频繁导致服务卡顿&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;问题现象&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;峰值时段接口 p95 延迟由 150ms 升至 2.5s；GC 日志显示 Full GC 每 20–40s 触发&lt;/li&gt;
&lt;li&gt;指标：CPU 70–85%，OldGen 使用率持续上升；Safepoint 触发次数增多&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;诊断过程&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;快速采样：&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;jcmd&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;PI&lt;/span&gt;&lt;span&gt;D&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; VM.flags&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;jcmd&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;PI&lt;/span&gt;&lt;span&gt;D&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; GC.heap_info&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;jstat&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -gcutil&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;PI&lt;/span&gt;&lt;span&gt;D&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1000 20&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;线程栈：&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;jstack&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -l&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;PI&lt;/span&gt;&lt;span&gt;D&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; jstack.txt&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;观察到部分线程在 JSON 序列化与缓存键拼接上出现大量短生命周期对象分配&lt;/li&gt;
&lt;li&gt;堆直方图：&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;jmap&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -histo&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;PI&lt;/span&gt;&lt;span&gt;D&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt; |&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; head&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 50&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;Top N 对象以 &lt;code&gt;char[]&lt;/code&gt;、&lt;code&gt;StringBuilder&lt;/code&gt;、&lt;code&gt;byte[]&lt;/code&gt; 为主，Eden 分配速率高、晋升加剧&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;解决方案&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;切换 GC：JDK11 使用 G1，或 JDK8 启用 G1&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-XX:+UseG1GC -XX:MaxGCPauseMillis=200 \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-XX:InitiatingHeapOccupancyPercent=35 \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-XX:+UseStringDeduplication&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;对象分配优化：缓存键合并、减少临时 &lt;code&gt;StringBuilder&lt;/code&gt; 拼接；JSON 序列化改为复用缓冲&lt;/li&gt;
&lt;li&gt;堆大小与新生代比例：&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-Xms4g -Xmx4g -XX:MaxGCPauseMillis=200&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;视业务调整 &lt;code&gt;-XX:G1NewSizePercent=20&lt;/code&gt;、&lt;code&gt;-XX:G1MaxNewSizePercent=40&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;效果验证&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;优化后：Full GC 几乎无；Minor GC 间隔 3–8s，p95 延迟降至 180–250ms&lt;/li&gt;
&lt;li&gt;指标对比（示例）&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;指标&lt;/th&gt;&lt;th style=&quot;text-align: right&quot;&gt;优化前&lt;/th&gt;&lt;th style=&quot;text-align: right&quot;&gt;优化后&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;p95 延迟（ms）&lt;/td&gt;&lt;td style=&quot;text-align: right&quot;&gt;2500&lt;/td&gt;&lt;td style=&quot;text-align: right&quot;&gt;200&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Full GC 次数（/h）&lt;/td&gt;&lt;td style=&quot;text-align: right&quot;&gt;90&lt;/td&gt;&lt;td style=&quot;text-align: right&quot;&gt;2&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;OldGen 利用率（峰值）&lt;/td&gt;&lt;td style=&quot;text-align: right&quot;&gt;92%&lt;/td&gt;&lt;td style=&quot;text-align: right&quot;&gt;65%&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/li&gt;
&lt;li&gt;监控示例图：&lt;img src=&quot;/case1-gc-metrics-comparison.svg&quot; alt=&quot;GC 指标对比图&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;背景知识&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;电商高峰期对象分配速率暴涨，年轻代频繁回收与晋升导致老年代压力增大；缓存键拼接与 JSON 序列化是典型短生命周期对象热点&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;实现原理&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;G1 通过分区（Region）与并发标记控制停顿目标，&lt;code&gt;MaxGCPauseMillis&lt;/code&gt; 影响分区选择与回收预算；&lt;code&gt;InitiatingHeapOccupancyPercent&lt;/code&gt; 控制并发标记的触发阈值&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;实际应用场景&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;吞吐与低延迟兼顾的在线业务；字符串与序列化对象过多的接口；峰值流量下对 Full GC 敏感的交易与风控服务&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h1 id=&quot;shi-zhan-an-li-er-da-shu-ju-ying-yong-nei-cun-xie-lou-ding-wei-yu-xiu-fu&quot;&gt;实战案例二：大数据应用内存泄漏定位与修复&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;问题现象&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;任务运行数小时后堆使用逼近上限并 OOM；&lt;code&gt;OutOfMemoryError: Java heap space&lt;/code&gt; 与 &lt;code&gt;GC overhead limit exceeded&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;诊断过程&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;启用 OOM 堆转储并采集：&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/heapdump.hprof&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;使用 MAT/VisualVM 打开 dump，分析 Dominator Tree 与保留集大小&lt;/li&gt;
&lt;li&gt;发现自定义缓存 Map 未做过期与上限控制，且 Spring 单例中持有强引用导致无法回收&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;解决方案&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;缓存改造：引入 Caffeine，启用 TTL/大小上限与弱引用 value；定期 metrics 观测命中率&lt;/li&gt;
&lt;li&gt;Spring 特例：对单例 Bean 引用使用事件驱动清理、避免静态集合持有强引用；对 &lt;code&gt;ThreadLocal&lt;/code&gt; 调用结束时显式 &lt;code&gt;remove()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;参数：适度增大堆并保持统一 GC 日志，确认泄漏已闭环&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;效果验证&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;OOM 消失；堆使用稳定在 55–70% 区间；GC 周期稳定，Minor GC 2–6s 一次&lt;/li&gt;
&lt;li&gt;直方图 TopN 不再出现异常增长的自定义实体/集合类&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;背景知识&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;大数据应用中长生命周期集合与缓存极易引发保留集膨胀；Spring 单例生命周期贯穿应用运行期，易形成强引用链&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;实现原理&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dominator Tree 揭示对象保留关系；Caffeine TTL/大小上限与弱/软引用降低强引用保留；&lt;code&gt;ThreadLocal&lt;/code&gt; 未清理导致 ClassLoader 泄漏&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;实际应用场景&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ETL/流式任务的状态缓存；Web 服务的本地缓存/静态集合；框架级单例组件的资源持有&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;配图示意：&lt;img src=&quot;/spring-leak-architecture.svg&quot; alt=&quot;Spring 单例缓存强引用示意&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h1 id=&quot;shi-zhan-an-li-san-gao-bing-fa-chang-jing-xian-cheng-zu-sai-yu-can-shu-you-hua&quot;&gt;实战案例三：高并发场景线程阻塞与参数优化&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;问题现象&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;峰值 QPS 提升后吞吐不增反降；Web 层线程池饱和，队列等待；数据库连接池偶发耗尽&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;诊断过程&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;线程池与阻塞采样：&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;jstack&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -l&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;PI&lt;/span&gt;&lt;span&gt;D&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt; |&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A3 -E&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;WAITING|BLOCKED&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; head&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 50&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;发现部分请求在同步远程调用时长时间等待&lt;/li&gt;
&lt;li&gt;异步剖析（建议）：&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;./profiler.sh&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -e cpu -d&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 60&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -f /tmp/cpu.svg&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;PI&lt;/span&gt;&lt;span&gt;D&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;./profiler.sh&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -e wall -d&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 60&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -f /tmp/wall.svg&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;PI&lt;/span&gt;&lt;span&gt;D&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;定位到序列化与网络 I/O 占比过高&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;解决方案&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;线程池参数：合理设置核心/最大线程与队列长度，避免过大队列导致延迟扩散&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Spring Boot 示例（application.yml）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;server.tomcat.threads.max: 300&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;server.tomcat.accept-count: 200&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;HikariCP：连接池容量与超时参数与数据库上限一致，避免饱和抖动&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;spring.datasource.hikari.maximum-pool-size: 50&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;spring.datasource.hikari.connection-timeout: 30000&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;I/O 异步化：使用 WebClient/异步 HTTP 客户端改善阻塞；序列化复用缓冲与开启压缩按需&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;效果验证&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;吞吐从 6k rps 提升至 11k rps；p95 延迟由 800ms 降至 260ms&lt;/li&gt;
&lt;li&gt;队列等待基本消除，&lt;code&gt;BLOCKED/WAITING&lt;/code&gt; 线程显著降低&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;背景知识&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;高并发场景中线程池与下游连接池的容量规划、队列策略与超时配置直接影响延迟扩散与系统稳定性&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;实现原理&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;线程状态 &lt;code&gt;RUNNABLE/WAITING/BLOCKED&lt;/code&gt; 反映资源争用与同步阻塞；异步 I/O 降低阻塞等待；合理队列与限流避免过载&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;实际应用场景&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在线 API、网关、订单与支付服务；数据库/缓存/外部 HTTP 依赖明显的系统&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;配图示意：&lt;img src=&quot;/thread-blocking-flow.svg&quot; alt=&quot;线程阻塞与队列放大示意&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h1 id=&quot;tong-yong-diao-you-can-shu-yu-ming-ling-shi-li&quot;&gt;通用调优参数与命令示例&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;统一 GC 日志与诊断
&lt;ul&gt;
&lt;li&gt;JDK8：&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/var/log/app/gc.log \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-XX:+PrintTenuringDistribution -XX:+PrintGCApplicationStoppedTime&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;JDK11：&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-Xlog:gc*,safepoint=info:file=/var/log/app/gc.log:time,uptime,level,tags&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;典型堆与 GC 参数&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-Xms4g -Xmx4g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-XX:InitiatingHeapOccupancyPercent=35 -XX:+UseStringDeduplication \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/heapdump.hprof&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;快速命令清单&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 查看 JVM 启动参数，确认 GC 类型与关键调优项&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;jcmd&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;PI&lt;/span&gt;&lt;span&gt;D&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; VM.flags&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 查看堆结构与各区大小，评估晋升与老年代压力&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;jcmd&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;PI&lt;/span&gt;&lt;span&gt;D&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; GC.heap_info&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 以 1s 间隔采集 20 次 GC 利用率，观察 Minor/Full GC 频率&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;jstat&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -gcutil&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;PI&lt;/span&gt;&lt;span&gt;D&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1000 20&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 导出线程堆栈（含锁/等待），定位阻塞与热点代码路径&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;jstack&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -l&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;PI&lt;/span&gt;&lt;span&gt;D&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; jstack.txt&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 堆直方图，统计 TopN 对象类型与实例数，识别泄漏或分配热点&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;jmap&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -histo&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;PI&lt;/span&gt;&lt;span&gt;D&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt; |&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; head&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 50&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;原理示意（简化）：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;采样 -&amp;gt; 发现热点 -&amp;gt; 参数与代码调整 -&amp;gt; 指标回归&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       ^-----------------------------------|&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;注意：所有数据均已脱敏；在生产环境变更 JVM 参数前需进行灰度与回归测试，特别是 GC 类型切换与堆大小变更。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h1 id=&quot;jdk8-11-chai-yi-yu-spring-te-li&quot;&gt;JDK8/11 差异与 Spring 特例&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;JDK8 vs JDK11
&lt;ul&gt;
&lt;li&gt;默认 GC：Parallel/CMS（常见） vs G1；统一日志从 &lt;code&gt;PrintGC*&lt;/code&gt; 到 &lt;code&gt;Xlog&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;字符串去重：JDK8/11 G1 支持 &lt;code&gt;UseStringDeduplication&lt;/code&gt;，对大量相同字符串有效&lt;/li&gt;
&lt;li&gt;ZGC（JDK11+）、Shenandoah（部分发行版）：低停顿方案，需评估稳定性与生态&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Spring 特例
&lt;ul&gt;
&lt;li&gt;单例 Bean 持有静态集合导致泄漏；Web 容器热部署/类加载器泄漏风险&lt;/li&gt;
&lt;li&gt;Tomcat 线程与队列、HikariCP 连接池参数需与后端系统容量一致&lt;/li&gt;
&lt;li&gt;Actuator/指标采集过度会带来额外对象分配与锁竞争，需限流与采样&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h1 id=&quot;zong-jie-yu-zui-jia-shi-jian&quot;&gt;总结与最佳实践&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;指标驱动：以 p95 延迟、吞吐、GC 周期/时长、OldGen 占比为核心指标&lt;/li&gt;
&lt;li&gt;渐进式调整：从日志与采样入手，小步迭代，保留回滚路径（配置版本化）&lt;/li&gt;
&lt;li&gt;结合业务：对象分配速率与状态大小决定 GC 策略与堆规划&lt;/li&gt;
&lt;li&gt;框架特性：Spring 下注意单例与连接池、线程池、序列化策略的交互影响&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;参考与延伸阅读：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GC 调优（JDK11）：https://docs.oracle.com/javase/11/gctuning/&lt;/li&gt;
&lt;li&gt;G1 GC 原理与参数：https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/g1_gc.html&lt;/li&gt;
&lt;li&gt;Unified Logging（JDK9+）：https://docs.oracle.com/javase/9/tools/java.htm#JSWOR690&lt;/li&gt;
&lt;li&gt;Async-Profiler：https://github.com/async-profiler/async-profiler&lt;/li&gt;
&lt;li&gt;VisualVM：https://visualvm.github.io/&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Linux iptables、ipset 与 tc 的综合应用实践</title>
        <published>2025-10-25T10:00:00+08:00</published>
        <updated>2025-10-25T10:00:00+08:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/linux-iptables-ipset-tc-integrated-practice/"/>
        <id>https://scp.net.cn/blog/linux-iptables-ipset-tc-integrated-practice/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/linux-iptables-ipset-tc-integrated-practice/">&lt;h1 id=&quot;yin-yan&quot;&gt;引言&lt;/h1&gt;
&lt;p&gt;在中小规模到企业生产环境中，常需要同时满足“连接访问控制”与“带宽/队列管理”。Linux 生态提供了三件利器：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;iptables：基于 Netfilter 的防火墙规则管理，负责匹配并决定包的命运（ACCEPT/DROP/LOG 等）&lt;/li&gt;
&lt;li&gt;ipset：高效维护 IP、网段等集合，供 iptables 高速匹配，适合批量名单/黑白名单场景&lt;/li&gt;
&lt;li&gt;tc（Traffic Control）：基于 qdisc/class/filter 的流量控制，对包进行分类、整形与队列管理，实现带宽限制与延迟优化&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;三者组合可实现“按集合过滤 + 按集合限速”的统一方案，且不依赖上层代理或应用改造。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1 id=&quot;ji-shu-bei-jing-yu-he-xin-gong-neng&quot;&gt;技术背景与核心功能&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;iptables（过滤防火墙）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;核心概念：表（&lt;code&gt;filter&lt;/code&gt;/&lt;code&gt;nat&lt;/code&gt;/&lt;code&gt;mangle&lt;/code&gt;/&lt;code&gt;raw&lt;/code&gt;/&lt;code&gt;security&lt;/code&gt;）、链（&lt;code&gt;INPUT&lt;/code&gt;/&lt;code&gt;FORWARD&lt;/code&gt;/&lt;code&gt;OUTPUT&lt;/code&gt;/&lt;code&gt;PREROUTING&lt;/code&gt;/&lt;code&gt;POSTROUTING&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;常见模块：&lt;code&gt;-m set&lt;/code&gt;（与 ipset 集合匹配）、&lt;code&gt;-m state/conntrack&lt;/code&gt;（连接状态）、&lt;code&gt;-m tcp/udp&lt;/code&gt;（端口）&lt;/li&gt;
&lt;li&gt;典型用途：按源/目的 IP、端口、协议过滤；日志记录；打标（&lt;code&gt;-j MARK&lt;/code&gt;）为后续路由/流控使用&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;ipset（集合加速）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;集合类型：&lt;code&gt;hash:ip&lt;/code&gt;、&lt;code&gt;hash:net&lt;/code&gt;、&lt;code&gt;bitmap:ip&lt;/code&gt;、&lt;code&gt;list:set&lt;/code&gt; 等，支持 &lt;code&gt;timeout&lt;/code&gt;、&lt;code&gt;maxelem&lt;/code&gt;、&lt;code&gt;hashsize&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;典型用途：维护黑白名单、限速名单、DDoS 封禁集合；动态增删元素而无需频繁改 iptables 规则&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;tc（流量控制）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;组件：qdisc（队列策略，如 &lt;code&gt;htb&lt;/code&gt;、&lt;code&gt;tbf&lt;/code&gt;、&lt;code&gt;fq_codel&lt;/code&gt;）、class（类）、filter（过滤器，如 &lt;code&gt;fw&lt;/code&gt;/&lt;code&gt;u32&lt;/code&gt;/&lt;code&gt;flower&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;典型用途：带宽整形（rate/ceil）、队列调度（延迟控制/拥塞管理）、分流分类（不同业务或不同 IP 的通道隔离）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;组合优势与典型场景&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;将集合匹配与带宽控制打通：iptables 在 &lt;code&gt;mangle&lt;/code&gt; 打标，tc 用 &lt;code&gt;fw&lt;/code&gt; filter 读取 &lt;code&gt;skb-&amp;gt;mark&lt;/code&gt; 分类&lt;/li&gt;
&lt;li&gt;场景示例：
&lt;ul&gt;
&lt;li&gt;为某 IP 集合限制总带宽，同时禁止其访问敏感端口&lt;/li&gt;
&lt;li&gt;DDoS 下快速封禁集合并限速保护核心服务&lt;/li&gt;
&lt;li&gt;多租户/环境隔离：不同租户 IP 集合分配不同通道与速率&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h1 id=&quot;wan-zheng-guan-kong-an-li-she-ji-xian-zhi-te-ding-ip-ji-he-de-dai-kuan-bing-guo-lu-qi-fang-wen&quot;&gt;完整管控案例设计：限制特定 IP 集合的带宽并过滤其访问&lt;/h1&gt;
&lt;p&gt;目标：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;建立 &lt;code&gt;restricted_clients&lt;/code&gt; 集合，限制其下行/上行总带宽至 10 Mbit，并禁止访问 &lt;code&gt;tcp/22&lt;/code&gt;，只允许 &lt;code&gt;tcp/80&lt;/code&gt;/&lt;code&gt;443&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;通过 iptables+ipset 实现过滤与打标，通过 tc 实现整形与分类&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;网络示意（简化 ASCII）：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[Clients in restricted_clients] --(eth0)--&amp;gt; [Server]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        | iptables(mangle: MARK) + filter(DROP/ACCEPT)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        v&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      tc(htb classes) &amp;lt;- fw filter by mark&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;bu-zou-yi-shi-yong-ipset-chuang-jian-yu-guan-li-ip-ji-he&quot;&gt;步骤一：使用 ipset 创建与管理 IP 集合&lt;/h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 创建集合：hash:ip 类型，支持最多 65536 个元素，默认无超时&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; ipset create restricted_clients hash:ip maxelem&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 65536&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 增加若干 IP（示例）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; ipset add restricted_clients&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 203.0.113.10&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; ipset add restricted_clients&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 203.0.113.11&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; ipset add restricted_clients&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 203.0.113.12&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 查看集合与统计&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; ipset list restricted_clients&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;参数说明：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;hash:ip&lt;/code&gt;：适合离散 IP 集；如批量网段可用 &lt;code&gt;hash:net&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;maxelem&lt;/code&gt;：最大元素数，需结合内存与性能规划&lt;/li&gt;
&lt;li&gt;&lt;code&gt;timeout&lt;/code&gt;：可选，为元素设置过期时间（秒），便于临时封禁&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;bu-zou-er-tong-guo-iptables-she-zhi-ji-yu-ipset-de-guo-lu-yu-da-biao-gui-ze&quot;&gt;步骤二：通过 iptables 设置基于 ipset 的过滤与打标规则&lt;/h2&gt;
&lt;p&gt;建议在 &lt;code&gt;mangle&lt;/code&gt; 表的 &lt;code&gt;PREROUTING&lt;/code&gt;/&lt;code&gt;OUTPUT&lt;/code&gt; 早期对包打标，减少后续模块开销。&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 1) mangle 表：对来自 restricted_clients 的包打标 0x1（十六进制）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; iptables -t mangle -A PREROUTING -m set --match-set restricted_clients src&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;  -j MARK --set-mark&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0x1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 2) filter 表：拒绝其访问敏感端口（示例：SSH 22）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; iptables -A INPUT -p tcp --dport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 22&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -m set --match-set restricted_clients src -j DROP&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 3) filter 表：允许 HTTP/HTTPS（80/443），其余端口默认策略按需设置&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; iptables -A INPUT -p tcp -m multiport --dports 80,443&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;  -m set --match-set restricted_clients src -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 4) 可选：对不在集合的流量按默认策略（示例：允许已建立连接）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;参数说明：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-t mangle&lt;/code&gt;：适合做标记与特殊处理（不改变连接状态）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-m set --match-set NAME src|dst&lt;/code&gt;：匹配集合与方向（源/目的 IP）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-j MARK --set-mark&lt;/code&gt;：设置包标记供路由/tc 使用&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-m multiport&lt;/code&gt;：端口组合匹配，简化规则&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;bu-zou-san-jie-he-tc-dui-te-ding-ip-ji-he-jin-xing-dai-kuan-xian-zhi-an-biao-ji-fen-lei&quot;&gt;步骤三：结合 tc 对特定 IP 集合进行带宽限制（按标记分类）&lt;/h2&gt;
&lt;p&gt;tc 以“设备维度”工作，通常在出口（egress）整形。若需入口（ingress）限速，建议使用 &lt;code&gt;ifb&lt;/code&gt; 虚拟设备做重定向（下文扩展说明）。&lt;/p&gt;
&lt;p&gt;示例：在 &lt;code&gt;eth0&lt;/code&gt; 上创建 HTB 根队列，分两个类：默认类与限速类，使用 &lt;code&gt;fw&lt;/code&gt; 过滤器按标记将集合流量导向限速类。&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 1) 创建根 qdisc：HTB，默认 class id 1:30&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; tc qdisc add dev eth0 root handle 1: htb default&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 30&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 2) 创建类：为 restricted_clients 分配 10Mbit（可调），普通流量 100Mbit&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; tc class add dev eth0 parent 1: classid 1:10 htb rate 10mbit ceil 10mbit prio&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; tc class add dev eth0 parent 1: classid 1:30 htb rate 100mbit ceil 100mbit prio&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 3) 为类挂队列（可选优化：FQ-CoDel 降低排队延迟）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; tc qdisc add dev eth0 parent 1:10 handle 10: fq_codel&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; tc qdisc add dev eth0 parent 1:30 handle 30: fq_codel&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 4) 过滤器：按 fw 标记 0x1 将流量导入 1:10（限速类）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; tc filter add dev eth0 parent 1: protocol ip prio&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; handle&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0x1&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; fw flowid 1:10&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;参数说明：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;htb&lt;/code&gt;：分层令牌桶，适合多类带宽分配与上限控制（&lt;code&gt;rate&lt;/code&gt;/&lt;code&gt;ceil&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fq_codel&lt;/code&gt;：队列算法，抑制 Bufferbloat，改善交互延迟&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fw filter&lt;/code&gt;：按 &lt;code&gt;skb-&amp;gt;mark&lt;/code&gt; 分类；iptables 置位的 &lt;code&gt;MARK&lt;/code&gt; 在此生效&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rate/ceil&lt;/code&gt;：保证速率与上限；必要时结合 &lt;code&gt;burst/cburst&lt;/code&gt;（令牌桶突发）&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h1 id=&quot;pei-zhi-wan-zheng-shi-li-yu-zhu-xiang-shuo-ming&quot;&gt;配置完整示例与逐项说明&lt;/h1&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# ==== ipset ====&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 创建集合并导入样例 IP&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;ipset&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; create restricted_clients hash:ip maxelem&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 65536&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;ipset&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; add restricted_clients&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 203.0.113.10&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;ipset&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; add restricted_clients&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 203.0.113.11&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;ipset&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; add restricted_clients&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 203.0.113.12&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# ==== iptables ====&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# mangle 表：标记集合流量为 0x1（PREROUTING 更早匹配）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;ip&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -t mangle -A PREROUTING -m set --match-set restricted_clients src -j MARK --set-mark&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0x1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# filter 表：禁止集合访问 SSH（22）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A INPUT -p tcp --dport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 22&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -m set --match-set restricted_clients src -j DROP&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# filter 表：允许集合访问 80/443&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A INPUT -p tcp -m multiport --dports 80,443 -m set --match-set restricted_clients src -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 一般允许已建立连接，避免误伤&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# ==== tc ====&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# HTB 根队列，默认类 1:30（普通流量）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; qdisc add dev eth0 root handle 1: htb default&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 30&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 创建限速类（集合流量）与普通类&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; class add dev eth0 parent 1: classid 1:10 htb rate 10mbit ceil 10mbit prio&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; class add dev eth0 parent 1: classid 1:30 htb rate 100mbit ceil 100mbit prio&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 为类挂 FQ-CoDel 队列（可选）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; qdisc add dev eth0 parent 1:10 handle 10: fq_codel&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; qdisc add dev eth0 parent 1:30 handle 30: fq_codel&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 按 fw 标记分类：0x1 -&amp;gt; 1:10（限速）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; filter add dev eth0 parent 1: protocol ip prio&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; handle&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0x1&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; fw flowid 1:10&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;验证方法：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 查看 ipset 集合及命中统计&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;ipset&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; list restricted_clients&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 查看 iptables 规则与计数&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -t mangle -vnL PREROUTING&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -vnL INPUT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 查看 tc 类与队列统计（字节/包/丢弃等）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -s class show dev eth0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -s qdisc show dev eth0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 进行带宽测试（从集合中的客户端发起）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iperf3&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -c&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;server-i&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 5201&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 期望限速类吞吐 ≈ 10Mbit，普通类不受影响&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h1 id=&quot;ying-yong-chang-jing-kuo-zhan-yu-zui-jia-shi-jian&quot;&gt;应用场景扩展与最佳实践&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;企业网络管理&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;租户/部门/分环境的 IP 集合管理（ipset），配合 iptables 做端口准入控制&lt;/li&gt;
&lt;li&gt;按集合限速（tc/htb + fw filter），保障核心业务优先级&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;DDoS 防护（基础版）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;通过 ipset 快速维护黑名单；iptables 直接 DROP 或限速打标&lt;/li&gt;
&lt;li&gt;结合 &lt;code&gt;hashlimit&lt;/code&gt; 模块对新建连接速率限流（如 SYN），减轻峰值冲击&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;性能优化建议&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;集合规模规划：&lt;code&gt;maxelem/hashsize&lt;/code&gt; 与内存开销权衡；批量导入用 &lt;code&gt;ipset restore&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;规则层次清晰：先 mangle 打标，后 filter 做准入；减少重复匹配&lt;/li&gt;
&lt;li&gt;队列算法选择：默认 &lt;code&gt;fq_codel&lt;/code&gt; 提升交互；大带宽可评估 &lt;code&gt;cake&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;入口限速：使用 ifb 重定向 ingress&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 创建 ifb 并启用&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;modprobe&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; ifb&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;ip&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; link add ifb0 type ifb&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;ip&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; link set ifb0 up&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 将 eth0 ingress 重定向到 ifb0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; qdisc add dev eth0 handle ffff: ingress&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; filter add dev eth0 parent ffff: protocol ip u32 match u32&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0 0&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;  action mirred egress redirect dev ifb0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 在 ifb0 上做 HTB/TBF 等入口整形&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; qdisc add dev ifb0 root handle 2: htb default&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 20&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# ... 类与过滤器同上（可按 mark 或 u32/flower 匹配）&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h1 id=&quot;cgroup-wang-luo-kong-jian-ji-cheng-shi-jian&quot;&gt;cgroup 网络空间集成实践&lt;/h1&gt;
&lt;h2 id=&quot;host-wang-luo-mo-shi-vs-fei-host-wang-luo-mo-shi&quot;&gt;Host 网络模式 vs 非 Host 网络模式&lt;/h2&gt;
&lt;p&gt;本文前面介绍了按进程（cgroup）、按目的地址集合（ipset）和按接口/队列（tc）的整形与管控。本小节聚焦容器/进程的网络命名空间（netns）维度，解释 Host 网络模式与独立网络命名空间（非 Host 模式）的差异及实操要点。&lt;/p&gt;
&lt;h3 id=&quot;1-wang-luo-ge-chi-xing&quot;&gt;1) 网络隔离性&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Host 模式：进程/容器直接加入宿主机的网络命名空间，复用同一网络栈与接口（如 &lt;code&gt;eth0&lt;/code&gt;、&lt;code&gt;lo&lt;/code&gt;）。没有网络隔离，容器内看到的 &lt;code&gt;127.0.0.1&lt;/code&gt; 与宿主机一致。&lt;/li&gt;
&lt;li&gt;非 Host 模式：为进程/容器创建独立的网络命名空间，通常通过 &lt;code&gt;veth&lt;/code&gt; 与宿主机桥接（bridge）或使用 &lt;code&gt;macvlan/ipvlan&lt;/code&gt; 等机制。命名空间间网络栈相互隔离，需要显式路由/端口映射才能互访。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;2-wang-luo-pei-zhi&quot;&gt;2) 网络配置&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Host 模式：
&lt;ul&gt;
&lt;li&gt;使用宿主机 IP 与端口，直接在主机 &lt;code&gt;iptables&lt;/code&gt;/&lt;code&gt;tc&lt;/code&gt; 规则范围内活动。&lt;/li&gt;
&lt;li&gt;端口冲突需自行避免（容器与宿主机服务共享同一端口空间）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;非 Host 模式：
&lt;ul&gt;
&lt;li&gt;容器/进程拥有独立 IP（来自 bridge/maclvan 网络），与宿主机通过 NAT（&lt;code&gt;-p&lt;/code&gt; 端口映射）或路由互通。&lt;/li&gt;
&lt;li&gt;端口映射通常通过 &lt;code&gt;iptables&lt;/code&gt; &lt;code&gt;nat&lt;/code&gt; 表 &lt;code&gt;PREROUTING/OUTPUT/POSTROUTING&lt;/code&gt; 完成；也可不经 NAT，直接在同一二层网络下互通（macvlan/ipvlan）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;3-xing-neng-ying-xiang&quot;&gt;3) 性能影响&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Host 模式：路径最短，无 &lt;code&gt;veth&lt;/code&gt;/bridge/NAT 额外开销，通常更低延迟与更高吞吐。避免 &lt;code&gt;conntrack&lt;/code&gt; 压力与 SNAT 代价，适合高 PPS/低延迟场景。&lt;/li&gt;
&lt;li&gt;非 Host 模式：存在 &lt;code&gt;veth&lt;/code&gt;、bridge、NAT/conntrack 等开销。若采用 &lt;code&gt;macvlan/ipvlan&lt;/code&gt; 且不经 NAT，性能介于 Host 与 bridge+NAT 之间。开启/关闭网卡与栈的硬件卸载（GRO/LRO/TSO）也会影响实际性能。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;4-an-quan-xing&quot;&gt;4) 安全性&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Host 模式：安全性较低。进程/容器可访问宿主机网络栈（包含 &lt;code&gt;lo&lt;/code&gt;），宿主机 &lt;code&gt;INPUT/OUTPUT&lt;/code&gt; 规则直接影响容器，容器误配置更易影响全机网络。&lt;/li&gt;
&lt;li&gt;非 Host 模式：命名空间隔离更强，可在容器 netns 内单独维护 &lt;code&gt;iptables&lt;/code&gt;，并在宿主机上通过 &lt;code&gt;FORWARD&lt;/code&gt; 与 bridge 接口集中治理。适合多租户、严格边界控制与网络策略（NetworkPolicy）场景。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;5-shi-yong-chang-jing&quot;&gt;5) 使用场景&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Host 模式：
&lt;ul&gt;
&lt;li&gt;需要极致网络性能与最低延迟的服务（如负载均衡、数据面代理、主机级监控代理如 &lt;code&gt;node_exporter&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;必须直接绑定宿主机地址的守护进程（如监听 &lt;code&gt;:80/:443&lt;/code&gt; 的反向代理）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;非 Host 模式：
&lt;ul&gt;
&lt;li&gt;多租户隔离、零信任分段、需精细网络策略与审计的微服务集群。&lt;/li&gt;
&lt;li&gt;需要不同 IP/路由域的服务编排，简化冲突管理与迁移。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;6-pei-zhi-shi-li&quot;&gt;6) 配置示例&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Docker&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Host 模式：&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 容器共享宿主机网络命名空间，无端口映射&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; run --rm --network host --name svc-host-mode&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;  -e ENV=prod myimage:latest&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;Bridge（非 Host）模式：&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 默认 bridge，容器独立 netns + veth；通过 -p 进行端口映射（NAT）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; run --rm --name svc-bridge -p 8080:80 myimage:latest&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;Macvlan（非 Host）模式：&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 宿主机与容器处于同一二层域，无需 NAT；更接近物理直连，仍具命名空间隔离&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; network create -d macvlan&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;  --subnet=192.168.10.0/24 --gateway=192.168.10.1&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;  -o parent=eth0 macvlan_net&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; run --rm --network macvlan_net --name svc-macvlan myimage:latest&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Kubernetes&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Host 网络：&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;apiVersion&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; v1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;kind&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; Pod&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;metadata&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;  name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; svc-host-net&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;spec&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;  hostNetwork&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  # 直接加入宿主机 netns&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;  containers&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    -&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; app&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;      image&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; myimage:latest&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;      ports&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        -&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; containerPort&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 8080&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  # 注意与宿主机端口冲突&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;非 Host（由 CNI 提供隔离网络）：&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;apiVersion&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; v1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;kind&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; Pod&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;metadata&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;  name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; svc-bridge-net&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;spec&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;  containers&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    -&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; app&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;      image&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; myimage:latest&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;      ports&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        -&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; containerPort&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 80&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 通过 Service/Ingress 暴露，底层常见为 veth+bridge，必要时经 NAT。&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;手动 netns（Linux 原生）&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 创建独立网络命名空间，配置 veth 与 bridge（非 Host）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;ip&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; netns add ns1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;ip&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; link add veth-host type veth peer name veth-ns1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;ip&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; link set veth-ns1 netns ns1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 宿主机侧创建 bridge 并加入 veth-host&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;ip&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; link add name br0 type bridge&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;ip&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; link set veth-host master br0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;ip&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; link set br0 up&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;ip&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; link set veth-host up&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 命名空间内配置 IP 与默认路由&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;ip&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; netns exec ns1 ip addr add 10.10.0.2/24 dev veth-ns1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;ip&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; netns exec ns1 ip link set veth-ns1 up&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;ip&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; netns exec ns1 ip route add default via&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10.10.0.1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 宿主机为 br0 配置地址作为网关&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;ip&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; addr add 10.10.0.1/24 dev br0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 出站上网的 NAT（示例）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -t nat -A POSTROUTING -s 10.10.0.0/24 -o eth0 -j MASQUERADE&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;7-yu-iptables-ipset-tc-de-ji-cheng-chai-yi&quot;&gt;7) 与 iptables/ipset/tc 的集成差异&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Host 模式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;iptables&lt;/code&gt;：容器进程经过宿主机 &lt;code&gt;OUTPUT/INPUT&lt;/code&gt;（本机出入站）与 &lt;code&gt;FORWARD&lt;/code&gt;（转发场景）。可直接在宿主机使用 &lt;code&gt;-m cgroup&lt;/code&gt;/&lt;code&gt;-m set&lt;/code&gt; 做准入与标记。&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 结合 cgroup + ipset，按进程与目标集合做标记与限速&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -t mangle -A OUTPUT -m cgroup --cgroup&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0x00010010&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;  -m set --match-set restricted dst -j MARK --set-mark&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0x3&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tc&lt;/code&gt;：建议在实际出站接口（如 &lt;code&gt;eth0&lt;/code&gt;）布置队列与过滤器，&lt;code&gt;cgroup&lt;/code&gt; 过滤器可直接匹配该进程的 &lt;code&gt;classid&lt;/code&gt;。&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; qdisc add dev eth0 root handle 1: htb default&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 30&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; class add dev eth0 parent 1: classid 1:10 htb rate 10mbit ceil 10mbit&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; filter add dev eth0 parent 1: protocol ip prio&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 20&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; cgroup flowid 1:10&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;非 Host 模式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;iptables&lt;/code&gt;：容器流量经 &lt;code&gt;veth&lt;/code&gt; 进入宿主机 bridge，一般走 &lt;code&gt;FORWARD&lt;/code&gt; 链与 &lt;code&gt;nat&lt;/code&gt;。可在宿主机匹配 &lt;code&gt;-i vethX&lt;/code&gt;/bridge 端口，或进入容器 netns 内单独维护防火墙。&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 宿主机上按容器 veth 接口做访问限制（示例）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A FORWARD -i vethXYZ -m set --match-set restricted dst -j DROP&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tc&lt;/code&gt;：可以选择在容器 &lt;code&gt;eth0&lt;/code&gt;（命名空间内）、宿主机 veth 对端或 bridge 设备上布置队列与过滤器；若使用 &lt;code&gt;cgroup&lt;/code&gt; 过滤器，仍可匹配由 &lt;code&gt;net_cls&lt;/code&gt; 标记的套接字，但需确保过滤器挂载在实际经过的数据路径设备上。&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 示例：对宿主机 veth 对端做限速（假设设备名 veth-host）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; qdisc add dev veth-host root handle 1: htb default&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 30&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; class add dev veth-host parent 1: classid 1:10 htb rate 5mbit ceil 5mbit&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; filter add dev veth-host parent 1: protocol ip prio&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 20&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; cgroup flowid 1:10&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 或在 bridge 设备上按流分类（可结合 flower/iptables 标记）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; qdisc add dev br0 root handle 1: htb default&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 30&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; filter add dev br0 ingress prio&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; flower skip_sw&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;  dst_ip 203.0.113.0/24 action drop&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;8-shi-ji-zhu-yi-shi-xiang&quot;&gt;8) 实际注意事项&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;端口与地址：Host 模式需要避免端口冲突与误监听（容器监听 &lt;code&gt;127.0.0.1&lt;/code&gt; 即为宿主机回环）。非 Host 模式建议通过 Service/Ingress 或明确路由暴露服务。&lt;/li&gt;
&lt;li&gt;策略边界：非 Host 模式可在容器 netns 内单独维护 &lt;code&gt;iptables/ipset&lt;/code&gt;，并在宿主机通过 &lt;code&gt;FORWARD&lt;/code&gt; 与 bridge 汇总治理；Host 模式建议统一在宿主机层做分段与速率控制。&lt;/li&gt;
&lt;li&gt;性能与可靠性：
&lt;ul&gt;
&lt;li&gt;关注 &lt;code&gt;conntrack&lt;/code&gt; 容量与哈希：非 Host NAT 场景下可调 &lt;code&gt;nf_conntrack_max&lt;/code&gt; 与 &lt;code&gt;hashsize&lt;/code&gt;，避免高并发丢包。&lt;/li&gt;
&lt;li&gt;选择合适队列算法：&lt;code&gt;fq_codel/cake&lt;/code&gt; 抑制 Bufferbloat；HTB 做带宽层次管理。&lt;/li&gt;
&lt;li&gt;评估硬件卸载与 GRO/LRO/TSO 开关对延迟/CPU 的影响。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;兼容性：Kubernetes &lt;code&gt;hostNetwork: true&lt;/code&gt; 与 CNI/NetworkPolicy 的交互因实现而异，需结合具体 CNI 文档验证策略是否仍生效或需要例外规则。&lt;/li&gt;
&lt;li&gt;持久化与编排：在主机用 systemd unit/开机脚本持久化 &lt;code&gt;iptables/tc&lt;/code&gt;；容器场景可在入口脚本中执行 netns 内规则，或使用宿主机守护进程监听容器生命周期事件同步策略。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;ji-ben-gai-nian-yu-gong-zuo-yuan-li&quot;&gt;基本概念与工作原理&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;cgroups（控制组）用于按进程维度进行资源隔离与配额管理。网络相关的两个传统控制器：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;net_cls&lt;/code&gt;（v1）：为所属 cgroup 的进程产生的网络包打上 32 位 &lt;code&gt;classid&lt;/code&gt;（位于 &lt;code&gt;skb-&amp;gt;priority&lt;/code&gt;），用于后续在 &lt;code&gt;tc&lt;/code&gt; 中以 &lt;code&gt;cgroup&lt;/code&gt; 过滤器分类，或在 iptables 以 &lt;code&gt;-m cgroup&lt;/code&gt; 匹配。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;net_prio&lt;/code&gt;（v1）：按接口为 socket 设置优先级（较少使用）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;cgroup v2 差异：统一层级中不再包含 &lt;code&gt;net_cls/net_prio&lt;/code&gt; 控制器。现代内核推荐用 BPF（如 &lt;code&gt;tc&lt;/code&gt; eBPF + &lt;code&gt;clsact&lt;/code&gt;，或 cgroup-bpf 钩子）实现按进程/服务的网络分类与策略。本文以 v1 &lt;code&gt;net_cls&lt;/code&gt; 为主，并给出 v2 的替代思路。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ASCII 流程示意：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[Process in cgroup] --(net_cls: classid)--&amp;gt; [skb-&amp;gt;priority]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        |                                  |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        |                             tc filter cgroup -&amp;gt; class&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        v                                  v&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     iptables -m cgroup              HTB/FQ-CoDel shaping&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;pei-zhi-bu-zou-yu-ming-ling-shi-li-cgroup-v1-net-cls&quot;&gt;配置步骤与命令示例（cgroup v1 net_cls）&lt;/h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 1) 挂载 net_cls（若系统未自动挂载）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; mkdir -p /sys/fs/cgroup/net_cls&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; mount -t cgroup -o net_cls none /sys/fs/cgroup/net_cls&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 2) 创建 cgroup 并设置 classid（示例：0x00010010）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; mkdir -p /sys/fs/cgroup/net_cls/restricted_svc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0x00010010&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; sudo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; tee /sys/fs/cgroup/net_cls/restricted_svc/net_cls.classid&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 3) 将进程加入该 cgroup（两种方式）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 3.1 直接写入 cgroup.procs（PID 示例：12345）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 12345&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; sudo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; tee /sys/fs/cgroup/net_cls/restricted_svc/cgroup.procs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 3.2 通过 cgexec 启动进程（需安装 libcgroup 工具）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; cgexec -g net_cls:restricted_svc /usr/bin/my-service --opts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 4) 验证 classid 是否生效（可通过 tc/iptables 计数或 ss 观察）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# tc/iptables 命中计数将用于验证（见下文集成章节）&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;说明与建议：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;classid&lt;/code&gt; 为 32 位，常用高 16 位表示主类、低 16 位表示子类，便于分层管理。&lt;/li&gt;
&lt;li&gt;systemd 环境下也可按服务/切片组织进程，但 net_cls 赋值仍需在对应 cgroup 路径设置。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;yu-iptables-ipset-tc-de-ji-cheng-shi-yong&quot;&gt;与 iptables、ipset、tc 的集成使用&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;tc（按 cgroup 分类到限速类）&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 在 eth0 已创建的 HTB 根队列下，增加 cgroup 过滤器&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; tc filter add dev eth0 parent 1: protocol ip prio&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 20&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; cgroup flowid 1:10&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 说明：将属于 cgroup 的进程产生的流量导向 class 1:10（限速类）&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;iptables（匹配 cgroup 并打标/过滤）&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 将本机进程的 egress/OUTPUT 流量按 cgroup classid 匹配并设置 MARK=0x3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; iptables -t mangle -A OUTPUT -m cgroup --cgroup&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0x00010010&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -j MARK --set-mark&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0x3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 可结合 filter 表进行准入控制（如仅允许 80/443）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; iptables -A OUTPUT -p tcp -m cgroup --cgroup&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0x00010010&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -m multiport --dports 80,443 -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; iptables -A OUTPUT -p tcp -m cgroup --cgroup&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0x00010010&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -j DROP&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;与 ipset 组合（进程 + 目的 IP 集合的双重约束）&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 仅当进程属于 cgroup 且目的地址在 restricted_clients 集合时打标/限速&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; iptables -t mangle -A OUTPUT -m cgroup --cgroup&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0x00010010&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;  -m set --match-set restricted_clients dst -j MARK --set-mark&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0x1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# tc 侧继续用 fw/cgroup filter 将标记或 cgroup 流量导向限速类&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;方向选择与注意：
&lt;ul&gt;
&lt;li&gt;进程级匹配更适合本机 egress（&lt;code&gt;OUTPUT&lt;/code&gt;）策略；&lt;code&gt;PREROUTING&lt;/code&gt;/转发链不一定能关联本机进程。&lt;/li&gt;
&lt;li&gt;结合现有“按 IP 集合限速”的方案，可通过 cgroup 将本机服务与离线任务区分，避免彼此影响。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;ying-yong-chang-jing-yu-zui-jia-shi-jian&quot;&gt;应用场景与最佳实践&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;按服务/作业限速：将备份、日志上传、离线批处理进程放入 cgroup，限制其带宽与队列优先级，保障交互服务。&lt;/li&gt;
&lt;li&gt;多租户主机：不同服务（租户）映射不同 &lt;code&gt;classid&lt;/code&gt;，在 HTB 下分配独立通道与速率上限。&lt;/li&gt;
&lt;li&gt;与 IP 集合协同：对外访问仍基于 ipset 管理名单；对内按进程（cgroup）区分业务类型，实现“谁访问 + 访问哪里”的双维管控。&lt;/li&gt;
&lt;li&gt;命名与映射规范：约定 &lt;code&gt;classid&lt;/code&gt; 与 HTB &lt;code&gt;classid&lt;/code&gt; 有一致映射（如 0x00010010 -&amp;gt; 1:10），便于运维与审计。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;xing-neng-diao-you-jian-yi-yu-zhu-yi-shi-xiang&quot;&gt;性能调优建议与注意事项&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;队列算法：为 cgroup 对应的类使用 &lt;code&gt;fq_codel&lt;/code&gt; 或 &lt;code&gt;cake&lt;/code&gt;，降低排队延迟与抖动。&lt;/li&gt;
&lt;li&gt;过滤器优先级：合理设置 &lt;code&gt;prio&lt;/code&gt;，确保 cgroup/mark 过滤器早匹配；避免过多 &lt;code&gt;u32&lt;/code&gt; 复杂匹配。&lt;/li&gt;
&lt;li&gt;监控与验证：使用 &lt;code&gt;tc -s class/qdisc show&lt;/code&gt; 与 &lt;code&gt;iptables -vnL&lt;/code&gt; 观察命中计数，定期复核 &lt;code&gt;cgroup.procs&lt;/code&gt; 中的进程是否符合预期。&lt;/li&gt;
&lt;li&gt;兼容性：
&lt;ul&gt;
&lt;li&gt;需要内核模块支持：&lt;code&gt;sch_htb&lt;/code&gt;、&lt;code&gt;sch_fq_codel&lt;/code&gt;、&lt;code&gt;cls_fw&lt;/code&gt;、&lt;code&gt;cls_cgroup&lt;/code&gt;、&lt;code&gt;xt_set&lt;/code&gt;、&lt;code&gt;xt_cgroup&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;cgroup v2 环境建议评估 BPF 方案（&lt;code&gt;tc qdisc add dev eth0 clsact&lt;/code&gt; + &lt;code&gt;tc filter add ... bpf&lt;/code&gt;），实现更灵活的按进程/Socket 分类。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;持久化：将 cgroup 挂载、classid 设置与 tc/iptables 规则固化为开机脚本或 systemd unit，确保重启后生效。&lt;/li&gt;
&lt;li&gt;安全与隔离：严格控制写入 &lt;code&gt;cgroup.procs&lt;/code&gt; 的权限，防止误归类；为高风险作业单独 cgroup 并限制资源上限（CPU/IO 也可结合）。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h1 id=&quot;zhu-yi-shi-xiang-yu-pai-cha&quot;&gt;注意事项与排查&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;操作前备份与回滚&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;备份规则：&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables-save&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /etc/iptables/rules.v4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;ipset&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; save&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /etc/ipset.conf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;恢复规则：&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables-restore&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /etc/iptables/rules.v4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;ipset&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; restore&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /etc/ipset.conf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;持久化方法（随发行版而异）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Debian/Ubuntu：安装 &lt;code&gt;iptables-persistent&lt;/code&gt; 或 &lt;code&gt;netfilter-persistent&lt;/code&gt;，保存于 &lt;code&gt;/etc/iptables/rules.v4&lt;/code&gt;、&lt;code&gt;/etc/ipset.conf&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;RHEL/CentOS：使用 &lt;code&gt;service iptables save&lt;/code&gt; 或结合 firewalld/nftables 转写；注意 iptables-nft 与 iptables-legacy 差异&lt;/li&gt;
&lt;li&gt;tc：通常以脚本（systemd unit）在启动时应用，或借助 NetworkManager/ifup 触发&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;常见问题排查&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;标记未生效：检查 &lt;code&gt;mangle&lt;/code&gt; 表规则计数；确认 &lt;code&gt;MARK&lt;/code&gt; 置位在 &lt;code&gt;PREROUTING&lt;/code&gt;/&lt;code&gt;OUTPUT&lt;/code&gt; 的正确方向&lt;/li&gt;
&lt;li&gt;tc 过滤无匹配：确认 &lt;code&gt;fw filter handle&lt;/code&gt; 与 iptables 标记一致；检查过滤器挂载的设备（egress 对应出口设备）&lt;/li&gt;
&lt;li&gt;入口限速未起效：是否使用 &lt;code&gt;ifb&lt;/code&gt; 重定向；&lt;code&gt;ingress qdisc&lt;/code&gt; 默认只统计不整形&lt;/li&gt;
&lt;li&gt;nftables 兼容：现代系统默认 iptables-nft，语义兼容但内部实现不同；大规模规则建议评估直接迁移到 nftables&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h1 id=&quot;zong-jie&quot;&gt;总结&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;使用 ipset 管理名单，iptables 做准入与打标，tc 做速率与队列管理，是兼顾简单、性能与可维护性的组合&lt;/li&gt;
&lt;li&gt;建议以“标记驱动分类”的模式组织规则，保持早打标、少匹配、设备维度清晰&lt;/li&gt;
&lt;li&gt;推行脚本化与持久化，确保在重启、变更或回滚时可控可复现&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;参考链接：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;iptables 文档：https://netfilter.org/&lt;/li&gt;
&lt;li&gt;ipset 手册：https://ipset.netfilter.org/&lt;/li&gt;
&lt;li&gt;tc 与 qdisc：https://man7.org/linux/man-pages/man8/tc.8.html&lt;/li&gt;
&lt;li&gt;FQ-CoDel：https://www.bufferbloat.net/projects/codel/wiki/&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Apache DolphinScheduler 二次开发技术手册</title>
        <published>2025-10-25T00:00:00+00:00</published>
        <updated>2025-10-25T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/apache-dolphinscheduler-secondary-development-handbook/"/>
        <id>https://scp.net.cn/blog/apache-dolphinscheduler-secondary-development-handbook/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/apache-dolphinscheduler-secondary-development-handbook/">&lt;h1 id=&quot;1-xiang-mu-jie-shao&quot;&gt;1. 项目介绍&lt;/h1&gt;
&lt;p&gt;Apache DolphinScheduler 是一款面向数据工程的现代化工作流编排平台，支持通过 Web 可视化拖拽构建复杂的依赖拓扑，具备高可用与高性能的分布式架构，提供丰富的内置任务类型（Shell、Python、Spark、Flink、HTTP、SQL 等），并支持跨云与多数据中心编排。&lt;a rel=&quot;external&quot; href=&quot;https://github.com/apache/dolphinscheduler&quot;&gt;参考：GitHub 项目主页&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;核心功能：工作流定义与版本管理、任务编排与重试、定时调度、资源中心、告警与权限、多租户与项目隔离。&lt;/li&gt;
&lt;li&gt;架构设计：去中心化多 Master/Worker 架构，基于队列/注册中心的调度协调，任务类型采用插件化机制，UI 前后端分离。&lt;/li&gt;
&lt;li&gt;主要场景：数据集成、ETL/ELT、机器学习训练与部署流水线、跨系统批任务编排。&lt;/li&gt;
&lt;li&gt;技术特点：高并发调度、水平扩展、插件化任务/告警通道、开放 API 与 SDK、K8s/容器化支持。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;示意架构（简化）：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+-----------+      +----------+      +-----------+&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;|   UI/API  | ---&amp;gt; |  Master  | ---&amp;gt; |   Worker  |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+-----------+      +----------+      +-----------+&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      |                 |                   |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      v                 v                   v&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   Metadata         Queue/ZK             Task Plugins&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (MySQL/PG)    (Coordination)         (Shell/SQL/...)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&quot;2-kai-fa-huan-jing-da-jian&quot;&gt;2. 开发环境搭建&lt;/h1&gt;
&lt;p&gt;软硬件要求（建议值）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;OS：macOS/Linux（x86_64/arm64）&lt;/li&gt;
&lt;li&gt;JDK：Java 8/11（开发者常用 11）&lt;/li&gt;
&lt;li&gt;构建：Maven 3.6+，Node.js 16+/npm 或 pnpm（前端），Git&lt;/li&gt;
&lt;li&gt;中间件：MySQL/PG、ZooKeeper（或注册服务）、可选：Docker/K8s&lt;/li&gt;
&lt;li&gt;资源：8GB+ 内存，20GB+ 磁盘&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;配置步骤：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;安装 JDK 与 Maven，并设置 &lt;code&gt;JAVA_HOME&lt;/code&gt;、&lt;code&gt;MAVEN_HOME&lt;/code&gt; 与 &lt;code&gt;PATH&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;安装 Node.js 与 npm（用于构建前端 UI）。&lt;/li&gt;
&lt;li&gt;准备数据库（MySQL/PG）与用户；初始化 DolphinScheduler 元数据（参考官方文档）。&lt;/li&gt;
&lt;li&gt;获取源代码：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# 拉取源码&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;git clone https://github.com/apache/dolphinscheduler.git&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cd dolphinscheduler&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# 构建后端（跳过测试可加快首次构建）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;mvn -Prelease -DskipTests clean package&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# 构建前端 UI（不同版本可能已集成到 Maven）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cd dolphinscheduler-ui&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;npm install &amp;amp;&amp;amp; npm run build&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;本地快速体验（不同版本命令略有差异）：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Standalone/本地启动示例（参考官方 quickstart）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# 部署包生成后进入 bin 目录&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;./bin/dolphinscheduler-daemon.sh start master-server&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;./bin/dolphinscheduler-daemon.sh start worker-server&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;./bin/dolphinscheduler-daemon.sh start api-server&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&quot;3-er-ci-kai-fa-zhi-nan&quot;&gt;3. 二次开发指南&lt;/h1&gt;
&lt;p&gt;核心模块与扩展点（以 3.x 为例）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Server 层：Master（调度协调）、Worker（任务执行）、API（接口与权限）。&lt;/li&gt;
&lt;li&gt;Task 插件：通过 SPI/插件机制扩展任务类型（自定义 TaskChannel/Factory）。&lt;/li&gt;
&lt;li&gt;Alert 插件：扩展告警渠道（邮件、钉钉、飞书、企业微信、Webhook 等）。&lt;/li&gt;
&lt;li&gt;Resource/Storage：交互资源中心（脚本、UDF、队列、数据源适配）。&lt;/li&gt;
&lt;li&gt;UI 扩展：前端新增任务表单字段、类型图标与配置联动。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;自定义任务类型示例（伪代码，展示结构）：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 依赖：实现任务插件工厂与执行器，按版本对应接口命名可能不同&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;public class&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; HttpTaskChannelFactory&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; implements&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;font-weight: bold;&quot;&gt; TaskChannelFactory&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  @&lt;/span&gt;&lt;span style=&quot;color: #D08770;&quot;&gt;Override&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  public&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; String&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; getName&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;() {&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;HTTP&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  @&lt;/span&gt;&lt;span style=&quot;color: #D08770;&quot;&gt;Override&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  public&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; TaskChannel&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; create&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;() {&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; HttpTaskChannel&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;public class&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; HttpTaskChannel&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; implements&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;font-weight: bold;&quot;&gt; TaskChannel&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  @&lt;/span&gt;&lt;span style=&quot;color: #D08770;&quot;&gt;Override&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  public&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; TaskExecutor&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; createExecutor&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;TaskExecutionContext&lt;/span&gt;&lt;span&gt; ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; HttpTaskExecutor&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;public class&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; HttpTaskExecutor&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; extends&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;font-weight: bold;&quot;&gt; AbstractTaskExecutor&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  public&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; HttpTaskExecutor&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;TaskExecutionContext&lt;/span&gt;&lt;span&gt; ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; super&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  @&lt;/span&gt;&lt;span style=&quot;color: #D08770;&quot;&gt;Override&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  public void&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; handle&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;TaskExecutionContext&lt;/span&gt;&lt;span&gt; ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; throws&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Exception&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 从上下文读取参数（URL、Method、Headers、Body 等）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    String&lt;/span&gt;&lt;span&gt; url&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getTaskParams&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;url&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 调用 HTTP 客户端执行，写入日志与结果&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    int&lt;/span&gt;&lt;span&gt; code&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; HttpClient&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;post&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getTaskParams&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;())&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;code &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 200&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; throw new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; RuntimeException&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;HTTP task failed&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注册与打包：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;将自定义插件模块按项目约定放入 &lt;code&gt;dolphinscheduler-*-plugin&lt;/code&gt; 目录，并在 &lt;code&gt;pom.xml&lt;/code&gt; 中声明。&lt;/li&gt;
&lt;li&gt;按需使用 &lt;code&gt;META-INF/services&lt;/code&gt; 或注解方式（例如 AutoService）注册接口实现。&lt;/li&gt;
&lt;li&gt;在 UI 中为新任务类型增加表单与校验，API 增加参数映射。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;自定义告警通道示例（伪代码）：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;public class&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; FeishuAlertChannel&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; implements&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;font-weight: bold;&quot;&gt; AlertChannel&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  @&lt;/span&gt;&lt;span style=&quot;color: #D08770;&quot;&gt;Override&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  public&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; AlertResult&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; send&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;AlertInfo&lt;/span&gt;&lt;span&gt; info&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 将告警内容组装成消息卡片，调用飞书 Webhook&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    String&lt;/span&gt;&lt;span&gt; webhook&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; info&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getProps&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;webhook&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; HttpClient&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;jsonPost&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;webhook&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; info&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;toJson&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;())&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;常见扩展场景：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;新增任务类型（如：自研服务调用、特定数据源同步）。&lt;/li&gt;
&lt;li&gt;增强执行策略（超时、自定义重试、幂等保障）。&lt;/li&gt;
&lt;li&gt;接入企业统一告警与审计平台。&lt;/li&gt;
&lt;li&gt;扩展资源中心（版本化脚本、集中密钥/凭据管理）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;4-zui-jia-shi-jian&quot;&gt;4. 最佳实践&lt;/h1&gt;
&lt;p&gt;经验与教训：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;与生产环境隔离：先在独立项目/租户验证插件，再灰度到生产。&lt;/li&gt;
&lt;li&gt;参数与密钥：通过环境变量/凭据管理，不把密钥写入任务参数。&lt;/li&gt;
&lt;li&gt;可观测性：统一日志格式、关联 traceId，收敛告警风暴。&lt;/li&gt;
&lt;li&gt;版本管理：任务与工作流版本化，保持脚本与镜像可复现。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;性能优化：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Master/Worker 水平扩展，合理分配队列与并发度。&lt;/li&gt;
&lt;li&gt;使用批量与异步 IO 的任务实现，减少阻塞。&lt;/li&gt;
&lt;li&gt;避免热点资源争用，拆分长链路任务，利用子工作流与并行化。&lt;/li&gt;
&lt;li&gt;调整心跳与容错参数，降低无效重试与频繁超时。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;安全加固：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;细化权限与租户边界，限制高危任务类型的使用范围。&lt;/li&gt;
&lt;li&gt;审计与合规：记录关键操作轨迹，敏感参数脱敏。&lt;/li&gt;
&lt;li&gt;插件白名单与代码扫描（SAST/DAST），发布前强制检查。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;系统集成：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;通过 OpenAPI/SDK 将编排作为外部系统的“控制面”。&lt;/li&gt;
&lt;li&gt;事件驱动集成：任务完成事件推送到消息总线触发下游流程。&lt;/li&gt;
&lt;li&gt;与数据源平台/元数据中心打通，实现任务参数与血缘的自动化维护。&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;5-ce-shi-yu-bu-shu&quot;&gt;5. 测试与部署&lt;/h1&gt;
&lt;p&gt;测试方法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;单元测试：任务/告警插件核心逻辑的快速覆盖。&lt;/li&gt;
&lt;li&gt;集成测试：模拟 Master/Worker 的调度与执行链路（本地 Docker Compose）。&lt;/li&gt;
&lt;li&gt;UI 测试：表单校验与交互流程（Cypress/Playwright）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;部署方案：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;传统部署：多 Master/Worker + API，数据库高可用，ZooKeeper 集群。&lt;/li&gt;
&lt;li&gt;容器化：K8s + Helm Chart，使用 HPA 与亲和/反亲和策略。&lt;/li&gt;
&lt;li&gt;升级策略：先扩展新版本旁路节点，完成数据迁移与兼容验证后切流。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;贡献社区：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;遵循 Apache 规范（版权头、License、DCO），代码风格与 Checkstyle。&lt;/li&gt;
&lt;li&gt;提交 PR 前：补充文档、测试用例与变更说明，关联 Issue。&lt;/li&gt;
&lt;li&gt;与社区沟通：邮件列表/Slack，善用“good first issue”。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;参考资料与延伸阅读：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Apache DolphinScheduler GitHub：https://github.com/apache/dolphinscheduler&lt;/li&gt;
&lt;li&gt;官方文档与 QuickStart（不同版本入口可能不同，请以官方文档为准）&lt;/li&gt;
&lt;li&gt;Helm Chart 与 K8s 部署示例（社区维护）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本文示例代码为演示结构，具体接口与包名以对应版本的官方源码与文档为准。&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Apache Flink 任务性能调优实践手册</title>
        <published>2025-10-25T00:00:00+00:00</published>
        <updated>2025-10-25T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/apache-flink-performance-tuning-practice/"/>
        <id>https://scp.net.cn/blog/apache-flink-performance-tuning-practice/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/apache-flink-performance-tuning-practice/">&lt;h1 id=&quot;ji-shu-bei-jing-jie-shao&quot;&gt;技术背景介绍&lt;/h1&gt;
&lt;p&gt;Apache Flink 是一款面向有状态流处理的分布式计算引擎，支持事件时间、Exactly-Once 语义、复杂窗口与跨算子状态管理。生产环境中常见的性能问题包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;吞吐达不到预期（TPS 低、CPU 空闲）&lt;/li&gt;
&lt;li&gt;延迟波动大（水位推进慢、Checkpoint 阻塞）&lt;/li&gt;
&lt;li&gt;反压频繁（上游等待下游、网络缓冲耗尽）&lt;/li&gt;
&lt;li&gt;数据倾斜（热点 key 导致局部算子过载）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;原理示意（简化）：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Source --&amp;gt; Map/FlatMap --&amp;gt; KeyBy --&amp;gt; Window/Aggregate --&amp;gt; Sink&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;           | 状态读写 | 反压传播 | Checkpoint 对齐&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&quot;he-xin-you-hua-fang-fa-lun&quot;&gt;核心优化方法论&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;资源匹配：并行度与槽位、内存与网络缓冲均衡，避免“过度/不足配置”。&lt;/li&gt;
&lt;li&gt;有状态算子优先：明确状态大小与访问模式（热/冷），选择合适状态后端与快照策略。&lt;/li&gt;
&lt;li&gt;反压治理：监控并切分重算子链路，必要时异步化与解耦 I/O。&lt;/li&gt;
&lt;li&gt;数据倾斜治理：发现热点 key，分片/双阶段聚合/路由重平衡。&lt;/li&gt;
&lt;li&gt;持续度量：以指标驱动（吞吐、延迟、背压、Checkpoint 时延大小），进行小步迭代优化。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;方法论图（简化）：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[监控指标] -&amp;gt; [定位瓶颈] -&amp;gt; [资源/参数/算子结构调整] -&amp;gt; [回归测试]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;           ^-----------------------------------------------|&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&quot;wen-ti-ding-wei-yu-fa-xian&quot;&gt;问题定位与发现&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;统一问题画像
&lt;ul&gt;
&lt;li&gt;类型归类：吞吐不足、延迟偏高、反压频繁、Checkpoint 卡顿、数据倾斜。&lt;/li&gt;
&lt;li&gt;影响面：端到端延迟、失败重试次数、恢复耗时（Savepoint/Checkpoint）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;观察入口
&lt;ul&gt;
&lt;li&gt;Flink Web UI：Job → Task → Subtask 指标页；BackPressure、Checkpoints、Watermarks。&lt;/li&gt;
&lt;li&gt;日志与线程栈：JM/TM/算子日志，&lt;code&gt;jstack&lt;/code&gt; 抓取阻塞位；Kafka Consumer Lag。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;算子链路画像
&lt;ul&gt;
&lt;li&gt;Operator Chain 识别热点算子（聚合/窗口/外部 I/O），梳理上下游依赖与分区策略。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;反压定位
&lt;ul&gt;
&lt;li&gt;关键指标：&lt;code&gt;backPressuredTimeMsPerSecond&lt;/code&gt;、&lt;code&gt;busyTimeMsPerSecond&lt;/code&gt;、&lt;code&gt;idleTimeMsPerSecond&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;诊断要点：某子任务 BackPressured 高且上游 Idle 高，通常下游算子是瓶颈。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Checkpoint 卡顿
&lt;ul&gt;
&lt;li&gt;关键指标：Checkpoint Duration/Alignment Time/Bytes；对齐时间在反压时显著升高。&lt;/li&gt;
&lt;li&gt;诊断要点：非对齐快照可降低对齐等待，但恢复时可能更耗缓冲与带宽。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;状态后端与存储
&lt;ul&gt;
&lt;li&gt;RocksDB：&lt;code&gt;state size&lt;/code&gt;、SST 文件数、写入放大、IO 读写耗时。&lt;/li&gt;
&lt;li&gt;HDFS/S3：快照目录吞吐与延迟，网络带宽与并发限制。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;快速排查清单（示例）：
&lt;ul&gt;
&lt;li&gt;BackPressure 高？→ 调整并行度/拆链/异步 I/O/缓冲超时。&lt;/li&gt;
&lt;li&gt;Checkpoint 慢？→ 缩小状态/增量快照/非对齐/存储通道优化。&lt;/li&gt;
&lt;li&gt;倾斜严重？→ 盐化键/双阶段聚合/重平衡分区。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;原理示意（简化）：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Metrics -&amp;gt; 定位瓶颈 -&amp;gt; 假设与改动 -&amp;gt; 回归验证&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;         ^-------------------------------|&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&quot;he-xin-jian-kong-zhi-biao-xiang&quot;&gt;核心监控指标项&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;吞吐与延迟
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;numRecordsInPerSecond&lt;/code&gt; / &lt;code&gt;numRecordsOutPerSecond&lt;/code&gt;：核心吞吐；推荐稳定无大幅锯齿。&lt;/li&gt;
&lt;li&gt;端到端延迟（业务埋点/外部监控）：p95 建议 &amp;lt; 500ms（低延迟场景）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;资源与反压
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;busy/backPressured/idle Time&lt;/code&gt;：忙/压/闲三角。推荐 BackPressured &amp;lt; 10%，Busy 60–85%。&lt;/li&gt;
&lt;li&gt;CPU/Heap/GC：YoungGC 时间占比 &amp;lt; 10%，FullGC 次数≈0；Heap 使用 60–80%。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;网络缓冲
&lt;ul&gt;
&lt;li&gt;缓冲利用率与积压：稳定中位为佳，极端高位抖动需检查下游消费能力。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bufferTimeout&lt;/code&gt;：5–50ms；过小导致协议开销、过大增延迟。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Checkpoint
&lt;ul&gt;
&lt;li&gt;Duration：建议均值 &amp;lt; 2s（视状态量调整）；Alignment 在反压时显著增长。&lt;/li&gt;
&lt;li&gt;并发与间隔：&lt;code&gt;maxConcurrent=1&lt;/code&gt; + &lt;code&gt;minPause=2s&lt;/code&gt;，间隔 3–10s。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;状态后端（RocksDB）
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;state size&lt;/code&gt;、SST 数量、Block Cache 命中率、写入阻塞（write stall）。&lt;/li&gt;
&lt;li&gt;本地 SSD 优先，托管内存比例 0.3–0.5。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Source/Sink 外部系统
&lt;ul&gt;
&lt;li&gt;Kafka Consumer Lag 接近 0；Sink 端限流与批量参数需与外部系统一致。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;注意：指标需结合业务 SLA、数据分布与链路结构评估，推荐值为经验范围，实际以回归测试与压测结果为准。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&quot;ju-ti-diao-you-can-shu-pei-zhi&quot;&gt;具体调优参数配置&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;任务并行度与槽位
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;env.setParallelism(n)&lt;/code&gt;：总并行度 ≈ &lt;code&gt;taskManagers × slotsPerTM&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;推荐范围：每个 TaskManager &lt;code&gt;slots&lt;/code&gt; 2–8（结合 CPU 核心与业务算子权重）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;网络缓冲（低延迟与稳态）
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;taskmanager.network.memory.fraction=0.12&lt;/code&gt;（推荐 0.1–0.2）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;taskmanager.network.memory.min=64mb&lt;/code&gt;，&lt;code&gt;taskmanager.network.memory.max=1gb&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ExecutionConfig#setBufferTimeout(5)&lt;/code&gt; 或 &lt;code&gt;env.getConfig().setAutoWatermarkInterval(...)&lt;/code&gt;，缓冲 5–50ms 平衡吞吐与延迟&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;内存模型（Flink 新内存模型）
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;taskmanager.memory.process.size=4096m&lt;/code&gt;（按容器配额）&lt;/li&gt;
&lt;li&gt;RocksDB 状态后端建议启用托管内存：&lt;code&gt;taskmanager.memory.managed.fraction=0.4&lt;/code&gt;（0.3–0.5）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Checkpoint 参数
&lt;ul&gt;
&lt;li&gt;间隔：&lt;code&gt;env.enableCheckpointing(5000)&lt;/code&gt;（3–10s）&lt;/li&gt;
&lt;li&gt;模式：&lt;code&gt;EXACTLY_ONCE&lt;/code&gt;（大多数场景），必要时 &lt;code&gt;AT_LEAST_ONCE&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;对齐优化：启用“非对齐快照”以减轻反压时阻塞（版本支持见下节）&lt;/li&gt;
&lt;li&gt;并发：&lt;code&gt;setMaxConcurrentCheckpoints(1)&lt;/code&gt;（避免堆积），&lt;code&gt;setMinPauseBetweenCheckpoints(2000)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;超时：&lt;code&gt;setCheckpointTimeout(60000)&lt;/code&gt;（30–120s）&lt;/li&gt;
&lt;li&gt;外部化：&lt;code&gt;enableExternalizedCheckpoints(RETAIN_ON_CANCELLATION)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;状态后端与快照
&lt;ul&gt;
&lt;li&gt;小状态/低延迟：内存（HashMapStateBackend/旧 MemoryStateBackend）&lt;/li&gt;
&lt;li&gt;大状态/落盘可靠：RocksDBStateBackend + 增量快照（提升快照与恢复效率）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;ke-luo-di-de-pei-zhi-shi-li&quot;&gt;可落地的配置示例&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;典型优化配置示例（Flink ≤ 1.12 常见写法）：&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 典型优化配置示例（&amp;lt;=1.12）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;final&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; StreamExecutionEnvironment&lt;/span&gt;&lt;span&gt; env&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; StreamExecutionEnvironment&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getExecutionEnvironment&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;env&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;setParallelism&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 启用 Exactly-Once 快照，每 5s&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;env&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;enableCheckpointing&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;5000&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; CheckpointingMode&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;EXACTLY_ONCE&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;CheckpointConfig&lt;/span&gt;&lt;span&gt; cfg&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; env&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getCheckpointConfig&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cfg&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;setMinPauseBetweenCheckpoints&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;2000&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cfg&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;setCheckpointTimeout&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;60000&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cfg&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;setMaxConcurrentCheckpoints&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cfg&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;enableExternalizedCheckpoints&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;CheckpointConfig&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;ExternalizedCheckpointCleanup&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;RETAIN_ON_CANCELLATION&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 在发生反压时提升快照效率（版本支持后可开启）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cfg&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;enableUnalignedCheckpoints&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 状态后端（旧 API 示例，根据版本选择）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;env&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;setStateBackend&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;new&lt;/span&gt;&lt;span&gt; org&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;apache&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;flink&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;runtime&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;state&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;filesystem&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;FsStateBackend&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;hdfs://namenode/flink/checkpoints&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 示例作业&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;DataStream&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; src&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; env&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;fromElements&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;b&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;c&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;DataStream&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Tuple2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Integer&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span&gt; out&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; src&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    .&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;v &lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt; Tuple2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    .&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;returns&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;Types&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;TUPLE&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;Types&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;STRING&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; Types&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;INT&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    .&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;keyBy&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;t &lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt; t&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;f0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    .&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sum&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;out&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;env&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;execute&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Tuning Example&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;推荐写法（Flink ≥ 1.15）：在 &lt;code&gt;flink-conf.yaml&lt;/code&gt; 配置状态后端与快照目录，代码仅设置策略参数（示例片段）：&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# flink-conf.yaml（示例）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;state.backend&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; rocksdb&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;state.checkpoints.dir&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; hdfs://namenode/flink/checkpoints&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;state.savepoints.dir&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; hdfs://namenode/flink/savepoints&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;execution.checkpointing.interval&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 5000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;execution.checkpointing.externalized-checkpoint-retention&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; RETAIN_ON_CANCELLATION&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;execution.checkpointing.unaligned&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;taskmanager.numberOfTaskSlots&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 4&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;final&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; StreamExecutionEnvironment&lt;/span&gt;&lt;span&gt; env&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; StreamExecutionEnvironment&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getExecutionEnvironment&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;env&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;setParallelism&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 其余状态后端与目录从配置文件生效&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&quot;xing-neng-dui-bi-ce-shi-shu-ju&quot;&gt;性能对比测试数据&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;基准测试环境
&lt;ul&gt;
&lt;li&gt;集群：3 × TaskManager（8 vCPU / 16GB RAM / slots=4），1 × JobManager&lt;/li&gt;
&lt;li&gt;存储：HDFS（3 副本），RocksDB 本地 SSD&lt;/li&gt;
&lt;li&gt;负载：Kafka 输入 50K msg/s（1KB 消息），简单聚合与写出&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;优化前后指标对比（示例数据）&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;指标&lt;/th&gt;&lt;th style=&quot;text-align: right&quot;&gt;优化前&lt;/th&gt;&lt;th style=&quot;text-align: right&quot;&gt;优化后&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;吞吐量（records/s）&lt;/td&gt;&lt;td style=&quot;text-align: right&quot;&gt;25,000&lt;/td&gt;&lt;td style=&quot;text-align: right&quot;&gt;60,000&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;端到端延迟（p95, ms）&lt;/td&gt;&lt;td style=&quot;text-align: right&quot;&gt;600&lt;/td&gt;&lt;td style=&quot;text-align: right&quot;&gt;250&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Checkpoint 时间（平均, ms）&lt;/td&gt;&lt;td style=&quot;text-align: right&quot;&gt;5,200&lt;/td&gt;&lt;td style=&quot;text-align: right&quot;&gt;1,300&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;反压占比（BackPressured）&lt;/td&gt;&lt;td style=&quot;text-align: right&quot;&gt;35%&lt;/td&gt;&lt;td style=&quot;text-align: right&quot;&gt;8%&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;CPU 使用率（TaskManagers 平均）&lt;/td&gt;&lt;td style=&quot;text-align: right&quot;&gt;80%&lt;/td&gt;&lt;td style=&quot;text-align: right&quot;&gt;70%&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;网络缓冲利用率&lt;/td&gt;&lt;td style=&quot;text-align: right&quot;&gt;高位抖动&lt;/td&gt;&lt;td style=&quot;text-align: right&quot;&gt;稳定中位&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h1 id=&quot;zi-yuan-pei-zhi-you-hua&quot;&gt;资源配置优化&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;并行度规划
&lt;ul&gt;
&lt;li&gt;槽位总量 = &lt;code&gt;TMs × slotsPerTM&lt;/code&gt;，并行度应匹配关键算子压力（例如聚合/Windo w）&lt;/li&gt;
&lt;li&gt;计算型算子适度提高并行度，I/O 型算子注意带宽与外部系统限流&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;内存规划
&lt;ul&gt;
&lt;li&gt;Process 内存：&lt;code&gt;taskmanager.memory.process.size&lt;/code&gt; 占容器配额的 70–85%&lt;/li&gt;
&lt;li&gt;Managed 内存：&lt;code&gt;taskmanager.memory.managed.fraction=0.3–0.5&lt;/code&gt;（RocksDB/状态算子偏大）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;网络缓冲
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;fraction&lt;/code&gt; 调整至 0.1–0.2，确保数据高峰时不溢出也不浪费&lt;/li&gt;
&lt;li&gt;适度 &lt;code&gt;bufferTimeout&lt;/code&gt;（5–50ms），降低小批次带来的协议开销&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;checkpoint-ji-zhi-diao-you&quot;&gt;Checkpoint 机制调优&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;间隔与并发
&lt;ul&gt;
&lt;li&gt;缩短间隔可降低回放恢复成本，但会增加对齐频次与 I/O 压力&lt;/li&gt;
&lt;li&gt;一般 &lt;code&gt;maxConcurrent=1&lt;/code&gt;，配合 &lt;code&gt;minPause&lt;/code&gt; 保证稳定快照节奏&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;非对齐快照（Unaligned Checkpoints）
&lt;ul&gt;
&lt;li&gt;在存在反压时显著降低快照时延；但恢复时需要更多数据缓冲&lt;/li&gt;
&lt;li&gt;适合高吞吐链路与偶发反压场景；稳定低延迟链路慎用&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;增量快照（RocksDB）
&lt;ul&gt;
&lt;li&gt;大状态场景强烈建议启用，降低 Checkpoint 与 Savepoint 时间&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;快照存储
&lt;ul&gt;
&lt;li&gt;HDFS/S3 推荐；本地盘仅用于缓存与 RocksDB 数据目录&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;zhuang-tai-hou-duan-xuan-xing-zhi-nan&quot;&gt;状态后端选型指南&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;HashMap/Memory：小状态、低延迟、快速算子，场景如轻量计数&lt;/li&gt;
&lt;li&gt;RocksDB：大状态、复杂聚合、精确恢复，适合边写边查与滚动窗口&lt;/li&gt;
&lt;li&gt;Filesystem（旧）：已逐步被替代，建议迁移到 RocksDB 或新内存后端&lt;/li&gt;
&lt;li&gt;选择要点：
&lt;ul&gt;
&lt;li&gt;状态量级（MB/GB）、访问频次（QPS）、恢复期望（SLA）&lt;/li&gt;
&lt;li&gt;磁盘类型（SSD 优先）、快照存储通道（HDFS/S3）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;fan-ya-chu-li-ce-lue&quot;&gt;反压处理策略&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;识别：Web UI BackPressure，任务日志、缓冲利用率、堆栈采样&lt;/li&gt;
&lt;li&gt;治理：
&lt;ul&gt;
&lt;li&gt;算子链路拆分：对重算子关闭 chaining，单独调度&lt;/li&gt;
&lt;li&gt;异步 I/O：用 &lt;code&gt;AsyncFunction&lt;/code&gt; 封装外部调用，&lt;code&gt;asyncWait&lt;/code&gt; 控制并发&lt;/li&gt;
&lt;li&gt;增加并行度与槽位，或限流上游（Kafka Source）&lt;/li&gt;
&lt;li&gt;调整 &lt;code&gt;bufferTimeout&lt;/code&gt;，避免微批过小导致协议开销过大&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;shu-ju-qing-xie-jie-jue-fang-an&quot;&gt;数据倾斜解决方案&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;热点 key 识别：TopN 统计、采样与 UI 指标&lt;/li&gt;
&lt;li&gt;解决方案：
&lt;ul&gt;
&lt;li&gt;Key 盐化：&lt;code&gt;key + randSalt(n)&lt;/code&gt;，下游再二次聚合&lt;/li&gt;
&lt;li&gt;双阶段聚合：局部聚合 + 全局聚合，降低单点压力&lt;/li&gt;
&lt;li&gt;路由重平衡：&lt;code&gt;rebalance()&lt;/code&gt; 或自定义 &lt;code&gt;partitioner&lt;/code&gt; 将热点分摊&lt;/li&gt;
&lt;li&gt;过滤/合并小流：对极端长尾/热点做预处理&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;zui-jia-shi-jian-zong-jie&quot;&gt;最佳实践总结&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;以指标驱动迭代，严控变更范围并保留回滚路径（Savepoint）&lt;/li&gt;
&lt;li&gt;大状态首选 RocksDB + 增量快照；稳态低延迟谨慎使用非对齐快照&lt;/li&gt;
&lt;li&gt;明确资源基线：槽位、内存、网络缓冲“三角平衡”&lt;/li&gt;
&lt;li&gt;反压问题优先解决算子结构与外部 I/O 约束，避免一味加并行度&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;注意：生产启用非对齐快照与大并行度前，务必进行回归测试与故障演练，评估恢复耗时与资源峰值。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h1 id=&quot;can-kao-yu-yan-shen-yue-du&quot;&gt;参考与延伸阅读&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Flink 官方文档：https://nightlies.apache.org/flink/flink-docs-release-1.15/&lt;/li&gt;
&lt;li&gt;Checkpoint 与状态后端：https://nightlies.apache.org/flink/flink-docs-release-1.15/docs/ops/state/checkpoints/&lt;/li&gt;
&lt;li&gt;RocksDB State Backend：https://nightlies.apache.org/flink/flink-docs-release-1.15/docs/ops/state/rocksdb/&lt;/li&gt;
&lt;li&gt;内存与资源：https://nightlies.apache.org/flink/flink-docs-release-1.15/docs/deployment/memory/&lt;/li&gt;
&lt;li&gt;Backpressure 监控：https://nightlies.apache.org/flink/flink-docs-release-1.15/docs/ops/monitoring/back_pressure/&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>FinOps 建设全指南：从理念到落地实践</title>
        <published>2025-10-25T00:00:00+00:00</published>
        <updated>2025-10-25T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/finops-construction-comprehensive-guide/"/>
        <id>https://scp.net.cn/blog/finops-construction-comprehensive-guide/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/finops-construction-comprehensive-guide/">&lt;h1 id=&quot;gai-lan&quot;&gt;概览&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;目标：建立可扩展、可度量、可协作的云成本管理体系，实现成本透明、预算可控与持续优化。&lt;/li&gt;
&lt;li&gt;图示：
&lt;ul&gt;
&lt;li&gt;架构示意图：&lt;img src=&quot;/finops-architecture.svg&quot; alt=&quot;FinOps 架构&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/li&gt;
&lt;li&gt;流程图：&lt;img src=&quot;/finops-process-flow.svg&quot; alt=&quot;FinOps 流程&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;1-gai-nian-jie-xi&quot;&gt;1. 概念解析&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;定义与原则
&lt;ul&gt;
&lt;li&gt;FinOps 是融合财务、技术与业务的云成本运营方法论，核心原则：可视化透明、共享责任、数据驱动、快速反馈与持续优化。&lt;/li&gt;
&lt;li&gt;三个支柱：信息透明（Visibility）、效率优化（Efficiency）、治理合规（Governance）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;重要性（行业调研参考：FinOps Foundation《State of FinOps 2024》）
&lt;ul&gt;
&lt;li&gt;多云与弹性按需导致成本波动大；企业通过 FinOps 实施后，常见 KPI 改善：成本节省 20–30%、预算偏差降低 30%+、异常响应时间缩短 40%+。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;与传统 IT 财务的区别
&lt;ul&gt;
&lt;li&gt;传统模式以年度预算与固定资产为中心；FinOps 面向云的实时消耗与弹性资源，强调跨部门协作与数据驱动决策，迭代优化快、粒度细。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;2-shi-shi-kuang-jia&quot;&gt;2. 实施框架&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;分阶段路线图
&lt;ul&gt;
&lt;li&gt;准备期：资产盘点、账单归集、资源标签与责任人绑定、预算与 KPI 设定；搭建数据底座（CUR/BigQuery/Snowflake）。&lt;/li&gt;
&lt;li&gt;实施期：成本可视化、自动化监控与告警、成本分摊与核算、优化策略执行（预留实例/节省计划、自动关停、规格优化）。&lt;/li&gt;
&lt;li&gt;优化期：异常检测与预测、治理策略（配额/策略/准入）、FinOps 作业流程固化与平台化。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;跨部门协作机制
&lt;ul&gt;
&lt;li&gt;财务：预算制定、成本核算与结算、政策与合规；技术：数据采集、优化实施与自动化；业务：需求优先级与价值评估。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;关键角色与职责
&lt;ul&gt;
&lt;li&gt;FinOps Lead（统筹与治理）、Cloud Engineer（优化与工具）、Data Analyst（分析与模型）、Product Owner（业务价值）、Finance Analyst（核算与预算）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;3-ji-shu-fang-an&quot;&gt;3. 技术方案&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;工具链比较（示例）
&lt;ul&gt;
&lt;li&gt;AWS Cost Explorer、AWS Budgets 与 Cost Anomaly Detection：原生集成度高，适合 AWS 重度用户。&lt;/li&gt;
&lt;li&gt;Azure Cost Management + Advisor：强可视化与建议，适合 Azure 场景。&lt;/li&gt;
&lt;li&gt;GCP Billing + BigQuery Export + Looker：数据驱动能力优秀，适合分析型组织。&lt;/li&gt;
&lt;li&gt;第三方：Apptio Cloudability、Harness、CloudHealth 等，适合多云与治理要求更强的企业。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;自动化监控与告警
&lt;ul&gt;
&lt;li&gt;数据源：账单导出（CUR/Export）、用量与配额、资源清单与标签。&lt;/li&gt;
&lt;li&gt;告警：预算阈值、异常波动（同比环比/季节性）、未标记与孤儿资源、折扣利用率低。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;资源标签策略与成本分摊模型
&lt;ul&gt;
&lt;li&gt;标签规范：&lt;code&gt;owner/team/project/env/cost-center/app&lt;/code&gt;；强制策略（SCP/Azure Policy）确保入云即标注。&lt;/li&gt;
&lt;li&gt;分摊模型：直接归集（标签）、共享成本二次分摊（权重/用量比例/固定比例）、跨账号/订阅对齐。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;4-zui-jia-shi-jian&quot;&gt;4. 最佳实践&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;成本可视化实现
&lt;ul&gt;
&lt;li&gt;数据仓：BigQuery/Snowflake；ETL：DBT/Glue；可视化：Looker/QuickSight/Power BI；统一维表与度量。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;预算控制与异常检测
&lt;ul&gt;
&lt;li&gt;预算层级：公司/部门/项目；告警策略：阈值、突增检测（MAD/ESD）、季节性模型（Holt-Winters）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;优化建议生成与执行
&lt;ul&gt;
&lt;li&gt;建议来源：规格优化（CPU/内存/吞吐）、预留/节省计划匹配、关停空闲资源、存储冷热分层与生命周期（ILM）。&lt;/li&gt;
&lt;li&gt;执行：变更审批流（低风险自动、高风险人工）、计划窗口与回滚、自动化脚本（IaC + API）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;5-luo-di-tiao-zhan&quot;&gt;5. 落地挑战&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;常见障碍与解决方案
&lt;ul&gt;
&lt;li&gt;标签缺失与不一致：推行强制策略与自动补齐；未标注直接阻断或纳入共享池并限期治理。&lt;/li&gt;
&lt;li&gt;数据质量与口径不统一：统一维表、口径定义与结算规则；审计可追溯。&lt;/li&gt;
&lt;li&gt;组织协同难：建立 RACI 与例行评审机制；目标与激励绑定（预算与 KPI）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;变革管理策略
&lt;ul&gt;
&lt;li&gt;宣贯与培训、试点先行、里程碑与复盘、度量可视化、从胜利中扩展。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;持续改进机制
&lt;ul&gt;
&lt;li&gt;周期性评审、指标看板与告警复盘、优化建议闭环、成本基线动态调整。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;6-jia-gou-yu-liu-cheng-can-kao-shi-xian&quot;&gt;6. 架构与流程（参考实现）&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;架构组成
&lt;ul&gt;
&lt;li&gt;采集：账单、用量、资源清单与标签；&lt;/li&gt;
&lt;li&gt;存储与处理：仓库与 ETL、归一化模型、指标聚合；&lt;/li&gt;
&lt;li&gt;应用：看板、预算、告警与异常检测、优化建议引擎；&lt;/li&gt;
&lt;li&gt;治理：策略与准入、审批与变更、审计与合规。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;流程阶段
&lt;ul&gt;
&lt;li&gt;发现→基线→预算→监控→优化→治理→复盘（形成闭环）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;7-guan-jian-zhi-biao-yu-ji-suan-gong-shi&quot;&gt;7. 关键指标与计算公式&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;单位成本（Unit Cost）：&lt;code&gt;总云成本 / 业务量（请求数/订单数/MAU）&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;资源效率（Resource Efficiency）：&lt;code&gt;实际利用率 / 期望利用率&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;折扣覆盖率（Coverage）：&lt;code&gt;(RI+SP 折扣使用额) / 可折扣资源成本&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;优化收益率（Savings Rate）：&lt;code&gt;(优化前成本 - 优化后成本) / 优化前成本&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;预算偏差率（Budget Variance）：&lt;code&gt;(实际 - 预算) / 预算&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;异常波动阈值（MAD）：&lt;code&gt;|x - 中位数| &amp;gt; k * MAD&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;8-shi-shi-jian-cha-qing-dan&quot;&gt;8. 实施检查清单&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;标签：规范、强制、审计、自动补齐；&lt;/li&gt;
&lt;li&gt;数据：账单与用量全量与增量、维表与口径定义；&lt;/li&gt;
&lt;li&gt;预算：层级、阈值与告警、审批与豁免；&lt;/li&gt;
&lt;li&gt;告警：异常检测模型、通道（邮件/IM/Webhook）、抑制与合并、复盘机制；&lt;/li&gt;
&lt;li&gt;优化：建议生成、风险分级、计划窗口与回滚、自动化执行；&lt;/li&gt;
&lt;li&gt;合规：SCP/Azure Policy/OrgPolicy、配额与策略、权限最小化、审计与留痕。&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;9-shi-shi-an-li-can-kao&quot;&gt;9. 实施案例（参考）&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;场景：大型电商企业，采用多云架构（AWS+GCP）。月均云成本约 200 万，业务为高并发促销、日常交易与推荐服务。历史上存在成本波动与预算偏差问题，标签覆盖不足导致成本归集困难，缺少异常检测与自动化优化闭环。目标是 3 个月内建立 FinOps 体系，实现透明化、预算可控、自动化优化闭环。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;/finops-case-timeline.svg&quot; alt=&quot;案例时间线&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;
&lt;img src=&quot;/finops-case-kpi.svg&quot; alt=&quot;案例关键KPI对比&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;9-1-an-li-bei-jing-fen-xi&quot;&gt;9.1 案例背景分析&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;行业背景与业务场景：
&lt;ul&gt;
&lt;li&gt;电商业务具有明显峰谷（大促、节假日）与服务多样性（交易、搜索、推荐、风控）。多云设计用于差异化优势与冗余，但带来数据与治理复杂度。&lt;/li&gt;
&lt;li&gt;成本构成以计算（EC2/GCE、GKE/EKS）、存储（S3/GCS）、网络出口为主，另有数据库与分析（RDS/BigQuery）等。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;核心问题：
&lt;ul&gt;
&lt;li&gt;成本不可见：账单口径与维表不统一，标签覆盖低。&lt;/li&gt;
&lt;li&gt;预算不可控：实时波动导致预算预警滞后，异常响应慢。&lt;/li&gt;
&lt;li&gt;优化不可闭环：建议执行依赖人工，缺少审批与回滚机制。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;预期目标：
&lt;ul&gt;
&lt;li&gt;成本节省 ≥ 25%；预算偏差率 ≤ 6%；异常响应从 48 小时降至 ≤ 6 小时；标签覆盖 ≥ 95%；建立持续优化与治理闭环。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;9-2-shi-shi-zhun-bei-jie-duan&quot;&gt;9.2 实施准备阶段&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;技术栈与工具清单：
&lt;ul&gt;
&lt;li&gt;数据采集：AWS CUR、GCP Billing Export；资源清单与标签 API；配额与用量指标。&lt;/li&gt;
&lt;li&gt;数据仓与 ETL：BigQuery、DBT/Glue；数据归一化表与指标聚合。&lt;/li&gt;
&lt;li&gt;可视化与告警：Looker/Looker Studio、QuickSight；Budgets/Anomaly Detection；自研告警服务（Webhook/IM/邮件）。&lt;/li&gt;
&lt;li&gt;优化执行：Terraform/IaC、云厂商 API；审批流（Git PR + 审批机器人）。&lt;/li&gt;
&lt;li&gt;治理策略：SCP/Azure Policy/Org Policy；标签策略；审计与留痕。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;环境配置与权限：
&lt;ul&gt;
&lt;li&gt;最小权限原则，数据导出读权限、ETL 写权限、看板只读、优化脚本需受控的变更权限；审批双人机制；审计日志保留。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;项目时间表与里程碑（3 个月）：
&lt;ul&gt;
&lt;li&gt;M1：数据底座完成（账单与维表、可视化看板初版、标签策略上线）。&lt;/li&gt;
&lt;li&gt;M2：预算与异常检测落地，自动告警与事件复盘流程跑通；试点优化（规格/折扣/关停）。&lt;/li&gt;
&lt;li&gt;M3：平台化闭环（审批流 + 自动化执行 + 回滚），治理策略扩展（配额/准入），形成例行评审与持续改进。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;9-3-ju-ti-shi-shi-bu-zou&quot;&gt;9.3 具体实施步骤&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;阶段 A：数据底座与可视化
&lt;ul&gt;
&lt;li&gt;操作步骤：
&lt;ol&gt;
&lt;li&gt;开通 AWS CUR 与 GCP Billing 导出至 BigQuery；定义统一维表（账号/项目、部门、业务、标签）。&lt;/li&gt;
&lt;li&gt;通过 DBT 建立归一化模型与聚合指标（天/周/月维度）。&lt;/li&gt;
&lt;li&gt;搭建看板（部门/项目/应用/环境维度），支持钻取到资源明细。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;关键配置参数：
&lt;ul&gt;
&lt;li&gt;AWS CUR：&lt;code&gt;time granularity=daily, with resources=true&lt;/code&gt;；GCP Billing：&lt;code&gt;dataset=finops_cur&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;BigQuery 表设计：&lt;code&gt;cost, usage, discount, tags(owner/team/project/env/cost_center), account/project&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;预期中间结果：账单数据完整入仓，维度一致性通过校验；看板可视化上线。&lt;/li&gt;
&lt;li&gt;配置示例：&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;-- BigQuery: 统一账单归集视图&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;CREATE OR REPLACE VIEW&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; finops&lt;/span&gt;&lt;span&gt;.v_cost_daily &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;AS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;SELECT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  DATE&lt;/span&gt;&lt;span&gt;(usage_start_time) &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;AS&lt;/span&gt;&lt;span&gt; dt,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  provider&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  account_id,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  project_id,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  labels.owner,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  labels.team,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  labels.project,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  labels.env,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  labels.cost_center,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  SUM&lt;/span&gt;&lt;span&gt;(cost) &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;AS&lt;/span&gt;&lt;span&gt; total_cost,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  SUM&lt;/span&gt;&lt;span&gt;(usage_amount) &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;AS&lt;/span&gt;&lt;span&gt; total_usage,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  SUM&lt;/span&gt;&lt;span&gt;(discount_amount) &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;AS&lt;/span&gt;&lt;span&gt; total_discount&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;FROM&lt;/span&gt;&lt;span&gt; finops_cur.raw_billing&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;GROUP BY&lt;/span&gt;&lt;span&gt; dt, &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;provider&lt;/span&gt;&lt;span&gt;, account_id, project_id,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;         labels.owner, labels.team, labels.project, labels.env, labels.cost_center;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;阶段 B：标签策略与成本分摊
&lt;ul&gt;
&lt;li&gt;操作步骤：
&lt;ol&gt;
&lt;li&gt;制定标签规范并启用强制策略（入云即标注）；&lt;/li&gt;
&lt;li&gt;建立共享成本分摊模型（如网络出口、监控等），定义权重或用量比例；&lt;/li&gt;
&lt;li&gt;自动补齐缺失标签（基于资源命名或资产清单）。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;关键配置参数：&lt;code&gt;owner/team/project/env/cost-center/app&lt;/code&gt;；未标注资源纳入共享池并限期治理。&lt;/li&gt;
&lt;li&gt;预期中间结果：标签覆盖率快速提升（≥ 95%），分摊结果进入看板与结算。&lt;/li&gt;
&lt;li&gt;策略示例（Terraform）：&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;hcl&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;resource &amp;quot;aws_organizations_policy&amp;quot; &amp;quot;tag_policy&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  name&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;mandatory-tags&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  description&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Require tags on creation&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  content&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;     =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; jsonencode&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    tags&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      owner&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;       =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; required&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = true&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      team&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; required&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = true&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      project&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;     =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; required&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = true&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      env&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;         =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; required&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = true&lt;/span&gt;&lt;span&gt;, values&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;prod&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;staging&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;dev&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      cost_center&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span&gt; required&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = true&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  })&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;阶段 C：预算控制与异常检测
&lt;ul&gt;
&lt;li&gt;操作步骤：
&lt;ol&gt;
&lt;li&gt;建立预算层级（公司/部门/项目）与阈值；&lt;/li&gt;
&lt;li&gt;启用异常检测（MAD/季节性），通过 IM/Webhook 推送事件；&lt;/li&gt;
&lt;li&gt;复盘流程：事件分派、根因定位、处置与记录归档。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;关键配置参数：预算阈值、异常 k 值（MAD）、季节性窗口；告警聚合与抑制策略。&lt;/li&gt;
&lt;li&gt;预期中间结果：预算与异常事件闭环，响应时长显著下降。&lt;/li&gt;
&lt;li&gt;异常检测示例（Python）：&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span&gt; numpy&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; as&lt;/span&gt;&lt;span&gt; np&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; mad_threshold&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;series&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; k&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;3.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    median&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; np&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;median&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;series&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    mad&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; np&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;median&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;np&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;abs&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;series&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; -&lt;/span&gt;&lt;span&gt; median&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; median&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span&gt; k&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; *&lt;/span&gt;&lt;span&gt; mad&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 当日成本 x 超过阈值则触发&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;if&lt;/span&gt;&lt;span&gt; today_cost&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; mad_threshold&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;cost_last_30_days&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; k&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;3.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    trigger_alert&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;COST_SPIKE&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span&gt; value&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt;today_cost&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;阶段 D：优化建议与自动化执行
&lt;ul&gt;
&lt;li&gt;操作步骤：
&lt;ol&gt;
&lt;li&gt;生成优化建议（规格优化、RI/SP、关停闲置、存储分层）。&lt;/li&gt;
&lt;li&gt;建立审批流（低风险自动执行，高风险人工审批），支持计划窗口与回滚。&lt;/li&gt;
&lt;li&gt;执行动作脚本（IaC + API），记录留痕与效果评估。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;关键配置参数：折扣匹配规则（覆盖率/期限/灵活性）、CPU/内存/吞吐阈值、关停判定标准（空闲时长/访问量）。&lt;/li&gt;
&lt;li&gt;预期中间结果：节省逐步兑现，风险可控且可回滚。&lt;/li&gt;
&lt;li&gt;执行示例（伪代码）：&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 规格优化：将 t3.2xlarge 降配为 t3.xlarge（示例）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;aws&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; ec2 modify-instance-attribute&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;  --instance-id i-1234567890&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;  --instance-type t3.xlarge&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 购买 Savings Plan（示例）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;aws&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; ce purchase-savings-plan --amount&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 50000&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; --term 1-year --payment-option all-upfront&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;阶段 E：治理策略与平台化闭环
&lt;ul&gt;
&lt;li&gt;操作步骤：
&lt;ol&gt;
&lt;li&gt;扩展策略（配额、准入、模板化），防止回归与越权。&lt;/li&gt;
&lt;li&gt;平台化：统一入口、权限与审计；例行评审机制固化。&lt;/li&gt;
&lt;li&gt;与企业流程衔接（变更管理、CMDB、成本结算）。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;关键配置参数：配额上限、准入白名单、模板仓库与审批节点。&lt;/li&gt;
&lt;li&gt;预期中间结果：FinOps 体系可持续运行，治理常态化。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;9-4-yan-zheng-yu-ce-shi&quot;&gt;9.4 验证与测试&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;测试用例设计：
&lt;ul&gt;
&lt;li&gt;数据完整性：账单与维表入仓校验、边界资源（新建/删除/迁移）标签追踪。&lt;/li&gt;
&lt;li&gt;告警有效性：预算阈值与异常模型触发测试、抑制与合并策略覆盖。&lt;/li&gt;
&lt;li&gt;优化执行：审批与回滚流程演练、风险分级策略验证。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;性能指标与成功标准：
&lt;ul&gt;
&lt;li&gt;成本节省 ≥ 25%；预算偏差率 ≤ 6%；异常响应 ≤ 6 小时；标签覆盖 ≥ 95%。&lt;/li&gt;
&lt;li&gt;看板延迟 ≤ 2 小时；建议执行成功率 ≥ 95%；审计日志完备率 = 100%。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;常见问题排查：
&lt;ul&gt;
&lt;li&gt;数据延迟与缺失：检查导出任务、ETL 调度与失败重试；&lt;/li&gt;
&lt;li&gt;标签不一致：策略是否生效、自动补齐规则是否覆盖；&lt;/li&gt;
&lt;li&gt;告警噪声：阈值与聚合策略调优，事件分级与抑制窗口设置；&lt;/li&gt;
&lt;li&gt;执行失败：权限不足、资源占用或窗口冲突，回滚验证与重试机制。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;9-5-wen-dang-wan-shan&quot;&gt;9.5 文档完善&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;文档更新：
&lt;ul&gt;
&lt;li&gt;架构、流程与口径说明；维表与指标定义；预算与异常规则；审批与回滚流程；审计与留痕要求。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;图表与说明：
&lt;ul&gt;
&lt;li&gt;时间线与 KPI 对比图嵌入文章；看板截图与示意；建议执行流程图。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;经验教训记录：
&lt;ul&gt;
&lt;li&gt;强制标签与数据口径统一是成本透明的前提；&lt;/li&gt;
&lt;li&gt;告警聚合与抑制不可或缺；审批与回滚保障优化安全；&lt;/li&gt;
&lt;li&gt;例行复盘与度量驱动持续改进。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;9-6-hou-xu-you-hua-jian-yi&quot;&gt;9.6 后续优化建议&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;改进方向：
&lt;ul&gt;
&lt;li&gt;异常检测引入季节性与节假日因子、基线自适应；&lt;/li&gt;
&lt;li&gt;成本预测与预算分配模型；&lt;/li&gt;
&lt;li&gt;优化建议的自动优先级与风险评分。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;可扩展功能点：
&lt;ul&gt;
&lt;li&gt;Kubernetes 成本分摊（Pod/Namespace/Workload）；&lt;/li&gt;
&lt;li&gt;跨云资源编排与统一策略；&lt;/li&gt;
&lt;li&gt;成本与业务价值挂钩（单位成本对齐 KPI）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;参考资料与延伸阅读：
&lt;ul&gt;
&lt;li&gt;FinOps Foundation：《State of FinOps》《FinOps Technical Standard》《FinOps for Kubernetes》；&lt;/li&gt;
&lt;li&gt;AWS/Azure/GCP 成本管理文档与折扣策略指南；&lt;/li&gt;
&lt;li&gt;Gartner 云成本管理与优化相关报告。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;10-an-quan-yu-he-gui&quot;&gt;10. 安全与合规&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;策略：强制标签、配额与策略、资源准入与模板化（IaC）；&lt;/li&gt;
&lt;li&gt;权限：最小权限、双人审批、变更留痕；&lt;/li&gt;
&lt;li&gt;合规：账单与审计日志长期保留；满足 ISO 27001、SOC2、GDPR 数据保留与访问控制要求。&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;can-kao-zi-liao&quot;&gt;参考资料&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;FinOps Foundation：《State of FinOps 2023/2024》《FinOps for Kubernetes》《FinOps Technical Standard》&lt;/li&gt;
&lt;li&gt;AWS：Cost Explorer / Budgets / Anomaly Detection / CUR / Savings Plans / RI / Well-Architected Cost Optimization&lt;/li&gt;
&lt;li&gt;Azure：Cost Management + Advisor / Policy / Tagging / Reservations&lt;/li&gt;
&lt;li&gt;GCP：Billing Export / BigQuery / Looker Studio / Committed Use Discount&lt;/li&gt;
&lt;li&gt;Gartner：《Cloud Cost Management &amp;amp; Optimization》与相关报告&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>基于Golang的电商库存中台系统设计与实现</title>
        <published>2025-10-25T00:00:00+00:00</published>
        <updated>2025-10-25T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/golang-ecommerce-inventory-middle-platform/"/>
        <id>https://scp.net.cn/blog/golang-ecommerce-inventory-middle-platform/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/golang-ecommerce-inventory-middle-platform/">&lt;h1 id=&quot;gai-lan&quot;&gt;概览&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;目标：设计并实现一个可扩展、强一致、低延迟的库存中台，支撑电商常规销售与秒杀高峰场景。&lt;/li&gt;
&lt;li&gt;图示：
&lt;ul&gt;
&lt;li&gt;系统架构：&lt;img src=&quot;/inventory-system-architecture.svg&quot; alt=&quot;系统架构&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/li&gt;
&lt;li&gt;库存ER关系：&lt;img src=&quot;/inventory-db-er.svg&quot; alt=&quot;数据库ER图&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;1-xi-tong-jia-gou-she-ji&quot;&gt;1. 系统架构设计&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;微服务架构（Golang）：
&lt;ul&gt;
&lt;li&gt;服务划分：&lt;code&gt;inventory-service&lt;/code&gt;（核心库存）、&lt;code&gt;lock-service&lt;/code&gt;（分布式锁）、&lt;code&gt;flow-service&lt;/code&gt;（流水与对账）、&lt;code&gt;rule-engine&lt;/code&gt;（分仓与调度）、&lt;code&gt;sync-service&lt;/code&gt;（仓库同步）、&lt;code&gt;api-gateway&lt;/code&gt;（BFF）。&lt;/li&gt;
&lt;li&gt;通讯协议：内部 &lt;code&gt;gRPC&lt;/code&gt; + Protobuf；外部 &lt;code&gt;REST/GraphQL&lt;/code&gt;（BFF）；消息事件 &lt;code&gt;Kafka&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;存储：MySQL（主库 + 读写分离），Redis（缓存与热点削峰），对象存储（审计与离线对账）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;库存中台定位：
&lt;ul&gt;
&lt;li&gt;统一库存口径，提供原子动作与强一致出入库能力；对上承接订单、促销与风控，对下对接仓库WMS与供应链。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;模块交互图：见架构SVG与各模块时序图。&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;2-shu-ju-ku-she-ji&quot;&gt;2. 数据库设计&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;核心表（字段说明摘要）：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;inventory_main&lt;/code&gt;（库存主表）：&lt;code&gt;id(PK)&lt;/code&gt;、&lt;code&gt;sku_id&lt;/code&gt;、&lt;code&gt;warehouse_id&lt;/code&gt;、&lt;code&gt;total&lt;/code&gt;、&lt;code&gt;available&lt;/code&gt;、&lt;code&gt;locked&lt;/code&gt;、&lt;code&gt;reserved&lt;/code&gt;、&lt;code&gt;activity_tag&lt;/code&gt;、&lt;code&gt;version&lt;/code&gt;、&lt;code&gt;updated_at&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;inventory_flow&lt;/code&gt;（库存流水）：&lt;code&gt;id(PK)&lt;/code&gt;、&lt;code&gt;sku_id&lt;/code&gt;、&lt;code&gt;warehouse_id&lt;/code&gt;、&lt;code&gt;action(Add/Lock/Unlock/Reduce/Restore/Exception)&lt;/code&gt;、&lt;code&gt;delta&lt;/code&gt;、&lt;code&gt;biz_order_id&lt;/code&gt;、&lt;code&gt;trace_id&lt;/code&gt;、&lt;code&gt;operator&lt;/code&gt;、&lt;code&gt;created_at&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;inventory_lock&lt;/code&gt;（库存锁定）：&lt;code&gt;id(PK)&lt;/code&gt;、&lt;code&gt;sku_id&lt;/code&gt;、&lt;code&gt;warehouse_id&lt;/code&gt;、&lt;code&gt;lock_qty&lt;/code&gt;、&lt;code&gt;biz_order_id&lt;/code&gt;、&lt;code&gt;expire_at&lt;/code&gt;、&lt;code&gt;status(LOCKED/UNLOCKED/REDUCED)&lt;/code&gt;、&lt;code&gt;created_at&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;inventory_exception&lt;/code&gt;（库存异常）：&lt;code&gt;id(PK)&lt;/code&gt;、&lt;code&gt;sku_id&lt;/code&gt;、&lt;code&gt;warehouse_id&lt;/code&gt;、&lt;code&gt;type&lt;/code&gt;、&lt;code&gt;reason&lt;/code&gt;、&lt;code&gt;ctx(json)&lt;/code&gt;、&lt;code&gt;biz_order_id&lt;/code&gt;、&lt;code&gt;resolved(bool)&lt;/code&gt;、&lt;code&gt;created_at&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;warehouse&lt;/code&gt;（分仓表）：&lt;code&gt;id(PK)&lt;/code&gt;、&lt;code&gt;name&lt;/code&gt;、&lt;code&gt;region&lt;/code&gt;、&lt;code&gt;priority&lt;/code&gt;、&lt;code&gt;capacity&lt;/code&gt;、&lt;code&gt;status&lt;/code&gt;、&lt;code&gt;updated_at&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;表关系与索引：
&lt;ul&gt;
&lt;li&gt;关系：&lt;code&gt;inventory_main&lt;/code&gt; 1..n &lt;code&gt;inventory_flow&lt;/code&gt;；&lt;code&gt;inventory_lock&lt;/code&gt; 与订单1..n；&lt;code&gt;warehouse&lt;/code&gt; 与主表1..n。&lt;/li&gt;
&lt;li&gt;索引：&lt;code&gt;(sku_id, warehouse_id)&lt;/code&gt;唯一索引；&lt;code&gt;inventory_flow(sku_id, created_at)&lt;/code&gt;；&lt;code&gt;inventory_lock(biz_order_id)&lt;/code&gt;；&lt;code&gt;warehouse(region, priority)&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;事务与并发控制：
&lt;ul&gt;
&lt;li&gt;行级锁：&lt;code&gt;SELECT ... FOR UPDATE&lt;/code&gt; 锁主表行，基于 &lt;code&gt;version&lt;/code&gt; 实施乐观并发；&lt;/li&gt;
&lt;li&gt;原子动作在同一事务内更新主表 + 写入流水 + 出站消息（Outbox）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/inventory-db-er.svg&quot; alt=&quot;数据库ER图&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;h1 id=&quot;3-he-xin-ye-wu-luo-ji-shi-xian&quot;&gt;3. 核心业务逻辑实现&lt;/h1&gt;
&lt;h2 id=&quot;3-1-ku-cun-bian-hua-chu-li-yuan-zi-cao-zuo&quot;&gt;3.1 库存变化处理（原子操作）&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;原子动作：Add、Lock、Unlock、Reduce、Restore、Exception；保证幂等与可回滚。&lt;/li&gt;
&lt;li&gt;下单库存状态变迁：见时序图 &lt;code&gt;订单提交→库存锁定→支付成功→扣减→发货→完成&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;活动库存与销售库存：&lt;code&gt;activity_tag&lt;/code&gt;区分活动库存池，调度优先从活动池消耗，避免侵占常规库存。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/inventory-order-flow-sequence.svg&quot; alt=&quot;订单库存时序图&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;gRPC 接口定义（proto）：&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;proto&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;syntax =&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; &amp;quot;proto3&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;package&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; inventory.v1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;service&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; InventoryService&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  rpc&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Add&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;AddRequest&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;returns&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;ActionResult&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  rpc&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Lock&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;LockRequest&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;returns&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;ActionResult&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  rpc&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Unlock&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;UnlockRequest&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;returns&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;ActionResult&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  rpc&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Reduce&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;ReduceRequest&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;returns&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;ActionResult&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  rpc&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Restore&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;RestoreRequest&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;returns&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;ActionResult&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  rpc&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; ReportException&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;ExceptionRequest&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;returns&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;ActionResult&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Context&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; string&lt;/span&gt;&lt;span&gt; trace_id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;; string&lt;/span&gt;&lt;span&gt; operator&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; AddRequest&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; string&lt;/span&gt;&lt;span&gt; sku_id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;; string&lt;/span&gt;&lt;span&gt; warehouse_id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;; int64&lt;/span&gt;&lt;span&gt; qty&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;; Context&lt;/span&gt;&lt;span&gt; ctx&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; LockRequest&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; string&lt;/span&gt;&lt;span&gt; sku_id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;; string&lt;/span&gt;&lt;span&gt; warehouse_id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;; int64&lt;/span&gt;&lt;span&gt; qty&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;; string&lt;/span&gt;&lt;span&gt; biz_order_id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;; int64&lt;/span&gt;&lt;span&gt; ttl_ms&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 5&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;; Context&lt;/span&gt;&lt;span&gt; ctx&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 6&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; UnlockRequest&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; string&lt;/span&gt;&lt;span&gt; lock_id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;; Context&lt;/span&gt;&lt;span&gt; ctx&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; ReduceRequest&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; string&lt;/span&gt;&lt;span&gt; lock_id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;; Context&lt;/span&gt;&lt;span&gt; ctx&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; RestoreRequest&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; string&lt;/span&gt;&lt;span&gt; sku_id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;; string&lt;/span&gt;&lt;span&gt; warehouse_id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;; int64&lt;/span&gt;&lt;span&gt; qty&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;; Context&lt;/span&gt;&lt;span&gt; ctx&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; ExceptionRequest&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; string&lt;/span&gt;&lt;span&gt; sku_id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;; string&lt;/span&gt;&lt;span&gt; warehouse_id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;; string&lt;/span&gt;&lt;span&gt; type&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;; string&lt;/span&gt;&lt;span&gt; reason&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;; string&lt;/span&gt;&lt;span&gt; biz_order_id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 5&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;; string&lt;/span&gt;&lt;span&gt; ctx_json&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 6&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; ActionResult&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; bool&lt;/span&gt;&lt;span&gt; ok&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;; string&lt;/span&gt;&lt;span&gt; code&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;; string&lt;/span&gt;&lt;span&gt; message&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;; string&lt;/span&gt;&lt;span&gt; lock_id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Golang 原子操作示例（加锁与扣减，含注释）：&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// language: go&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// LockAndReduce: 下单场景，先锁定，再在支付成功后扣减&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;s &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span&gt;Service&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; LockAndReduce&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ctx context&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;Context&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; skuID&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; whID&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; qty&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; int64&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; orderID&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; error&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; s&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;db&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;WithTx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; func&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;tx&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; *&lt;/span&gt;&lt;span&gt;Tx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; error&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // 1) 行级锁，避免并发篡改&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        inv&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; :=&lt;/span&gt;&lt;span&gt; tx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;GetForUpdate&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; skuID&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; whID&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; != nil&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span&gt; inv&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;Available&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span&gt; qty&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return&lt;/span&gt;&lt;span&gt; ErrInsufficient&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // 2) 更新主表：可用-&amp;gt;减少，锁定-&amp;gt;增加&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        inv&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;Available&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; -=&lt;/span&gt;&lt;span&gt; qty&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        inv&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;Locked&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +=&lt;/span&gt;&lt;span&gt; qty&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        inv&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;Version&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; :=&lt;/span&gt;&lt;span&gt; tx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;UpdateInventory&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; inv&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; != nil&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // 3) 写锁记录与流水&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        lockID&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; :=&lt;/span&gt;&lt;span&gt; tx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;InsertLock&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; skuID&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; whID&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; qty&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; orderID&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; time&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Now&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Add&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;15&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span&gt;time&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;Minute&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; != nil&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; :=&lt;/span&gt;&lt;span&gt; tx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;InsertFlow&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; skuID&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; whID&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Lock&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span&gt; qty&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; orderID&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; != nil&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // 4) Outbox写入（事务内），由异步Worker可靠投递到Kafka&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; :=&lt;/span&gt;&lt;span&gt; tx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;InsertOutbox&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;inventory.lock&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; map&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span&gt;any&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{ &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;lock_id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; lockID&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;order_id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; orderID&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; })&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; != nil&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return nil&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    })&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// Reduce: 支付成功后扣减（幂等处理）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;s &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span&gt;Service&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Reduce&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ctx context&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;Context&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; lockID&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; error&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; s&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;db&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;WithTx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; func&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;tx&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; *&lt;/span&gt;&lt;span&gt;Tx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; error&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        lock&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; :=&lt;/span&gt;&lt;span&gt; tx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;GetLockForUpdate&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; lockID&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; != nil&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span&gt; lock&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;Status&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;REDUCED&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot; {&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return nil&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; // 幂等&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        inv&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; :=&lt;/span&gt;&lt;span&gt; tx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;GetForUpdate&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; lock&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;SkuID&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; lock&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;WhID&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; != nil&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span&gt; inv&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;Locked&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span&gt; lock&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;Qty&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return&lt;/span&gt;&lt;span&gt; ErrInvariantBroken&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        inv&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;Locked&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; -=&lt;/span&gt;&lt;span&gt; lock&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;Qty&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        inv&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;Total&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; -=&lt;/span&gt;&lt;span&gt; lock&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;Qty&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        inv&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;Version&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; :=&lt;/span&gt;&lt;span&gt; tx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;UpdateInventory&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; inv&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; != nil&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; :=&lt;/span&gt;&lt;span&gt; tx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;UpdateLockStatus&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; lockID&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;REDUCED&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; != nil&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; :=&lt;/span&gt;&lt;span&gt; tx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;InsertFlow&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; lock&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;SkuID&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; lock&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;WhID&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Reduce&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span&gt; lock&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;Qty&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; lock&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;OrderID&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; != nil&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; :=&lt;/span&gt;&lt;span&gt; tx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;InsertOutbox&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;inventory.reduce&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; map&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span&gt;any&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{ &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;lock_id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; lockID&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;order_id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span&gt; lock&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;OrderID&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; })&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; != nil&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return nil&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    })&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;3-2-ku-cun-fen-ceng-jia-gou&quot;&gt;3.2 库存分层架构&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;销售层：负责订单侧的锁定/扣减幂等、异常回滚；&lt;/li&gt;
&lt;li&gt;调度层：分仓分配算法（距离、库存、优先级、活动池）；&lt;/li&gt;
&lt;li&gt;仓库层：WMS同步机制（增量回写与对账）；&lt;/li&gt;
&lt;li&gt;规则引擎：可配置分仓策略，支持黑白名单、阈值与权重。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/inventory-layered-architecture.svg&quot; alt=&quot;分层架构&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;h1 id=&quot;4-ku-cun-quan-liu-cheng-guan-li&quot;&gt;4. 库存全流程管理&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;发货仓智能调度：综合&lt;code&gt;region&lt;/code&gt;、&lt;code&gt;priority&lt;/code&gt;、&lt;code&gt;activity_tag&lt;/code&gt;与可用量；&lt;/li&gt;
&lt;li&gt;多渠道统一：合并线上线下/跨平台库存口径；&lt;/li&gt;
&lt;li&gt;销售预测与补货：基于时序预测与安全库存策略；&lt;/li&gt;
&lt;li&gt;与订单/仓储交互：订单状态驱动库存状态机，WMS回写保障一致性。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/inventory-full-process-interactions.svg&quot; alt=&quot;全流程交互&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;h1 id=&quot;5-miao-sha-chang-jing-zhuan-xiang-you-hua&quot;&gt;5. 秒杀场景专项优化&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;预锁定：活动前生成令牌桶与预热&lt;code&gt;locked&lt;/code&gt;池；&lt;/li&gt;
&lt;li&gt;高并发扣减：使用Redis原子脚本 + DB异步批量对账；&lt;/li&gt;
&lt;li&gt;订单超时：TTL到期自动解锁并回滚；&lt;/li&gt;
&lt;li&gt;熔断降级：热点限流、仓库级降级与读降级缓存。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/inventory-seckill-sequence.svg&quot; alt=&quot;秒杀时序&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;h1 id=&quot;6-he-xin-dai-ma-zhan-shi&quot;&gt;6. 核心代码展示&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;分布式锁实现（Redis，简化版Redlock思想）：&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// language: go&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// TryLock: 基于SET NX PX与随机token实现简单租约锁&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;l &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span&gt;Locker&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; TryLock&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ctx context&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;Context&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; key&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; ttl time&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;Duration&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; bool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; error&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    token&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; :=&lt;/span&gt;&lt;span&gt; uuid&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;NewString&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ok&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; :=&lt;/span&gt;&lt;span&gt; l&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;redis&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;SetNX&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; key&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; token&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; ttl&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Result&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; token&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; ok&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// Unlock: 仅持有者可释放（Lua脚本保证原子性）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;var&lt;/span&gt;&lt;span&gt; unlockScript&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; redis&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;NewScript&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(`&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;if redis.call(&amp;#39;get&amp;#39;, KEYS[1]) == ARGV[1] then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;  return redis.call(&amp;#39;del&amp;#39;, KEYS[1])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;  return 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;end&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;`)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;l &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span&gt;Locker&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Unlock&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ctx context&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;Context&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; key&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; token&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;bool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; error&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    res&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; :=&lt;/span&gt;&lt;span&gt; unlockScript&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Run&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; l&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;redis&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, []&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;},&lt;/span&gt;&lt;span&gt; token&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Result&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; res&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;int64&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;事务消息可靠投递（Outbox + Kafka）：&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// language: go&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// Worker周期拉取未投递的Outbox记录，发布到Kafka并标记完成（含幂等Key）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;w &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span&gt;OutboxWorker&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Run&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ctx context&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;Context&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; error&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        msgs&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; :=&lt;/span&gt;&lt;span&gt; w&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;repo&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;FetchPending&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 100&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; != nil&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        for&lt;/span&gt;&lt;span&gt; _&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; m&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; := range&lt;/span&gt;&lt;span&gt; msgs&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            key&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; :=&lt;/span&gt;&lt;span&gt; m&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;TraceID&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            if&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; :=&lt;/span&gt;&lt;span&gt; w&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;kafka&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Produce&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; m&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;Topic&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; key&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; m&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;Payload&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; err&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; != nil&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;                continue&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; // 重试留给下次周期&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            _&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; w&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;repo&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;MarkDone&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ctx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; m&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;ID&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; // 容错处理（可用事务或两阶段）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        time&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Sleep&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;500&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; *&lt;/span&gt;&lt;span&gt; time&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;Millisecond&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;/inventory-service-call-sequence.svg&quot; alt=&quot;服务调用时序&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;h1 id=&quot;7-xing-neng-you-hua&quot;&gt;7. 性能优化&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;缓存策略：SKU维度缓存&lt;code&gt;available/locked&lt;/code&gt;与活动池；写路径旁路缓存并以消息驱动刷新；&lt;/li&gt;
&lt;li&gt;批量优化：合并锁定/扣减请求，DB批量更新与流水写入；&lt;/li&gt;
&lt;li&gt;热点分散：分片Key、队列多分片与令牌桶节流；&lt;/li&gt;
&lt;li&gt;压测数据（示例，10k SKU，并发1k）：
&lt;ul&gt;
&lt;li&gt;基线：P99延迟 85ms，QPS 12k，库存准确率 99.98%；&lt;/li&gt;
&lt;li&gt;优化后（缓存+批量+热点分散）：P99 28ms，QPS 35k，准确率 99.995%。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/inventory-performance-optimization-flow.svg&quot; alt=&quot;性能优化流程&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;h1 id=&quot;8-jian-kong-yu-bao-jing&quot;&gt;8. 监控与报警&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;指标：库存准确度偏差、锁等待队列、Outbox滞留、Kafka Lag、DB死锁、Redis饱和度；&lt;/li&gt;
&lt;li&gt;异常自动恢复：锁泄漏清理、过期订单批量回滚、消息重放与对账修复；&lt;/li&gt;
&lt;li&gt;报警规则：阈值、突增检测与抑制；业务级（活动池耗尽、分仓失败率）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/inventory-monitoring-alert-architecture.svg&quot; alt=&quot;监控与报警架构&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;h1 id=&quot;jing-yan-jiao-xun&quot;&gt;经验教训&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;原子动作必须围绕主表行锁+流水+消息的一致性闭环；&lt;/li&gt;
&lt;li&gt;活动库存与常规库存要分池管理，避免互相挤占；&lt;/li&gt;
&lt;li&gt;秒杀优化优先“限流+预锁+异步对账“的组合拳；&lt;/li&gt;
&lt;li&gt;可靠投递与幂等key是分布式一致性的生命线；&lt;/li&gt;
&lt;li&gt;监控告警以“业务可用性“为主线，而非只看基础设施指标。&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>基于 Filebeat、Kafka、Flink、ES、ClickHouse、HBase 的日志系统建设</title>
        <published>2025-10-25T00:00:00+00:00</published>
        <updated>2025-10-25T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/log-system-filebeat-kafka-flink-es-clickhouse-hbase/"/>
        <id>https://scp.net.cn/blog/log-system-filebeat-kafka-flink-es-clickhouse-hbase/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/log-system-filebeat-kafka-flink-es-clickhouse-hbase/">&lt;h1 id=&quot;gai-lan&quot;&gt;概览&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;目标：构建可扩展、低延迟、可检索与可分析的日志平台，支持实时处理与历史归档。&lt;/li&gt;
&lt;li&gt;数据流：&lt;code&gt;Filebeat → Kafka → Flink → {Elasticsearch | ClickHouse | HBase}&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;架构图：
&lt;img src=&quot;/log-system-architecture.svg&quot; alt=&quot;系统架构&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;1-xi-tong-jia-gou-she-ji&quot;&gt;1. 系统架构设计&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;角色定位
&lt;ul&gt;
&lt;li&gt;Filebeat：轻量采集器，支持多源文件、容器日志，提供行聚合、过滤与缓冲，向 Kafka 可靠投递。&lt;/li&gt;
&lt;li&gt;Kafka：日志总线与缓冲层，解耦生产与消费，提供分区并行与持久化，作为 Flink Source。&lt;/li&gt;
&lt;li&gt;Flink：实时计算引擎，做清洗、解析、路由与指标聚合，Exactly-Once 输出至各存储。&lt;/li&gt;
&lt;li&gt;Elasticsearch：面向检索与可视化（Kibana），适合结构化/半结构化日志快速查询。&lt;/li&gt;
&lt;li&gt;ClickHouse：面向多维分析与聚合（OLAP），高吞吐写入与秒级分析，适合报表与趋势洞察。&lt;/li&gt;
&lt;li&gt;HBase：长周期明细存储与宽表查询，支撑低频但深度明细回溯。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;高可用与容错
&lt;ul&gt;
&lt;li&gt;Filebeat：内置重试与持久队列（spool）；Kafka 端启用 &lt;code&gt;acks=all&lt;/code&gt; 与幂等写。&lt;/li&gt;
&lt;li&gt;Kafka：Broker 多副本+ISR，控制器自动选举；跨机房可启用 MirrorMaker2。&lt;/li&gt;
&lt;li&gt;Flink：Checkpoint+Savepoint，RocksDB 状态后端，事务性 Sink（两阶段提交）。&lt;/li&gt;
&lt;li&gt;Elasticsearch：索引副本与 ILM 滚动；跨集群搜索可做容灾；&lt;/li&gt;
&lt;li&gt;ClickHouse：分片+副本，ReplicatedMergeTree，失败节点自动恢复；&lt;/li&gt;
&lt;li&gt;HBase：HDFS 冗余、RegionServer 自动迁移，ZK 保证一致性。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;2-ji-shu-xuan-xing-fen-xi&quot;&gt;2. 技术选型分析&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;选择考量与对比
&lt;ul&gt;
&lt;li&gt;Filebeat vs Fluent Bit：生态与可维护性、配置一致性；FB 多模块成熟，FB→Kafka 链路稳定。&lt;/li&gt;
&lt;li&gt;Kafka vs Pulsar：Kafka 在日志生态与 Flink Source 上成熟；事务性写与生态工具完备。&lt;/li&gt;
&lt;li&gt;Flink vs Spark Streaming：更低延迟与原生事件时间，Exactly-Once 更易实现。&lt;/li&gt;
&lt;li&gt;ES vs OpenSearch：社区与商业支持综合评估；选 ES 8.x 以简化部署与安全集成。&lt;/li&gt;
&lt;li&gt;ClickHouse vs Druid：写入吞吐与查询延迟综合更优，维护成本低；&lt;/li&gt;
&lt;li&gt;HBase vs Cassandra：基于 HDFS 的生态整合与线性扩展、适合明细长保留。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;版本建议与兼容性
&lt;ul&gt;
&lt;li&gt;Kafka 3.x（带 KRaft 或 ZK）、Flink ≥1.17、ES 8.x、ClickHouse ≥23.x、HBase 2.x、JDK 17。&lt;/li&gt;
&lt;li&gt;序列化：JSON 起步，推荐 Avro/Protobuf+Schema Registry，便于演进与兼容。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;性能基准（示例环境：8C32G+NVMe，千兆网）
&lt;ul&gt;
&lt;li&gt;Kafka 单 Broker 吞吐（LZ4 压缩，批量写）：≥150k msg/s（1KB）；&lt;/li&gt;
&lt;li&gt;Flink 端到端延迟（解析+路由）：p95 ≤ 300ms；&lt;/li&gt;
&lt;li&gt;ES 索引速率：单节点 ≥20k doc/s（bulk 5k，刷新 5s）；&lt;/li&gt;
&lt;li&gt;ClickHouse 插入：≥150MB/s（HTTP batch）；&lt;/li&gt;
&lt;li&gt;HBase Put：≥50k row/s（批量 1k，Async 客户端）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;3-he-xin-shi-xian-xi-jie&quot;&gt;3. 核心实现细节&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Filebeat 配置&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;filebeat.inputs&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; log&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    paths&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: [&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;/var/log/app/*.log&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    multiline.pattern&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;^\[&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    multiline.negate&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    multiline.match&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; after&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    fields&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: {&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;app&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; myapp&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; env&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; prod&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    processors&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; drop_event&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;          when&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;            equals&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: {&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;log.level&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;debug&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;output.kafka&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;  hosts&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: [&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;kafka1:9092&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;kafka2:9092&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;  topic&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;logs.raw&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;  compression&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; lz4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;  partition.round_robin&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    reachable_only&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;  required_acks&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; -1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;  bulk_max_size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2048&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Kafka 主题规划
&lt;ul&gt;
&lt;li&gt;命名：&lt;code&gt;logs.{env}.{app}.{type}&lt;/code&gt;；分区数按峰值吞吐与消费者并行度估算；RF≥3。&lt;/li&gt;
&lt;li&gt;Producer：&lt;code&gt;acks=all&lt;/code&gt;、&lt;code&gt;enable.idempotence=true&lt;/code&gt;、&lt;code&gt;linger.ms=5-20&lt;/code&gt;、&lt;code&gt;batch.size=64-256KB&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;保留：热数据 7-14 天，冷归档转对象存储或 CH/HBase。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Flink 处理主线（Java 示例）&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;StreamExecutionEnvironment&lt;/span&gt;&lt;span&gt; env&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; StreamExecutionEnvironment&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getExecutionEnvironment&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;env&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;enableCheckpointing&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;30000&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Properties&lt;/span&gt;&lt;span&gt; props&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Properties&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;props&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;bootstrap.servers&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;kafka1:9092&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;FlinkKafkaConsumer&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; source&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; FlinkKafkaConsumer&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&amp;gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;logs.raw&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; SimpleStringSchema&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(),&lt;/span&gt;&lt;span&gt; props&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;DataStream&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; raw&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; env&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;addSource&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;source&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;DataStream&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;LogEvent&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; parsed&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; raw&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;Json&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;::&lt;/span&gt;&lt;span&gt;parse&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;assignTimestampsAndWatermarks&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(...)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 分流：检索类 → ES，分析类 → CH，明细长保留 → HBase&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;SideOutput&lt;/span&gt;&lt;span&gt; esOut&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; ...&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; SideOutput&lt;/span&gt;&lt;span&gt; chOut&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; ...&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; SideOutput&lt;/span&gt;&lt;span&gt; hbaseOut&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; ...&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;parsed&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;process&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; RouterFn&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;esOut&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; chOut&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; hbaseOut&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// Elasticsearch sink（bulk，低刷新）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;parsed&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getSideOutput&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;esOut&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;addSink&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;EsSink&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;bulk&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;http://es:9200&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;logs-idx&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// ClickHouse sink（HTTP insert）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;parsed&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getSideOutput&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;chOut&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;addSink&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ClickHouseSink&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;http&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;http://ch:8123&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;INSERT INTO logs VALUES (?, ?, ?)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// HBase sink（Async Put）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;parsed&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getSideOutput&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;hbaseOut&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;addSink&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;HBaseSink&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;zookeeper:2181&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;logs:evt&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;env&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;execute&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;log-pipeline&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Elasticsearch 索引与分片&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;settings&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;number_of_shards&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;number_of_replicas&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;refresh_interval&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;5s&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;index.translog.durability&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;mappings&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;properties&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;@timestamp&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;app&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;keyword&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;level&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;keyword&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;text&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;ClickHouse 表设计&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;CREATE TABLE&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; logs&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ts &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;DateTime&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  app String,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  level&lt;/span&gt;&lt;span&gt; LowCardinality(String),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  message&lt;/span&gt;&lt;span&gt; String&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) ENGINE &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt; MergeTree&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;PARTITION BY&lt;/span&gt;&lt;span&gt; toDate(ts)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;ORDER BY&lt;/span&gt;&lt;span&gt; (ts, app)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;SETTINGS index_granularity &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 8192&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;HBase RowKey 与列族&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;RowKey: &amp;lt;rev_ts&amp;gt;&amp;lt;tenant&amp;gt;&amp;lt;app&amp;gt;&amp;lt;hash&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CF: d (detail), m (meta)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;预分区：按时间与租户做 split；避免热点。&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;ri-zhi-cai-ji-mo-kuai-pei-zhi-rong-qi-yu-zhu-ji&quot;&gt;日志采集模块配置（容器与主机）&lt;/h2&gt;
&lt;h3 id=&quot;rong-qi-huan-jing-ri-zhi-cai-ji&quot;&gt;容器环境日志采集&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;采集 Docker 标准输出（stdout/stderr）
&lt;ul&gt;
&lt;li&gt;方法 A（文件采集）：Docker 默认 &lt;code&gt;json-file&lt;/code&gt; 驱动将容器日志写入 &lt;code&gt;/var/lib/docker/containers/&amp;lt;cid&amp;gt;/&amp;lt;cid&amp;gt;-json.log&lt;/code&gt;。&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;filebeat.inputs&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; log&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    enabled&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    paths&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /var/lib/docker/containers/*/*-json.log&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    processors&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; add_docker_metadata&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;          host&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;unix:///var/run/docker.sock&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  # 通过 Docker API 增强容器元数据&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; decode_json_fields&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;          fields&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: [&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;          target&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;json&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;          overwrite_keys&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    multiline.pattern&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;^{&amp;quot;log&amp;quot;:&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;   # 若应用以多行日志写入一条 JSON，可按需开启&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    multiline.negate&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    multiline.match&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; after&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;方法 B（容器输入）：使用 &lt;code&gt;type: container&lt;/code&gt; 读取容器运行时日志（支持 Docker/Containerd CRI），适合 K8s。&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;filebeat.inputs&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; container&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    enabled&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    paths&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /var/log/containers/*.log&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  # Kubernetes CRI 标准路径&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    processors&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; add_kubernetes_metadata&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;          host&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; ${NODE_NAME}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;          matchers&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            -&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; logs_path&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;                logs_path&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;/var/log/containers/&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  # 基于路径匹配 Pod/容器元数据&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; drop_event&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;          when&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;            equals&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;              kubernetes.labels.log_level&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;debug&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  # 示例：按标签过滤低价值日志&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;容器日志文件挂载采集
&lt;ul&gt;
&lt;li&gt;为 Filebeat 容器挂载主机日志目录与 Docker/K8s 元数据接口：
&lt;ul&gt;
&lt;li&gt;Docker：挂载 &lt;code&gt;/var/lib/docker/containers&lt;/code&gt; 与 &lt;code&gt;/var/run/docker.sock&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;K8s：挂载 &lt;code&gt;/var/log/containers&lt;/code&gt;、&lt;code&gt;/var/log/pods&lt;/code&gt;、&lt;code&gt;/var/lib/docker/containers&lt;/code&gt;（取决于运行时）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Kubernetes DaemonSet 部署示例&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;apiVersion&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; apps/v1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;kind&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; DaemonSet&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;metadata&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;  name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; filebeat&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;  namespace&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; logging&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;spec&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;  selector&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    matchLabels&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: {&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;app&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; filebeat&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;  template&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    metadata&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;      labels&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: {&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;app&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; filebeat&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    spec&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;      serviceAccountName&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; filebeat&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;      hostNetwork&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;      dnsPolicy&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; ClusterFirstWithHostNet&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;      containers&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        -&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; filebeat&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;          image&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; docker.elastic.co/beats/filebeat:8.12.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;          args&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: [&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;-c&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;/etc/filebeat.yml&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;-e&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;          env&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            -&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; NODE_NAME&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;              valueFrom&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: {&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;fieldRef&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: {&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;fieldPath&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; spec.nodeName&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;          volumeMounts&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            - {&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; config&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; mountPath&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /etc/filebeat.yml&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; subPath&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; filebeat.yml&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            - {&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; varlog&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; mountPath&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /var/log&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            - {&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; containers&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; mountPath&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /var/lib/docker/containers&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; readOnly&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            - {&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; dockersock&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; mountPath&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /var/run/docker.sock&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;          securityContext&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;            runAsUser&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;      volumes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        -&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; config&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;          configMap&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: {&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; filebeat-config&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        -&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; varlog&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;          hostPath&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: {&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;path&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /var/log&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        -&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; containers&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;          hostPath&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: {&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;path&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /var/lib/docker/containers&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        -&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; dockersock&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;          hostPath&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: {&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;path&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /var/run/docker.sock&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;apiVersion&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; v1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;kind&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; ConfigMap&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;metadata&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;  name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; filebeat-config&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;  namespace&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; logging&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;  filebeat.yml&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;    filebeat.inputs:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;      - type: container&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;        enabled: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;        paths:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;          - /var/log/containers/*.log&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;        processors:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;          - add_kubernetes_metadata:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;              host: ${NODE_NAME}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;              matchers:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;                - logs_path:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;                    logs_path: &amp;quot;/var/log/containers/&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;    output.kafka:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;      hosts: [&amp;quot;kafka1:9092&amp;quot;,&amp;quot;kafka2:9092&amp;quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;      topic: &amp;quot;logs.raw&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;      partition.round_robin.reachable_only: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;      compression: lz4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;      required_acks: -1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;容器元数据增强
&lt;ul&gt;
&lt;li&gt;Docker：&lt;code&gt;add_docker_metadata&lt;/code&gt; 通过 Docker API 提取容器名、镜像、标签等；&lt;/li&gt;
&lt;li&gt;Kubernetes：&lt;code&gt;add_kubernetes_metadata&lt;/code&gt; 注入 Pod/Namespace/Labels/Annotations；可用 &lt;code&gt;drop_event&lt;/code&gt;/&lt;code&gt;drop_fields&lt;/code&gt; 做过滤与瘦身。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;zhu-ji-huan-jing-ri-zhi-cai-ji&quot;&gt;主机环境日志采集&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;采集系统日志（syslog/auth/journald）
&lt;ul&gt;
&lt;li&gt;使用系统模块（推荐）：&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;filebeat.modules&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; module&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; system&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    syslog&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;      enabled&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;      var.paths&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: [&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;/var/log/syslog&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;/var/log/messages&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    auth&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;      enabled&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;      var.paths&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: [&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;/var/log/auth.log&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;/var/log/secure&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;或文件输入（通用）：&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;filebeat.inputs&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; log&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    paths&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /var/log/*.log&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /var/log/nginx/*.log&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    multiline.pattern&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;^\\[&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  # 以时间/方括号开始的堆栈等多行&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    multiline.negate&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    multiline.match&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; after&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    fields_under_root&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    fields&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;      host.role&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;web&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;      env&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;prod&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    processors&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; drop_fields&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: {&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;fields&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: [&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;log.offset&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;input.type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; rename&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;          fields&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            -&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;host.name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;              to&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;hostname&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;主机标签与自定义字段
&lt;ul&gt;
&lt;li&gt;使用 &lt;code&gt;fields&lt;/code&gt; 与 &lt;code&gt;fields_under_root: true&lt;/code&gt; 直接展开到事件根，提高检索友好性；配合 &lt;code&gt;tags: [prod, region-cn]&lt;/code&gt; 标注环境。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;日志轮转与归档建议
&lt;ul&gt;
&lt;li&gt;应用侧启用 &lt;code&gt;logrotate&lt;/code&gt; 或等效机制，控制单文件大小与保留周期；&lt;/li&gt;
&lt;li&gt;Filebeat 相关参数：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;close_inactive: 5m&lt;/code&gt;（无新数据关闭文件句柄）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;clean_inactive: 168h&lt;/code&gt;（长时间无活动的文件从注册表清理）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ignore_older: 24h&lt;/code&gt;（忽略过久文件）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;scan_frequency: 10s&lt;/code&gt;（扫描新文件频率）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;tong-yong-pei-zhi-yao-qiu&quot;&gt;通用配置要求&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;完整的 &lt;code&gt;filebeat.yml&lt;/code&gt; 示例（容器与主机通用骨架）&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;filebeat.inputs&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  -&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; log&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    enabled&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    paths&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: [&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;/var/log/app/*.log&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    multiline.pattern&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;^\\[&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    multiline.negate&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    multiline.match&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; after&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    processors&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; drop_event&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;          when&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;            equals&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: {&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;log.level&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;debug&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; decode_json_fields&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;          fields&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: [&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;          target&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;json&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;          overwrite_keys&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; add_docker_metadata&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;          host&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;unix:///var/run/docker.sock&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      -&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; add_kubernetes_metadata&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;          host&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; ${NODE_NAME}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;output.kafka&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;  hosts&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: [&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;kafka1:9092&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;kafka2:9092&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;  topic&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;logs.raw&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;  compression&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; lz4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;  partition.round_robin.reachable_only&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;  required_acks&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; -1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;  client_id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;filebeat-prod&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;  max_message_bytes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1000000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 安全（示例，按需启用）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# ssl.certificate_authorities: [&amp;quot;/etc/ssl/ca.pem&amp;quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# sasl.mechanism: scram-sha-512&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# username: &amp;quot;beat_user&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# password: &amp;quot;secret&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 监控接口&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;http.enabled&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;http.host&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0.0.0.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;http.port&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 5066&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;logging.level&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; info&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;logging.selectors&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: [&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;publish&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;processors&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;过滤与字段处理
&lt;ul&gt;
&lt;li&gt;首选在采集侧做降噪：&lt;code&gt;drop_event&lt;/code&gt;、&lt;code&gt;drop_fields&lt;/code&gt;、&lt;code&gt;dissect&lt;/code&gt;/&lt;code&gt;decode_json_fields&lt;/code&gt;、&lt;code&gt;rename&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;统一时间戳：&lt;code&gt;timestamp&lt;/code&gt; 处理器将自定义时间字段映射到 &lt;code&gt;@timestamp&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Kafka 输出参数说明
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;required_acks=-1&lt;/code&gt;（all ISR 确认）、&lt;code&gt;compression=lz4&lt;/code&gt;、&lt;code&gt;max_message_bytes&lt;/code&gt; 控制单消息大小；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;partition.round_robin.reachable_only=true&lt;/code&gt; 避免不可达分区；&lt;code&gt;client_id&lt;/code&gt; 标识采集实例；&lt;/li&gt;
&lt;li&gt;安全：SASL SCRAM 与 SSL 证书链；生产环境建议启用加密与认证。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;性能与安全建议
&lt;ul&gt;
&lt;li&gt;控制输入文件数量与 &lt;code&gt;harvester_limit&lt;/code&gt;，避免句柄耗尽；&lt;/li&gt;
&lt;li&gt;合理 &lt;code&gt;bulk_max_size&lt;/code&gt; 与 Kafka 端 &lt;code&gt;linger.ms&lt;/code&gt;/&lt;code&gt;batch.size&lt;/code&gt; 匹配；&lt;/li&gt;
&lt;li&gt;采集侧最小权限运行，限制可读取路径；容器中避免特权运行。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;yan-zheng-fang-an&quot;&gt;验证方案&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;功能验证
&lt;ul&gt;
&lt;li&gt;本地：&lt;code&gt;filebeat test output&lt;/code&gt; 检查与 Kafka 的连通；&lt;code&gt;filebeat -e -d &quot;publish&quot;&lt;/code&gt; 观察事件发送；&lt;/li&gt;
&lt;li&gt;端到端：使用 &lt;code&gt;kcat -C -b kafka1:9092 -t logs.raw -o -10&lt;/code&gt; 拉取最新评论，校验字段；&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;常见问题排查
&lt;ul&gt;
&lt;li&gt;容器元数据缺失：检查是否挂载 &lt;code&gt;/var/run/docker.sock&lt;/code&gt; 或正确配置 &lt;code&gt;add_kubernetes_metadata&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;多行合并异常：确认 &lt;code&gt;multiline.pattern&lt;/code&gt; 与日志格式匹配，适当调整 &lt;code&gt;timeout&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;无法读取文件：校验路径与权限，确认 Filebeat 运行用户与宿主机挂载；&lt;/li&gt;
&lt;li&gt;Kafka 429/缓慢：检查 &lt;code&gt;required_acks&lt;/code&gt;、网络与批量参数，监控 broker 队列与磁盘；&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;性能监控配置建议
&lt;ul&gt;
&lt;li&gt;启用 &lt;code&gt;http.enabled: true&lt;/code&gt; 暴露指标（&lt;code&gt;/stats&lt;/code&gt;），采集 &lt;code&gt;beat.events&lt;/code&gt;、&lt;code&gt;harvester.open_files&lt;/code&gt;、&lt;code&gt;output.events&lt;/code&gt; 成功/失败；&lt;/li&gt;
&lt;li&gt;用 Prometheus 抓取并设置告警：采集速率低于预期、发送失败率升高、打开文件数异常增长。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;4-xing-neng-you-hua-jing-yan&quot;&gt;4. 性能优化经验&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Filebeat：&lt;code&gt;bulk_max_size&lt;/code&gt; 调整批量；启用持久队列；过滤低价值日志降低链路压力。&lt;/li&gt;
&lt;li&gt;Kafka：合适分区数与 RF；Broker &lt;code&gt;num.network.threads&lt;/code&gt;/&lt;code&gt;socket.send.buffer.bytes&lt;/code&gt;；启用 LZ4；控制批大小与 linger。&lt;/li&gt;
&lt;li&gt;Flink：优化并行度与算子链；RocksDB state、增大 &lt;code&gt;write-buffer-size&lt;/code&gt;；Checkpoint 间隔与超时合理化。&lt;/li&gt;
&lt;li&gt;ES：降低刷新频率（5-10s）、增大 &lt;code&gt;indexing.buffer&lt;/code&gt;、合理分片；使用 ILM 滚动与冷/温节点。&lt;/li&gt;
&lt;li&gt;CH：控制 parts 数量，批量写入；&lt;code&gt;max_insert_block_size&lt;/code&gt;、&lt;code&gt;max_threads&lt;/code&gt; 调优；后台合并监控。&lt;/li&gt;
&lt;li&gt;HBase：RowKey 防热点；&lt;code&gt;memstore&lt;/code&gt;/&lt;code&gt;blockcache&lt;/code&gt; 调整；Major/Minor compaction 节奏。&lt;/li&gt;
&lt;li&gt;容量规划：按峰值吞吐与增长率规划分区/分片/Region 数量，留有 30% 余量。&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;5-yun-wei-jian-kong-fang-an&quot;&gt;5. 运维监控方案&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;指标
&lt;ul&gt;
&lt;li&gt;Filebeat：harvesters、publish queue 使用率、掉包率。&lt;/li&gt;
&lt;li&gt;Kafka：ISR、Under-Replicated Partitions、Consumer Lag、请求队列长度。&lt;/li&gt;
&lt;li&gt;Flink：Backpressure、Checkpoint Time/Fail、Task Failures。&lt;/li&gt;
&lt;li&gt;ES：JVM heap、GC、Indexing rate、Query p95/p99、Threadpool 队列。&lt;/li&gt;
&lt;li&gt;CH：parts 数、后台 merges、replication lag、查询耗时分布。&lt;/li&gt;
&lt;li&gt;HBase：RegionServer 负载、Compaction、读写延迟。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;告警阈值示例（PromQL）&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;kafka_server_replica_manager_underreplicatedpartitions &amp;gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sum(rate(es_indexing_index_total[5m])) &amp;lt; expected_rate * 0.7&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;运维清单：滚动升级、备份与快照、容量巡检、索引与表维护、Checkpoint 与 Savepoint 验证。&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;6-shi-ji-ying-yong-an-li-shi-li&quot;&gt;6. 实际应用案例（示例）&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;规模：日均 2TB，峰值 250k events/s；端到端 p95 ≤ 500ms。&lt;/li&gt;
&lt;li&gt;查询：ES 关键词检索 p95 ≤ 200ms；CH 1 亿行聚合 p95 ≤ 2s。&lt;/li&gt;
&lt;li&gt;价值：统一日志入口、降低故障定位时间 ≥50%，支持审计与增长分析。&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;7-bu-shu-jiao-ben-shi-li-pian-duan&quot;&gt;7. 部署脚本示例（片段）&lt;/h1&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;#!/usr/bin/env bash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -euo pipefail&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 安装并启动 Filebeat（示例）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;apt-get&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; update&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; apt-get&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; install -y filebeat&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;cp&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; filebeat.yml /etc/filebeat/filebeat.yml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;systemctl&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; enable filebeat&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; systemctl&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; restart filebeat&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# Kafka Producer 依赖 JDK&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;export&lt;/span&gt;&lt;span&gt; JAVA_HOME&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt;/usr/lib/jvm/java-17-openjdk-amd64&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# Flink 提交示例&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;flink&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; run -c com.example.LogPipeline ./log-pipeline.jar&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&quot;8-dian-xing-wen-ti-yu-jie-jue&quot;&gt;8. 典型问题与解决&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Kafka 负载不均：分区键散列不均导致热点 → 优化 Key 与增加分区。&lt;/li&gt;
&lt;li&gt;Flink Checkpoint 失败：外部存储带宽不足 → 升级存储与拉长间隔、压缩状态。&lt;/li&gt;
&lt;li&gt;ES 写入 429：线程池队列满 → 降低刷新频率、调大 bulk、限流入口。&lt;/li&gt;
&lt;li&gt;CH parts 过多：小批次写导致合并压力 → 增大批次与控制并发。&lt;/li&gt;
&lt;li&gt;HBase 热点 Region：RowKey 顺序导致集中 → 前缀散列或反转时间戳。&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;9-dui-bi-chuan-tong-fang-an-de-gai-jin&quot;&gt;9. 对比传统方案的改进&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;相比仅 ELK：引入 Kafka 与 Flink 实现解耦与实时计算；ClickHouse/HBase 提供高效分析与长期明细，整体可用性与扩展性更佳。&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;10-jia-gou-yan-jin-fang-xiang&quot;&gt;10. 架构演进方向&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Schema Registry+Avro/Protobuf；Kafka 分层存储；Flink Stateful Functions；ES 冷/温节点与 CCR；ClickHouse 对象存储分层；HBase 与 Data Lake（Iceberg/Hudi）打通。&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;hou-tai-kong-zhi-xi-tong-xiang-xi-she-ji&quot;&gt;后台控制系统详细设计&lt;/h1&gt;
&lt;p&gt;为支撑日志平台的可配置性、查询可扩展性与稳定告警能力，设计统一的后台控制系统，包含采集配置模块、查询分析模块与日志告警模块。每个模块提供架构图、技术选型、性能指标、接口定义与异常处理及一致性保障方案。&lt;/p&gt;
&lt;h2 id=&quot;1-cai-ji-pei-zhi-mo-kuai&quot;&gt;1) 采集配置模块&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;架构设计图：
&lt;img src=&quot;/backend-control-config-architecture.svg&quot; alt=&quot;采集配置中心架构&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;关键技术选型说明&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;配置中心：&lt;code&gt;PostgreSQL&lt;/code&gt; 存储配置与审计，&lt;code&gt;Git&lt;/code&gt; 作为版本库（拉取与回滚），&lt;code&gt;etcd/Consul&lt;/code&gt; 用于轻量型在线 KV 与 Watch；通过 &lt;code&gt;OpenAPI&lt;/code&gt; 提供读写接口。&lt;/li&gt;
&lt;li&gt;变更分发：&lt;code&gt;Kafka&lt;/code&gt; 主题 &lt;code&gt;config-updates&lt;/code&gt; 广播配置变更；&lt;code&gt;Flink&lt;/code&gt;/微服务消费后生成增量快照。&lt;/li&gt;
&lt;li&gt;Agent 管理：Filebeat、Fluent Bit、自研采集代理统一通过 &lt;code&gt;HTTPS/gRPC&lt;/code&gt; 拉取配置或被动订阅；支持多协议采集（HTTP/HTTPS/TCP/UDP）。&lt;/li&gt;
&lt;li&gt;校验与灰度：配置 Schema（&lt;code&gt;JSON Schema&lt;/code&gt;/&lt;code&gt;Protobuf&lt;/code&gt;）校验，支持批次灰度与逐步扩散；失败自动回滚。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;配置项设计&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;采集频率：&lt;code&gt;scan_frequency&lt;/code&gt;、&lt;code&gt;harvester_limit&lt;/code&gt;、&lt;code&gt;ignore_older/close_inactive&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;数据格式：&lt;code&gt;json/line/custom&lt;/code&gt;，字段映射与 &lt;code&gt;decode_json_fields/dissect&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;过滤规则：&lt;code&gt;drop_event/drop_fields/rename/timestamp&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;协议参数：HTTP/HTTPS（&lt;code&gt;headers/auth/timeout&lt;/code&gt;）、TCP/UDP（&lt;code&gt;host/port/max_message_bytes&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;版本控制：每次提交生成 &lt;code&gt;versionId&lt;/code&gt;（Git commit），支持标签与回滚；所有变更留审计轨迹。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;性能指标要求&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;吞吐：配置读取 &lt;code&gt;p99 ≥ 2k rps&lt;/code&gt;；写入 &lt;code&gt;p99 ≥ 200 rps&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;传播延迟：集群内 &lt;code&gt;p95 ≤ 5s&lt;/code&gt; 到达所有在线 Agent。&lt;/li&gt;
&lt;li&gt;可用性：&lt;code&gt;≥ 99.95%&lt;/code&gt;（双活/主备部署）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;与其他模块交互接口定义&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;REST/gRPC（示例）：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;POST /api/v1/configs&lt;/code&gt;（创建配置，返回 &lt;code&gt;versionId&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /api/v1/configs/{id}&lt;/code&gt;（读取配置）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;POST /api/v1/configs/{id}/deploy?strategy=canary&lt;/code&gt;（灰度发布）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;POST /api/v1/configs/{id}/rollback&lt;/code&gt;（版本回滚）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Kafka：&lt;code&gt;topic=config-updates&lt;/code&gt;（key: &lt;code&gt;agentId/group&lt;/code&gt;，value: &lt;code&gt;configVersion&lt;/code&gt;）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;异常处理与一致性保障&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;乐观并发控制（&lt;code&gt;version&lt;/code&gt; 字段）；写前校验与写后审计。&lt;/li&gt;
&lt;li&gt;分发失败重试与死信队列（DLQ）；Agent 端本地快照与超时回退策略。&lt;/li&gt;
&lt;li&gt;事件顺序保障：&lt;code&gt;configVersion&lt;/code&gt; 单调递增，Agent 只接受更高版本；幂等应用。&lt;/li&gt;
&lt;li&gt;部署回滚与熔断：批次灰度监控异常触发自动回滚；对下游 Kafka/HTTP 超时启用熔断。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;2-cha-xun-fen-xi-mo-kuai&quot;&gt;2) 查询分析模块&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;架构设计图：
&lt;img src=&quot;/backend-control-query-architecture.svg&quot; alt=&quot;查询分析引擎架构&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;关键技术选型说明&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;分布式查询引擎：&lt;code&gt;Trino/Presto&lt;/code&gt; 用于 SQL 跨源查询（ES/ClickHouse/HBase 适配器）；&lt;/li&gt;
&lt;li&gt;DSL 引擎：&lt;code&gt;Lucene/KQL&lt;/code&gt; 风格 DSL 转换为 ES 查询；复杂聚合落 CH 物化视图。&lt;/li&gt;
&lt;li&gt;缓存与索引优化：&lt;code&gt;Redis&lt;/code&gt; 查询结果缓存（Key=归一化查询+时间窗）；CH 物化视图与稀疏索引；ES 使用 &lt;code&gt;keyword&lt;/code&gt; 与 &lt;code&gt;nested&lt;/code&gt; 正确映射。&lt;/li&gt;
&lt;li&gt;路由层：根据查询类型与代价估算路由至 ES（检索）或 CH（聚合），支持双写兜底。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;多维聚合功能&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;维度：&lt;code&gt;app/env/host/region/userId&lt;/code&gt; 等，支持 &lt;code&gt;group by/rollup/cube&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;时间窗：&lt;code&gt;HOPPING/TUMBLING/SLIDING&lt;/code&gt;；预聚合表加速报表查询。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;性能指标要求&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;吞吐：并发查询 &lt;code&gt;p99 ≥ 500 qps&lt;/code&gt;（缓存命中场景）；&lt;/li&gt;
&lt;li&gt;延迟：实时检索 &lt;code&gt;p95 ≤ 300ms&lt;/code&gt;（ES）；重聚合 &lt;code&gt;p95 ≤ 2s&lt;/code&gt;（CH）；&lt;/li&gt;
&lt;li&gt;可用性：&lt;code&gt;≥ 99.9%&lt;/code&gt;，路由层与引擎多副本。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;与其他模块交互接口定义&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;HTTP/WS：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;POST /api/v1/query/sql&lt;/code&gt;（body: SQL，支持分页与超时）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;POST /api/v1/query/dsl&lt;/code&gt;（body: DSL，支持流式返回）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /api/v1/query/{id}/status&lt;/code&gt;（异步查询状态）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;结果缓存：&lt;code&gt;GET /api/v1/query/cache/{hash}&lt;/code&gt;；&lt;code&gt;DELETE /api/v1/query/cache/{hash}&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;异常处理与一致性保障&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;超时与降级：超过 SLA 自动降级为预聚合与近似结果；&lt;/li&gt;
&lt;li&gt;重试与幂等：幂等查询 ID；后端重试限制与指数退避；&lt;/li&gt;
&lt;li&gt;数据一致性：跨源时间窗对齐；ES/CH 双写校验差异并标记结果版本；&lt;/li&gt;
&lt;li&gt;背压控制：路由层限流与队列；防止查询风暴。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;3-ri-zhi-gao-jing-mo-kuai&quot;&gt;3) 日志告警模块&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;架构设计图：
&lt;img src=&quot;/backend-control-alert-architecture.svg&quot; alt=&quot;日志告警引擎架构&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;关键技术选型说明&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;规则引擎：&lt;code&gt;Flink&lt;/code&gt; 流式评估（事件时间），支持多级告警（INFO/WARNING/ERROR/CRITICAL）；&lt;/li&gt;
&lt;li&gt;时间窗口：&lt;code&gt;Sliding/Tumbling&lt;/code&gt; 窗口，支持去重键与聚合阈值；&lt;/li&gt;
&lt;li&gt;通知通道：&lt;code&gt;SMTP&lt;/code&gt; 邮件、短信网关（&lt;code&gt;HTTP&lt;/code&gt; SDK）、&lt;code&gt;Webhook&lt;/code&gt;（签名校验与重试）；&lt;/li&gt;
&lt;li&gt;抑制与降噪：重复告警抑制、合并策略、秒级阈值与指数退避；支持维护窗口与静默策略。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;性能指标要求&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;吞吐：规则评估 &lt;code&gt;≥ 1M events/min&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;延迟：端到端告警触发 &lt;code&gt;p95 ≤ 5s&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;可用性：&lt;code&gt;≥ 99.9%&lt;/code&gt;，检查点与状态容灾。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;与其他模块交互接口定义&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;规则管理：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;POST /api/v1/alerts/rules&lt;/code&gt;（创建/更新，返回 &lt;code&gt;ruleId/version&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /api/v1/alerts/rules/{id}&lt;/code&gt;（读取）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;POST /api/v1/alerts/rules/{id}/disable&lt;/code&gt;（禁用）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;告警事件：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GET /api/v1/alerts/events?level=ERROR&amp;amp;window=1h&lt;/code&gt;（查询告警事件）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;POST /api/v1/alerts/notifications/test&lt;/code&gt;（通道联通性测试）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Kafka：&lt;code&gt;topic=alerts-input&lt;/code&gt;（原始事件），&lt;code&gt;topic=alerts-output&lt;/code&gt;（告警结果）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;异常处理与一致性保障&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Exactly-Once：Kafka + Flink 两阶段提交，通知端幂等；&lt;/li&gt;
&lt;li&gt;顺序与乱序：事件时间窗口处理，迟到数据允许度 &lt;code&gt;allowedLateness&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;抑制策略：重复告警聚合与限流，按 &lt;code&gt;dedupKey&lt;/code&gt; 与时间窗去重；&lt;/li&gt;
&lt;li&gt;故障自愈：checkpoint 失败报警与自动重启；通道失败重试与 DLQ。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Kafka 调优十招：原理、实践与取舍</title>
        <published>2025-10-23T10:00:00+08:00</published>
        <updated>2025-10-23T10:00:00+08:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/kafka-top-10-optimizations/"/>
        <id>https://scp.net.cn/blog/kafka-top-10-optimizations/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/kafka-top-10-optimizations/">&lt;h2 id=&quot;zhai-yao&quot;&gt;摘要&lt;/h2&gt;
&lt;p&gt;本文系统梳理提升 Kafka 吞吐与稳定性的十项关键调优，并结合生产经验给出参数示例、取舍建议与监控要点。内容涵盖主题分区、复制滞后、代理线程、生产者压缩、确认策略、消费者抓取、网络缓冲、KRaft 元数据超时、磁盘日志目录与复制因子。读完你可建立一套具备技术深度与工程可执行性的 Kafka 调优方法论。&lt;/p&gt;
&lt;h2 id=&quot;jia-gou-zong-lan-tu-jie&quot;&gt;架构总览（图解）&lt;/h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Producer → RecordAccumulator/Batch → Socket Send → NIC TX → Network&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                               ↓&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Broker Socket Receive → Broker Threads → Page Cache → Log Segments (log.dirs)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                               ↓&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Consumer Fetch → Socket Receive → Application&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;关键瓶颈通常出现在：分区并行度不足、复制滞后、网络/磁盘 IO 饱和、抓取批次过小或等待过长。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;1-zeng-jia-fen-qu-shu-liang-ti-gao-bing-xing-du&quot;&gt;1) 增加分区数量（提高并行度）&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;原理：分区是并行与扩展的基本单位，消费者组的并发度≈分区数。&lt;/li&gt;
&lt;li&gt;实践：热点主题优先扩分区，但避免超过消费者实例数太多导致上下文切换增多。&lt;/li&gt;
&lt;li&gt;命令示例：&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 增加主题分区数（注意不可减少）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;kafka-topics.sh&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; --bootstrap-server&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;broker:909&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;  --alter --topic orders --partitions&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 64&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;经验：批次大、压缩好时分区更易发挥并行优势；观察 &lt;code&gt;record-send-rate&lt;/code&gt; 与端到端延迟平衡扩分区节奏。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;2-kong-zhi-fu-zhi-zhi-hou-replica-lag-time-max-ms&quot;&gt;2) 控制复制滞后 replica.lag.time.max.ms&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;原理：跟随者滞后超过阈值会被踢出 ISR，影响持久性与写入确认路径。&lt;/li&gt;
&lt;li&gt;配置：&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# broker/server.properties&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 示例：5s，需结合网络/磁盘能力与延迟容忍度&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;replica.lag.time.max.ms&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&lt;/span&gt;&lt;span&gt;5000&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;取舍：滞后阈值太短易频繁出入 ISR，太长则风险积累；结合 &lt;code&gt;min.insync.replicas&lt;/code&gt; 与 &lt;code&gt;acks&lt;/code&gt; 联动。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;3-diao-zheng-dai-li-xian-cheng-num-network-threads-num-io-threads&quot;&gt;3) 调整代理线程 num.network.threads / num.io.threads&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;原理：网络线程负责连接与请求，IO 线程处理磁盘与日志操作。&lt;/li&gt;
&lt;li&gt;配置：&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# broker/server.properties&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;num.network.threads&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&lt;/span&gt;&lt;span&gt;8&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;num.io.threads&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&lt;/span&gt;&lt;span&gt;16&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;num.replica.fetchers&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;经验：磁盘为 SSD 且网络连接多时适当加大 IO/网络线程；监控线程池队列长度与请求处理时间。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;4-sheng-chan-zhe-ya-suo-compression-type&quot;&gt;4) 生产者压缩 compression.type&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;原理：减小网络传输与磁盘写入体积，提高吞吐；常用 lz4 兼顾速度与压缩率。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// Producer 配置示例（Java）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Properties&lt;/span&gt;&lt;span&gt; props&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Properties&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;props&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;bootstrap.servers&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;broker1:9092,broker2:9092&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;props&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;compression.type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;lz4&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;props&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;batch.size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 65536&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;       // 64KB 批次&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;props&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;linger.ms&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;            // 等待聚合&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;props&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;buffer.memory&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 67108864&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  // 64MB&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;经验：压缩在高吞吐场景收益明显；CPU 紧张或消息极小（&amp;lt;几百字节）时可降低 batch 或取消压缩。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;5-she-zhi-gua-dang-de-sheng-chan-zhe-que-ren-acks&quot;&gt;5) 设置适当的生产者确认 acks&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;原理：&lt;code&gt;acks=1&lt;/code&gt; 追求速度，&lt;code&gt;acks=all&lt;/code&gt; 追求持久性。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;props&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;acks&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;all&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;             // 强持久性，需配合 min.insync.replicas&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 低延迟场景可用：props.put(&amp;quot;acks&amp;quot;, &amp;quot;1&amp;quot;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;经验：关键交易流选择 &lt;code&gt;acks=all + min.insync.replicas&amp;gt;=2&lt;/code&gt;；日志/监控流可选 &lt;code&gt;acks=1&lt;/code&gt; 提升吞吐。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;6-xiao-fei-zhe-fetch-diao-you&quot;&gt;6) 消费者 Fetch 调优&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;原理：每次抓取的最小字节与最大等待影响吞吐与延迟。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# consumer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 1MB，增大以减少请求开销&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;fetch.min.bytes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&lt;/span&gt;&lt;span&gt;1048576&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 最长等待以凑满批次&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;fetch.max.wait.ms&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&lt;/span&gt;&lt;span&gt;50&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 每分区最大抓取&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;max.partition.fetch.bytes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&lt;/span&gt;&lt;span&gt;8388608&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;经验：延迟敏感业务降低 &lt;code&gt;fetch.max.wait.ms&lt;/code&gt;；吞吐优先业务增大 &lt;code&gt;fetch.min.bytes&lt;/code&gt; 与 &lt;code&gt;max.partition.fetch.bytes&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;7-socket-huan-chong-wang-luo-ceng-guan-jian&quot;&gt;7) Socket 缓冲（网络层关键）&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;原理：发送/接收缓冲影响突发流量可承载能力。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# broker/server.properties&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;socket.send.buffer.bytes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&lt;/span&gt;&lt;span&gt;262144&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;socket.receive.buffer.bytes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&lt;/span&gt;&lt;span&gt;262144&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# OS 层（Linux）建议上限&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;net.core.wmem_max = 134217728&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; sudo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; tee -a /etc/sysctl.conf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;net.core.rmem_max = 134217728&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; sudo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; tee -a /etc/sysctl.conf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; sysctl -p&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;经验：结合 NIC 驱动与 MTU 调优；观察丢包/重传与队列长度，避免过度放大导致内存占用攀升。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;8-kraft-yuan-shu-ju-chao-shi&quot;&gt;8) KRaft 元数据超时&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;原理：KRaft 替代 ZooKeeper，选举与元数据请求的超时影响控制面稳定性。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# broker/server.properties（KRaft 模式，具体参数名随版本差异）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;controller.quorum.election.timeout.ms&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&lt;/span&gt;&lt;span&gt;5000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;controller.quorum.request.timeout.ms&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&lt;/span&gt;&lt;span&gt;30000&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;经验：在网络抖动或控制器负载高时适当放宽；务必结合当前 Kafka 版本文档验证参数名与默认值。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;9-duo-mu-lu-log-dirs-you-hua-ci-pan-io&quot;&gt;9) 多目录 log.dirs 优化磁盘 IO&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;原理：多物理盘分散日志写入与读取，降低单盘瓶颈。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;log.dirs&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&lt;/span&gt;&lt;span&gt;/data/kafka-logs1,/data/kafka-logs2,/data/kafka-logs3&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;经验：保持盘间均衡与独立挂载；注意文件系统选型与磁盘调度器（SSD 建议 &lt;code&gt;none&lt;/code&gt;/&lt;code&gt;mq-deadline&lt;/code&gt;）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;10-fu-zhi-yin-zi-replication-factor-yu-zui-xiao-isr&quot;&gt;10) 复制因子 Replication Factor 与最小 ISR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;原理：复制因子提升容灾能力；&lt;code&gt;min.insync.replicas&lt;/code&gt; 决定可写安全阈值。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 创建主题时指定复制因子&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;kafka-topics.sh&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; --bootstrap-server&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;broker:909&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;2&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;  --create --topic payments --partitions&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 32&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; --replication-factor&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 3&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 强一致要求&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;min.insync.replicas&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;经验：一般生产建议 RF=3；跨机架部署配合机架感知，保障副本分布合理。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;jian-kong-yu-yan-zheng-qing-dan&quot;&gt;监控与验证清单&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;关键指标：&lt;code&gt;request-rate/queue&lt;/code&gt;、&lt;code&gt;records-per-request&lt;/code&gt;、&lt;code&gt;bytes-in/out&lt;/code&gt;、&lt;code&gt;replica-lag&lt;/code&gt;、&lt;code&gt;fetch-latency&lt;/code&gt;、磁盘/网络利用率。&lt;/li&gt;
&lt;li&gt;端到端：生产-代理-消费延迟分解，定位瓶颈链路。&lt;/li&gt;
&lt;li&gt;回归测试：基准压测覆盖消息大小分布、峰值/平均 QPS、网络/磁盘抖动。&lt;/li&gt;
&lt;li&gt;变更策略：逐项调参、灰度发布、可回滚，记录版本与参数快照。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;ge-ren-shi-jian-jing-yan-qu-she-yuan-ze&quot;&gt;个人实践经验（取舍原则）&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;先“结构性并行”（分区数）再“局部高效”（批次与压缩）；避免只堆参数不改架构。&lt;/li&gt;
&lt;li&gt;写入安全三件套：&lt;code&gt;acks=all + min.insync.replicas&amp;gt;=2 + RF&amp;gt;=3&lt;/code&gt;；有压测支撑再降级到 &lt;code&gt;acks=1&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;抓取参数面向业务目标：低延迟用小批次、吞吐优先用大批次+等待。&lt;/li&gt;
&lt;li&gt;网络与磁盘是基础设施瓶颈，Kafka 参数只是“放大器”，必须与 OS/NIC/盘配置协同优化。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;can-kao-zi-liao&quot;&gt;参考资料&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Kafka 调优十招：https://mp.weixin.qq.com/s/RyPrlIps1tWUWgQcIyiEvw&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>分布式锁实践与对比：Redis、ZooKeeper、etcd、数据库</title>
        <published>2025-10-19T12:35:00+08:00</published>
        <updated>2025-10-19T12:35:00+08:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/distributed-locks/"/>
        <id>https://scp.net.cn/blog/distributed-locks/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/distributed-locks/">&lt;h2 id=&quot;bei-jing-yu-mu-biao&quot;&gt;背景与目标&lt;/h2&gt;
&lt;p&gt;分布式锁用于在多节点间对共享资源的互斥访问进行协调。正确的分布式锁不仅要“拿到锁”，更要保证在网络分区、节点崩溃、时钟漂移等故障下行为可预期。《数据密集型应用》提出关键原则：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用线性一致（linearizable）的存储实现锁，或在架构中引入防护策略（如 fencing token）。&lt;/li&gt;
&lt;li&gt;锁只是建议（advisory），业务层仍需幂等与回滚保障。&lt;/li&gt;
&lt;li&gt;赋予锁“租约”（lease/TTL）并持续续约；结合会话（session）与心跳释放过期锁。&lt;/li&gt;
&lt;li&gt;引入 &lt;strong&gt;fencing token&lt;/strong&gt;（单调递增版本号）防止旧持有者在失效后仍然操作资源。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;ping-gu-wei-du&quot;&gt;评估维度&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;正确性与一致性：是否线性一致、是否能防止“双主/脑裂”。&lt;/li&gt;
&lt;li&gt;可用性与容灾：跨机房、网络抖动、故障恢复能力。&lt;/li&gt;
&lt;li&gt;公平性：是否支持排队、公平获取（FIFO）。&lt;/li&gt;
&lt;li&gt;性能与成本：吞吐、延迟、存储/运维代价。&lt;/li&gt;
&lt;li&gt;易用性：API成熟度、客户端生态、部署复杂度。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;redis-fen-bu-shi-suo&quot;&gt;Redis 分布式锁&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;基本模式：&lt;code&gt;SET key value NX PX ttl&lt;/code&gt; 获取，释放用 Lua 保证原子性：&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;lua&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;-- 仅当持有者匹配时删除&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;if&lt;/span&gt;&lt;span&gt; redis.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;call&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;, KEYS[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span&gt;]) &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;==&lt;/span&gt;&lt;span&gt; ARGV[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  return&lt;/span&gt;&lt;span&gt; redis.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;call&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;del&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;, KEYS[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;续约：定期延长 TTL，避免长 GC/Stop-The-World导致过期；需守护线程。&lt;/li&gt;
&lt;li&gt;Redlock：通过多主实例多数派获取锁，但在强严格一致性语义上存在争议；不建议用于需要线性一致的关键场景。&lt;/li&gt;
&lt;li&gt;适用场景：同机房内的“去重/防重复任务启动”、非关键资源短持锁；配合幂等和回滚机制。&lt;/li&gt;
&lt;li&gt;风险与缓解：
&lt;ul&gt;
&lt;li&gt;网络分区与主从切换可能导致锁可见性不一致；避免跨机房关键路径。&lt;/li&gt;
&lt;li&gt;TTL不是严格终止条件，过期后旧持有者仍可能继续操作；加 &lt;strong&gt;fencing token&lt;/strong&gt; 在资源侧校验。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;zookeeper-fen-bu-shi-suo&quot;&gt;ZooKeeper 分布式锁&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;核心机制：临时节点（ephemeral）+ 顺序节点（sequential）。创建 &lt;code&gt;/${lock}/lock-&lt;/code&gt; 顺序临时节点；序号最小者获锁，其余监听前驱节点删除后再竞争。&lt;/li&gt;
&lt;li&gt;特性：强一致（基于 Zab），具备公平性（排队），会话失效自动释放。&lt;/li&gt;
&lt;li&gt;客户端：推荐使用 Curator Recipes（&lt;code&gt;InterProcessMutex&lt;/code&gt; 等），处理好 Watch 一次性触发与重入。&lt;/li&gt;
&lt;li&gt;适用场景：需要强一致与公平的分布式协调（调度器、主选举、全局限流）。&lt;/li&gt;
&lt;li&gt;风险与缓解：
&lt;ul&gt;
&lt;li&gt;群聚效应（herd effect）：尽量只监听前驱而非根目录，避免大量节点同时唤醒。&lt;/li&gt;
&lt;li&gt;会话过期与网络抖动：务必实现重连与锁重获逻辑。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;etcd-fen-bu-shi-suo&quot;&gt;etcd 分布式锁&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;推荐模式：&lt;code&gt;lease&lt;/code&gt; + &lt;code&gt;Txn(CAS)&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 伪代码：创建带租约的锁键&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;lease&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; :=&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Grant&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ttl&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;keepalive&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;lease&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;resp&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; :=&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Txn&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;If&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;key_not_exists&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Then&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; owner&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; WithLease&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;lease&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))).&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Commit&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;if&lt;/span&gt;&lt;span&gt; resp&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;Succeeded&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; /* got lock; use resp.Header.Revision 作为 fencing token */&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;特性：线性一致（Raft），原生支持 &lt;code&gt;lock&lt;/code&gt; API 与租约续约；可用 &lt;code&gt;revision&lt;/code&gt;/&lt;code&gt;mod_revision&lt;/code&gt; 作为 &lt;strong&gt;fencing token&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;适用场景：对一致性要求高的核心路径（支付、订单、分布式调度）。&lt;/li&gt;
&lt;li&gt;风险与缓解：
&lt;ul&gt;
&lt;li&gt;网络分区与领导者选举：设计重试与指数退避，降级为读一致或只读模式。&lt;/li&gt;
&lt;li&gt;续约失败处理：监控 keepalive 延迟与失败率，及时释放与重获。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;shu-ju-ku-fen-bu-shi-suo&quot;&gt;数据库分布式锁&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;模式一：行级锁/状态行 + 唯一约束 + CAS：&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;-- 获取锁&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;UPDATE&lt;/span&gt;&lt;span&gt; locks &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;SET owner =&lt;/span&gt;&lt;span&gt; :who, &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;version = version +&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;WHERE name =&lt;/span&gt;&lt;span&gt; :&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;resource AND&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;owner IS NULL OR&lt;/span&gt;&lt;span&gt; expired_at &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt; NOW&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;-- 判断影响行数以确定是否拿到锁；version 作为 fencing token&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;模式二：PostgreSQL Advisory Lock：&lt;code&gt;SELECT pg_try_advisory_lock(hashtext(:resource));&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;模式三：MySQL &lt;code&gt;GET_LOCK(&#39;res&#39;, timeout)&lt;/code&gt; 与 &lt;code&gt;RELEASE_LOCK(&#39;res&#39;)&lt;/code&gt;（注意复制一致性与可靠性）。&lt;/li&gt;
&lt;li&gt;特性：易用、无需新组件；但公平性与 TTL 支持有限，跨机房一致性取决于复制架构。&lt;/li&gt;
&lt;li&gt;适用场景：单库/同机房、任务编排/批处理；或过渡方案。&lt;/li&gt;
&lt;li&gt;风险与缓解：
&lt;ul&gt;
&lt;li&gt;会话崩溃释放语义不一致（不同数据库实现差异）；建议显式心跳与过期字段。&lt;/li&gt;
&lt;li&gt;复制延迟（主从）可能导致锁可见性问题；关键路径谨慎使用。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;guan-jian-shi-jian-fencing-token&quot;&gt;关键实践：Fencing Token&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;原理：每次成功获取锁生成单调递增的令牌（版本号）。资源侧仅接受令牌更大的写入，防止“旧持有者”在锁过期/网络分区后继续写。&lt;/li&gt;
&lt;li&gt;示例：将 &lt;code&gt;version&lt;/code&gt;/&lt;code&gt;revision&lt;/code&gt;随写入一起校验；存储系统需具备原子比较能力（CAS/upsert）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;chang-jing-zui-jia-fang-an&quot;&gt;场景最佳方案&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;强一致、关键业务（支付/订单/配置变更）：优先 etcd/ZooKeeper + 租约续约 + fencing token。&lt;/li&gt;
&lt;li&gt;公平排队（调度/限流/分布式队列）：ZooKeeper 顺序节点或 etcd 的队列/锁实现。&lt;/li&gt;
&lt;li&gt;低一致性需求、短持锁（去重、定时任务防并发）：Redis &lt;code&gt;SET NX PX&lt;/code&gt; + Lua 释放 + 续约守护；在单机房内使用。&lt;/li&gt;
&lt;li&gt;单库内任务编排/过渡期：数据库行级锁/Advisory Lock，但避免跨机房关键路径。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;jian-kong-yu-wen-ding-xing&quot;&gt;监控与稳定性&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;监控：锁等待时长、失败率、租约续约延迟、会话过期次数、fencing token 单调性、网络分区事件。&lt;/li&gt;
&lt;li&gt;降级：锁获取超时触发熔断或改为幂等重试；批任务降速；业务侧容错与回滚。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;chang-jian-keng&quot;&gt;常见坑&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;仅依赖 TTL 作为安全阀门；旧持有者仍可能继续写 =&amp;gt; 用 fencing token。&lt;/li&gt;
&lt;li&gt;忽视幂等与回滚；锁不是万能防线。&lt;/li&gt;
&lt;li&gt;未处理客户端重连与会话过期；需自动重试与锁重获。&lt;/li&gt;
&lt;li&gt;ZK 监听根目录导致群聚效应；只监听前驱节点。&lt;/li&gt;
&lt;li&gt;Redis 跨机房使用 Redlock 期望强一致；不现实。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;shi-li-su-lan&quot;&gt;示例速览&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Redis 获取与释放（Lua）：见上文；确保 &lt;code&gt;value&lt;/code&gt; 是唯一持有者标识并在释放时核验。&lt;/li&gt;
&lt;li&gt;etcd 事务：&lt;code&gt;If(key missing) Then Put(key, lease)&lt;/code&gt;；用 &lt;code&gt;revision&lt;/code&gt; 作为 fencing。&lt;/li&gt;
&lt;li&gt;PostgreSQL Advisory Lock：&lt;code&gt;pg_try_advisory_lock&lt;/code&gt; + 会话结束自动释放；非线性一致全局锁。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;can-kao-zi-liao&quot;&gt;参考资料&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;《数据密集型应用》：一致性、锁、Fencing Token 与分布式系统实践。&lt;/li&gt;
&lt;li&gt;官方文档：
&lt;ul&gt;
&lt;li&gt;Redis SET NX/PX 与 Lua 原子释放&lt;/li&gt;
&lt;li&gt;ZooKeeper Recipes（Curator）&lt;/li&gt;
&lt;li&gt;etcd &lt;code&gt;lease&lt;/code&gt;/&lt;code&gt;lock&lt;/code&gt;/&lt;code&gt;txn&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;PostgreSQL Advisory Lock / MySQL GET_LOCK&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Elasticsearch 索引性能优化实践</title>
        <published>2025-10-19T12:20:00+08:00</published>
        <updated>2025-10-19T12:20:00+08:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/es-index-speed/"/>
        <id>https://scp.net.cn/blog/es-index-speed/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/es-index-speed/">&lt;h2 id=&quot;bei-jing-yu-mu-biao&quot;&gt;背景与目标&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;背景：在日志/指标/业务数据持续摄入场景下，索引性能直接影响数据可用性与费用成本（CPU、IO 与磁盘）。&lt;/li&gt;
&lt;li&gt;目标：结合官方建议形成可落地的“索引优化清单”，同时明确风险与回滚策略。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;参考：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Elasticsearch 6.8 索引速度优化：https://www.elastic.co/guide/en/elasticsearch/reference/6.8/tune-for-indexing-speed.html#_disable_refresh_and_replicas_for_initial_loads&lt;/li&gt;
&lt;li&gt;Elastic Docs 索引速度优化：https://www.elastic.co/docs/deploy-manage/production-guidance/optimize-performance/indexing-speed&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;yi-ye-qing-dan-quick-wins&quot;&gt;一页清单（Quick Wins）&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;使用 &lt;code&gt;_bulk&lt;/code&gt; 批量写入，按基准测试选择合适批次大小（建议请求体控制在数十 MB 内）。&lt;/li&gt;
&lt;li&gt;提高 &lt;code&gt;index.refresh_interval&lt;/code&gt;（如 30s），减少段切分与后续合并压力；初始大批量加载可临时设置为 &lt;code&gt;-1&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;初始批量加载时将 &lt;code&gt;index.number_of_replicas: 0&lt;/code&gt;，完成后恢复副本数。&lt;/li&gt;
&lt;li&gt;用多线程/多进程并发发送 bulk，监控 &lt;code&gt;429 TOO_MANY_REQUESTS&lt;/code&gt; 并使用指数退避重试。&lt;/li&gt;
&lt;li&gt;优先使用自动生成 &lt;code&gt;_id&lt;/code&gt;，避免查重开销；写入密集的索引给足 index buffer。&lt;/li&gt;
&lt;li&gt;给文件系统缓存留出足够内存（机器内存至少一半给 FS cache，合理控制 JVM heap）。&lt;/li&gt;
&lt;li&gt;采用本地 SSD，避免远程文件系统；需要时用 RAID0 进行条带化，并通过副本与快照保障容错。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;pi-liang-xie-ru-yu-bing-fa&quot;&gt;批量写入与并发&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;批量大小优化：在单节点/单分片做基准测试，逐步增加批次（100→200→400→…），当速度趋于平稳即为合适大小；过大批次会导致内存压力与失败重试成本升高。&lt;/li&gt;
&lt;li&gt;并发与退避：多线程/多进程并发发送 bulk；遇到 &lt;code&gt;429&lt;/code&gt;（&lt;code&gt;EsRejectedExecutionException&lt;/code&gt;）说明集群承压，应暂停并指数退避重试。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;shua-xin-yu-fu-ben-chu-shi-jia-zai-de-jia-su-ce-lue&quot;&gt;刷新与副本：初始加载的加速策略&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;提高刷新间隔：减少新段创建频率，降低合并压力并提升写入吞吐。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;http&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;PUT&lt;/span&gt;&lt;span&gt; my-index/_settings&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;index&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;refresh_interval&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;30s&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;初始加载禁用刷新与副本（风险可控）：&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;http&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;PUT&lt;/span&gt;&lt;span&gt; my-index/_settings&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;index&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;refresh_interval&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;-1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;number_of_replicas&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;加载完成后恢复设置：&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;http&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;PUT&lt;/span&gt;&lt;span&gt; my-index/_settings&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;index&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;refresh_interval&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;1s&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;number_of_replicas&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;风险提示：在 &lt;code&gt;replicas=0&lt;/code&gt; 与 &lt;code&gt;refresh=-1&lt;/code&gt; 期间，任一分片丢失会导致数据丢失；仅在受控窗口期执行并做好快照/备份。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;id-ce-lue-yu-suo-yin-huan-chong&quot;&gt;ID 策略与索引缓冲&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;自动 ID：使用自动生成 &lt;code&gt;_id&lt;/code&gt; 可跳过“同分片查重”，显著降低写入开销，尤其在索引规模增长后。&lt;/li&gt;
&lt;li&gt;索引 Buffer：为重写入分片提升 &lt;code&gt;indices.memory.index_buffer_size&lt;/code&gt;，最多让“单个重索引分片”获得约 512MB 的索引缓冲。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;http&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;PUT&lt;/span&gt;&lt;span&gt; _cluster/settings&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;persistent&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;indices.memory.index_buffer_size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;20%&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;说明：默认 10% 通常足够（10GB 堆约 1GB buffer，可支撑两个重写入分片）；超过 512MB 对单分片收益有限。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;wen-jian-xi-tong-huan-cun-yu-cun-chu-jie-zhi&quot;&gt;文件系统缓存与存储介质&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;FS Cache：将机器内存至少一半留给文件系统缓存以缓冲 IO；避免系统发生 swap（禁用交换或设置 swappiness 很小）。&lt;/li&gt;
&lt;li&gt;存储介质：优先本地 SSD；避免 NFS/SMB 远程文件系统；在云环境下使用有保障的 IOPS（如 EBS 的 provisioned IOPS）。&lt;/li&gt;
&lt;li&gt;RAID0 条带化：提升单分片吞吐，但任一盘故障会破坏索引；通过副本与跨节点冗余降低风险，并定期快照。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;jian-kong-yu-hui-tui&quot;&gt;监控与回退&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;监控项：bulk 吞吐与失败率、&lt;code&gt;429&lt;/code&gt; 比例、刷新/合并耗时、磁盘水位、线程池队列。&lt;/li&gt;
&lt;li&gt;回退策略：一旦出现持续 &lt;code&gt;429&lt;/code&gt; 或 IO 饱和，降低并发与批次大小；必要时临时提升刷新间隔或扩容集群资源。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;feng-xian-yu-quan-heng&quot;&gt;风险与权衡&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;刷新与副本调低：提升吞吐但降低数据与查询可用性；必须在窗口期执行，结束后及时恢复。&lt;/li&gt;
&lt;li&gt;批量与并发过高：可能导致内存压力与失败后重试成本显著增加；基准测试与节流至关重要。&lt;/li&gt;
&lt;li&gt;自动 &lt;code&gt;_id&lt;/code&gt;：牺牲“指定 ID 的幂等写入能力”，但换取显著吞吐提升；如需幂等可在上层做去重/幂等逻辑。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;can-kao&quot;&gt;参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Elasticsearch 6.8：Tune for indexing speed（禁用刷新与副本等）
&lt;ul&gt;
&lt;li&gt;https://www.elastic.co/guide/en/elasticsearch/reference/6.8/tune-for-indexing-speed.html#_disable_refresh_and_replicas_for_initial_loads&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Elastic Docs：Optimize indexing speed（批量、并发与退避等）
&lt;ul&gt;
&lt;li&gt;https://www.elastic.co/docs/deploy-manage/production-guidance/optimize-performance/indexing-speed&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>1brc CalculateAverage_thomaswue 代码解读</title>
        <published>2025-09-01T12:13:32+05:30</published>
        <updated>2025-09-01T12:13:32+05:30</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/1brc-calculateaverage-thomaswue/"/>
        <id>https://scp.net.cn/blog/1brc-calculateaverage-thomaswue/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/1brc-calculateaverage-thomaswue/">&lt;p&gt;这是一个高性能的Java程序，用于解决“1 Billion Row Challenge“（十亿行挑战）问题。该程序专门用于快速处理大量温度测量数据。详细解读：&lt;/p&gt;
&lt;h2 id=&quot;cheng-xu-zheng-ti-jia-gou&quot;&gt;程序整体架构&lt;/h2&gt;
&lt;h3 id=&quot;1-duo-jin-cheng-she-ji&quot;&gt;1. 多进程设计&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;private static void&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; spawnWorker&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span&gt; throws IOException &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 启动工作子进程，主进程负责启动和收集结果&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 子进程负责实际的数据处理工作&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;使用子进程处理数据，主进程快速返回结果&lt;/li&gt;
&lt;li&gt;避免内存映射清理延迟问题&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;2-bing-xing-chu-li-ce-lue&quot;&gt;2. 并行处理策略&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;int&lt;/span&gt;&lt;span&gt; numberOfWorkers&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; Runtime&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getRuntime&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;availableProcessors&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 每个CPU核心创建一个工作线程&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;he-xin-you-hua-ji-shu&quot;&gt;核心优化技术&lt;/h2&gt;
&lt;h3 id=&quot;1-nei-cun-ying-she-unsafecao-zuo&quot;&gt;1. 内存映射 + Unsafe操作&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;final long&lt;/span&gt;&lt;span&gt; fileStart&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; fileChannel&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;FileChannel&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;MapMode&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;READ_ONLY&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; fileSize&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    java&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;lang&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;foreign&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;Arena&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;global&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()).&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;address&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;直接内存映射文件，避免传统IO开销&lt;/li&gt;
&lt;li&gt;使用&lt;code&gt;sun.misc.Unsafe&lt;/code&gt;进行底层内存操作&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;2-fen-duan-bing-xing-chu-li&quot;&gt;2. 分段并行处理&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;private static final int&lt;/span&gt;&lt;span&gt; SEGMENT_SIZE&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 21&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; // 2MB段&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;将文件分成2MB的段&lt;/li&gt;
&lt;li&gt;使用工作窃取模式而非简单的平均分配&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;3-san-lu-bing-xing-sao-miao&quot;&gt;3. 三路并行扫描&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;long&lt;/span&gt;&lt;span&gt; dist&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;segmentEnd &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&lt;/span&gt;&lt;span&gt; segmentStart&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; /&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Scanner&lt;/span&gt;&lt;span&gt; scanner1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Scanner&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;segmentStart&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; midPoint1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Scanner&lt;/span&gt;&lt;span&gt; scanner2&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Scanner&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;midPoint1 &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; midPoint2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Scanner&lt;/span&gt;&lt;span&gt; scanner3&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Scanner&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;midPoint2 &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; segmentEnd&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;每个段内部再分成3部分，同时处理&lt;/li&gt;
&lt;li&gt;提高单线程内的并行度&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;4-wu-fen-zhi-shu-zi-jie-xi&quot;&gt;4. 无分支数字解析&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;private static long&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; convertIntoNumber&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;int&lt;/span&gt;&lt;span&gt; decimalSepPos&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; long&lt;/span&gt;&lt;span&gt; numberWord&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // Quan Anh Mai的无分支数字解析算法&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 避免条件分支导致的CPU流水线停顿&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;5-wei-cao-zuo-you-hua-de-fen-ge-fu-cha-zhao&quot;&gt;5. 位操作优化的分隔符查找&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;private static long&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; findDelimiter&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;long&lt;/span&gt;&lt;span&gt; word&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    long&lt;/span&gt;&lt;span&gt; input&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; word &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;^&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0x3B3B3B3B3B3B3B3BL&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; // 查找&amp;#39;;&amp;#39;字符&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;input &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0x0101010101010101L&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;amp; ~&lt;/span&gt;&lt;span&gt;input &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0x8080808080808080L&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;一次操作可以在8个字节中查找分隔符&lt;/li&gt;
&lt;li&gt;避免逐字节比较&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;6-gao-xiao-ha-xi-biao&quot;&gt;6. 高效哈希表&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;private static final int&lt;/span&gt;&lt;span&gt; HASH_TABLE_SIZE&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 17&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; // 128K&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;使用开放寻址法处理哈希冲突&lt;/li&gt;
&lt;li&gt;针对城市名称优化的哈希函数&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;7-zi-fu-chuan-bi-jiao-you-hua&quot;&gt;7. 字符串比较优化&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 直接比较内存中的long值而非字符串&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;existingResult&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;firstNameWord&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ==&lt;/span&gt;&lt;span&gt; word &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span&gt; existingResult&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;secondNameWord&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ==&lt;/span&gt;&lt;span&gt; word2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; existingResult&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;xing-neng-te-dian&quot;&gt;性能特点&lt;/h2&gt;
&lt;h3 id=&quot;chu-li-su-du&quot;&gt;处理速度&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;在Intel i9-13900K上运行时间：0.31秒&lt;/li&gt;
&lt;li&gt;相比参考实现的120.37秒，提升约388倍&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;guan-jian-you-hua-lai-yuan&quot;&gt;关键优化来源&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;内存映射&lt;/strong&gt; - 消除文件IO开销&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SIMD式处理&lt;/strong&gt; - 8字节批量操作&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;无分支算法&lt;/strong&gt; - 避免CPU分支预测失败&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;多级并行&lt;/strong&gt; - 进程+线程+段内并行&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;缓存友好&lt;/strong&gt; - 连续内存访问模式&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;shu-ju-jie-gou&quot;&gt;数据结构&lt;/h2&gt;
&lt;h3 id=&quot;resultlei&quot;&gt;Result类&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;private static final class&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Result&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    long&lt;/span&gt;&lt;span&gt; firstNameWord&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; secondNameWord&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; // 城市名前16字节&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    short&lt;/span&gt;&lt;span&gt; min&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; max&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;                     // 最小/最大温度&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    int&lt;/span&gt;&lt;span&gt; count&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;                          // 记录数量&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    long&lt;/span&gt;&lt;span&gt; sum&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;                           // 温度总和&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    long&lt;/span&gt;&lt;span&gt; nameAddress&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;                   // 名称在内存中的地址&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个程序展示了现代Java在极端性能优化方面的能力，通过底层内存操作、并行计算和算法优化，实现了接近C/C++级别的性能。&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Kafka &amp; Nic Buffer</title>
        <published>2025-08-19T12:13:32+05:30</published>
        <updated>2025-08-19T12:13:32+05:30</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/kafka-nic-buff/"/>
        <id>https://scp.net.cn/blog/kafka-nic-buff/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/kafka-nic-buff/">&lt;p&gt;NIC buffer（网卡缓冲区）是网络接口卡（Network Interface Card）中用于临时存储数据的内存区域。&lt;/p&gt;
&lt;h2 id=&quot;nic-buffer-de-zuo-yong&quot;&gt;NIC Buffer 的作用&lt;/h2&gt;
&lt;h3 id=&quot;1-shu-ju-huan-cun&quot;&gt;1. &lt;strong&gt;数据缓存&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;临时存储接收到的网络数据包&lt;/li&gt;
&lt;li&gt;缓存等待发送的数据包&lt;/li&gt;
&lt;li&gt;平衡网络传输速度和系统处理速度的差异&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;2-xing-neng-you-hua&quot;&gt;2. &lt;strong&gt;性能优化&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;减少CPU中断频率&lt;/li&gt;
&lt;li&gt;提高数据传输效率&lt;/li&gt;
&lt;li&gt;降低数据丢失的风险&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;buffer-lei-xing&quot;&gt;Buffer 类型&lt;/h2&gt;
&lt;h3 id=&quot;jie-shou-huan-chong-qu-rx-buffer&quot;&gt;接收缓冲区（RX Buffer）&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;网络 → NIC → RX Buffer → 系统内存 → 应用程序&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;fa-song-huan-chong-qu-tx-buffer&quot;&gt;发送缓冲区（TX Buffer）&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;应用程序 → 系统内存 → TX Buffer → NIC → 网络&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;gong-zuo-yuan-li&quot;&gt;工作原理&lt;/h2&gt;
&lt;h3 id=&quot;1-shu-ju-jie-shou-liu-cheng&quot;&gt;1. &lt;strong&gt;数据接收流程&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;网卡接收网络数据包&lt;/li&gt;
&lt;li&gt;数据暂存在RX Buffer中&lt;/li&gt;
&lt;li&gt;通过DMA传输到系统内存&lt;/li&gt;
&lt;li&gt;通知CPU处理数据&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;2-shu-ju-fa-song-liu-cheng&quot;&gt;2. &lt;strong&gt;数据发送流程&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;CPU将数据写入TX Buffer&lt;/li&gt;
&lt;li&gt;网卡从缓冲区读取数据&lt;/li&gt;
&lt;li&gt;按照网络协议发送数据&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;chang-jian-wen-ti-he-you-hua&quot;&gt;常见问题和优化&lt;/h2&gt;
&lt;h3 id=&quot;bufferyi-chu&quot;&gt;Buffer溢出&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;原因&lt;/strong&gt;：数据到达速度超过处理速度&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;后果&lt;/strong&gt;：数据包丢失&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;解决&lt;/strong&gt;：增大缓冲区大小、优化网络驱动&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;xing-neng-diao-you&quot;&gt;性能调优&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 查看网卡缓冲区设置&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;ethtool&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -g eth0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 调整缓冲区大小&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;ethtool&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -G eth0 rx&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1024&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; tx&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1024&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;NIC Buffer是网络通信中的重要组件，合理配置可以显著提升网络性能。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;kafka-xie-ru-shu-ju-de-huan-cun-jiao-hu-liu-cheng&quot;&gt;Kafka 写入数据的缓存交互流程&lt;/h2&gt;
&lt;h3 id=&quot;1-producer-duan-huan-cun&quot;&gt;1. &lt;strong&gt;Producer 端缓存&lt;/strong&gt;&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// Producer 配置示例&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Properties&lt;/span&gt;&lt;span&gt; props&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Properties&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;props&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;buffer.memory&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 33554432&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // 32MB 缓冲区&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;props&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;batch.size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 16384&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;              // 16KB 批次大小&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;props&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;linger.ms&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 5&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;                   // 等待时间&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;props&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;compression.type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;snappy&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     // 压缩类型&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Producer 缓存层级：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Record Accumulator&lt;/strong&gt;：消息聚合缓冲区&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Batch Buffer&lt;/strong&gt;：按 partition 分组的批次缓存&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Network Send Buffer&lt;/strong&gt;：网络发送缓冲区&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;2-wan-zheng-de-xie-ru-liu-cheng&quot;&gt;2. &lt;strong&gt;完整的写入流程&lt;/strong&gt;&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Producer App → Record Accumulator → Batch Buffer → Network Buffer &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     ↓&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Socket Send Buffer → NIC TX Buffer → 网络传输&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     ↓&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;NIC RX Buffer → Socket Receive Buffer → Kafka Broker&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     ↓&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Broker Memory → Page Cache → Disk&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;ge-ceng-huan-cun-xiang-xi-shuo-ming&quot;&gt;各层缓存详细说明&lt;/h2&gt;
&lt;h3 id=&quot;producer-duan-huan-cun&quot;&gt;Producer 端缓存&lt;/h3&gt;
&lt;h4 id=&quot;record-accumulator&quot;&gt;Record Accumulator&lt;/h4&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 内部工作原理&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;public class&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; RecordAccumulator&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    private final&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; ConcurrentMap&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;TopicPartition&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Deque&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;ProducerBatch&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span&gt; batches&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    private final&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; BufferPool&lt;/span&gt;&lt;span&gt; free&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; // 内存池管理&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 消息添加到缓冲区&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; RecordAppendResult&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; append&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;TopicPartition&lt;/span&gt;&lt;span&gt; tp&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; byte&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[]&lt;/span&gt;&lt;span&gt; key&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; byte&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[]&lt;/span&gt;&lt;span&gt; value&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // 1. 获取或创建 partition 对应的 batch&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // 2. 尝试添加到现有 batch&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // 3. 如果 batch 满了，创建新的 batch&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;guan-jian-pei-zhi-can-shu&quot;&gt;关键配置参数&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;buffer.memory&lt;/strong&gt;: 总缓冲区大小（默认32MB）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;batch.size&lt;/strong&gt;: 单个批次大小（默认16KB）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;linger.ms&lt;/strong&gt;: 批次等待时间（默认0ms）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;wang-luo-ceng-huan-cun&quot;&gt;网络层缓存&lt;/h3&gt;
&lt;h4 id=&quot;socket-huan-cun&quot;&gt;Socket 缓存&lt;/h4&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 查看和调整 socket 缓冲区&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /proc/sys/net/core/wmem_default&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  # 发送缓冲区默认大小&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /proc/sys/net/core/rmem_default&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  # 接收缓冲区默认大小&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 调整缓冲区大小&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 262144&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /proc/sys/net/core/wmem_default&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 262144&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /proc/sys/net/core/rmem_default&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;broker-duan-huan-cun&quot;&gt;Broker 端缓存&lt;/h3&gt;
&lt;h4 id=&quot;page-cache-ye-huan-cun&quot;&gt;Page Cache（页缓存）&lt;/h4&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// Kafka 利用操作系统页缓存&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;public class&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Log&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 写入消息到日志文件&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public void&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; append&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;MemoryRecords&lt;/span&gt;&lt;span&gt; records&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // 1. 数据首先写入 Page Cache&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // 2. 操作系统负责刷盘（fsync）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        segment&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;records&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;xing-neng-you-hua-ce-lue&quot;&gt;性能优化策略&lt;/h2&gt;
&lt;h3 id=&quot;1-producer-duan-you-hua&quot;&gt;1. &lt;strong&gt;Producer 端优化&lt;/strong&gt;&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 高吞吐量配置&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;props&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;buffer.memory&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 67108864&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // 64MB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;props&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;batch.size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 65536&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;              // 64KB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;props&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;linger.ms&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;                  // 10ms 等待&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;props&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;compression.type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;lz4&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // 高效压缩&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 低延迟配置&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;props&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;buffer.memory&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 33554432&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // 32MB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;props&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;batch.size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1024&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;               // 1KB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;props&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;linger.ms&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;                   // 立即发送&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;props&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;acks&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;                      // 减少确认等待&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;2-xi-tong-ji-you-hua&quot;&gt;2. &lt;strong&gt;系统级优化&lt;/strong&gt;&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 网络缓冲区优化&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;net.core.wmem_max = 134217728&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /etc/sysctl.conf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;net.core.rmem_max = 134217728&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /etc/sysctl.conf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 磁盘调度优化&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; deadline&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /sys/block/sda/queue/scheduler&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 文件系统优化（减少刷盘频率）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;mount&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -o noatime,commit=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;30&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /dev/sda1 /kafka-logs&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;3-broker-duan-you-hua&quot;&gt;3. &lt;strong&gt;Broker 端优化&lt;/strong&gt;&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# server.properties 配置&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# Socket 发送缓冲区&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;socket.send.buffer.bytes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&lt;/span&gt;&lt;span&gt;102400&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# Socket 接收缓冲区&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;socket.receive.buffer.bytes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&lt;/span&gt;&lt;span&gt;102400&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 刷盘消息数量&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;log.flush.interval.messages&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&lt;/span&gt;&lt;span&gt;10000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 刷盘时间间隔&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;log.flush.interval.ms&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;=&lt;/span&gt;&lt;span&gt;3000&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;jian-kong-he-diao-you&quot;&gt;监控和调优&lt;/h2&gt;
&lt;h3 id=&quot;guan-jian-zhi-biao-jian-kong&quot;&gt;关键指标监控&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# Producer 指标&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;kafka-console-consumer&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; --bootstrap-server localhost:9092&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;  --topic __consumer_offsets --formatter kafka.tools.ConsumerOffsetsChecker&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 查看网络统计&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;netstat&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -i&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;ss&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -tuln&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 查看页缓存使用情况&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;free&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -h&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /proc/meminfo&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; grep&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -i cache&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;chang-jian-xing-neng-wen-ti&quot;&gt;常见性能问题&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;缓冲区溢出&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;现象：producer 阻塞或抛出异常&lt;/li&gt;
&lt;li&gt;解决：增大 &lt;code&gt;buffer.memory&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;批次过小&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;现象：吞吐量低，网络开销大&lt;/li&gt;
&lt;li&gt;解决：增大 &lt;code&gt;batch.size&lt;/code&gt; 和 &lt;code&gt;linger.ms&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;页缓存不足&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;现象：频繁磁盘IO&lt;/li&gt;
&lt;li&gt;解决：增加系统内存，调整JVM堆大小&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;通过合理配置这些缓存层级，可以显著提升 Kafka 的写入性能和整体吞吐量。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;kafka-du-qu-shu-ju-de-huan-cun-jiao-hu-liu-cheng&quot;&gt;Kafka 读取数据的缓存交互流程&lt;/h2&gt;
&lt;h3 id=&quot;1-wan-zheng-de-du-qu-liu-cheng&quot;&gt;1. &lt;strong&gt;完整的读取流程&lt;/strong&gt;&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Consumer App ← Fetch Buffer ← Socket Receive Buffer ← NIC RX Buffer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     ↑&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Network ← NIC TX Buffer ← Socket Send Buffer ← Kafka Broker&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     ↑&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Page Cache ← Disk (如果 Page Cache miss)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;2-consumer-duan-huan-cun-ceng-ji&quot;&gt;2. &lt;strong&gt;Consumer 端缓存层级&lt;/strong&gt;&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// Consumer 配置示例&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Properties&lt;/span&gt;&lt;span&gt; props&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Properties&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;props&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;fetch.min.bytes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1024&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;           // 最小拉取字节数&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;props&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;fetch.max.wait.ms&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 500&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;          // 最大等待时间&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;props&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;max.partition.fetch.bytes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1048576&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; // 单分区最大拉取&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;props&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;receive.buffer.bytes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 65536&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     // Socket 接收缓冲区&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;xiang-xi-de-huan-cun-jiao-hu-guo-cheng&quot;&gt;详细的缓存交互过程&lt;/h2&gt;
&lt;h3 id=&quot;1-consumer-fa-qi-du-qu-qing-qiu&quot;&gt;1. &lt;strong&gt;Consumer 发起读取请求&lt;/strong&gt;&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;public class&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; KafkaConsumer&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; V&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    private final&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Fetcher&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; V&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; fetcher&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; ConsumerRecords&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; V&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; poll&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Duration&lt;/span&gt;&lt;span&gt; timeout&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // 1. 检查本地缓存是否有数据&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;fetcher&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;hasCompletedFetches&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            return&lt;/span&gt;&lt;span&gt; fetcher&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;fetchedRecords&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // 2. 发送 fetch 请求到 broker&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        fetcher&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sendFetches&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // 3. 等待响应并缓存数据&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return&lt;/span&gt;&lt;span&gt; fetcher&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;fetchedRecords&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;2-broker-duan-chu-li-du-qu-qing-qiu&quot;&gt;2. &lt;strong&gt;Broker 端处理读取请求&lt;/strong&gt;&lt;/h3&gt;
&lt;h4 id=&quot;page-cache-ming-zhong-qing-kuang-zui-you-lu-jing&quot;&gt;Page Cache 命中情况（最优路径）&lt;/h4&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;scala&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// Kafka Broker 处理 fetch 请求&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; KafkaRequestHandler&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  def&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; handleFetchRequest&lt;/span&gt;&lt;span&gt;(request:&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; FetchRequest&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 1. 从 Page Cache 读取数据（零拷贝）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    val&lt;/span&gt;&lt;span&gt; records&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; log.read(startOffset, maxBytes)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 2. 直接通过 sendfile() 发送到 socket&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    channel.transferTo(socketChannel, records)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;page-cache-miss-qing-kuang&quot;&gt;Page Cache Miss 情况&lt;/h4&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1. Broker 收到 fetch 请求&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2. 检查 Page Cache 中是否有数据&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3. 如果 miss，从磁盘读取到 Page Cache&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4. 通过零拷贝技术发送给 Consumer&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;3-ling-kao-bei-you-hua-zero-copy&quot;&gt;3. &lt;strong&gt;零拷贝优化（Zero-Copy）&lt;/strong&gt;&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 传统方式（4次拷贝）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// Disk → Kernel Buffer → User Buffer → Socket Buffer → NIC&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// Kafka 零拷贝方式（2次拷贝）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// Disk → Page Cache → NIC Buffer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;FileChannel&lt;/span&gt;&lt;span&gt; fileChannel&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; RandomAccessFile&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;file&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;r&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;).&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getChannel&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fileChannel&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;transferTo&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;position&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; count&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; socketChannel&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;ge-ceng-huan-cun-xiang-xi-fen-xi&quot;&gt;各层缓存详细分析&lt;/h2&gt;
&lt;h3 id=&quot;1-broker-duan-page-cache&quot;&gt;1. &lt;strong&gt;Broker 端 Page Cache&lt;/strong&gt;&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 查看页缓存使用情况&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;free&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -h&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;              total&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;        used        free      shared  buff/cache   available&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Mem:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;           32Gi       8.0Gi       2.0Gi       1.0Gi        22Gi        22Gi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 查看文件在页缓存中的情况&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;vmtouch&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /kafka-logs/topic-0/00000000000000000000.log&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;page-cache-gong-zuo-yuan-li&quot;&gt;Page Cache 工作原理&lt;/h4&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// Linux 页缓存机制&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;public class&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; PageCache&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 1. 读取请求首先检查页缓存&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 2. 命中：直接返回缓存数据&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 3. 未命中：从磁盘读取并缓存&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 4. LRU 算法管理缓存淘汰&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;2-consumer-duan-huan-cun&quot;&gt;2. &lt;strong&gt;Consumer 端缓存&lt;/strong&gt;&lt;/h3&gt;
&lt;h4 id=&quot;fetch-buffer&quot;&gt;Fetch Buffer&lt;/h4&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;public class&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Fetcher&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; V&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    private final&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; LinkedHashMap&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;TopicPartition&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;ConsumerRecord&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; V&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span&gt; records&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 预拉取和缓存机制&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    private void&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; fetch&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // 1. 批量拉取多个分区数据&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // 2. 缓存在本地 buffer 中&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // 3. 应用程序按需消费&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        Map&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;TopicPartition&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;ConsumerRecord&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; V&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span&gt; fetchedRecords&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;            parseCompletedFetch&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        records&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;putAll&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;fetchedRecords&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;yu-du-qu-ce-lue&quot;&gt;预读取策略&lt;/h4&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// Consumer 预读取配置&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;props&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;fetch.min.bytes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 50000&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // 累积50KB再返回&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;props&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;fetch.max.wait.ms&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 100&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // 最多等待100ms&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;props&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;max.poll.records&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1000&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // 单次poll最大记录数&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;xing-neng-you-hua-ce-lue-1&quot;&gt;性能优化策略&lt;/h2&gt;
&lt;h3 id=&quot;1-page-cache-you-hua&quot;&gt;1. &lt;strong&gt;Page Cache 优化&lt;/strong&gt;&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 预热页缓存&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;vmtouch&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -t /kafka-logs/&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;.log&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 监控页缓存命中率&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sar&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -B&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1 10&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  # 查看页面换入换出情况&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 调整系统参数&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /proc/sys/vm/swappiness&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;          # 减少swap使用&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /proc/sys/vm/dirty_ratio&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        # 控制脏页比例&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;2-consumer-duan-you-hua&quot;&gt;2. &lt;strong&gt;Consumer 端优化&lt;/strong&gt;&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 高吞吐量配置&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;props&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;fetch.min.bytes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1048576&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;       // 1MB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;props&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;fetch.max.wait.ms&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 100&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;         // 100ms&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;props&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;max.partition.fetch.bytes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10485760&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; // 10MB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;props&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;max.poll.records&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10000&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // 10000条记录&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 低延迟配置&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;props&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;fetch.min.bytes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;             // 1字节&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;props&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;fetch.max.wait.ms&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;          // 10ms&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;props&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;max.partition.fetch.bytes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1048576&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; // 1MB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;props&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;max.poll.records&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 100&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;          // 100条记录&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;3-wang-luo-ceng-you-hua&quot;&gt;3. &lt;strong&gt;网络层优化&lt;/strong&gt;&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# TCP 接收缓冲区优化&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;net.core.rmem_default = 262144&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /etc/sysctl.conf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;net.core.rmem_max = 16777216&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /etc/sysctl.conf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;net.ipv4.tcp_rmem = 4096 87380 16777216&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /etc/sysctl.conf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 应用配置&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sysctl&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -p&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;jian-kong-he-diao-you-1&quot;&gt;监控和调优&lt;/h2&gt;
&lt;h3 id=&quot;1-xing-neng-zhi-biao-jian-kong&quot;&gt;1. &lt;strong&gt;性能指标监控&lt;/strong&gt;&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# Broker 端指标&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;kafka-run-class&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; kafka.tools.JmxTool&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;  --jmx-url service:jmx:rmi:///jndi/rmi://localhost:9999/jmxrmi&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;  --object-name kafka.network:type=RequestMetrics,name=TotalTimeMs,request=FetchConsumer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 系统级监控&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iostat&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -x&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        # 磁盘IO统计&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iftop&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;              # 网络流量监控&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;htop&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;               # CPU和内存使用&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;2-consumer-lag-jian-kong&quot;&gt;2. &lt;strong&gt;Consumer Lag 监控&lt;/strong&gt;&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 监控消费延迟&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;kafka-consumer-groups&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; --bootstrap-server localhost:9092&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;  --group my-group --describe&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 输出示例&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;TOPIC&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;     PARTITION  CURRENT-OFFSET  LOG-END-OFFSET  LAG&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;my-topic&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;  0          1000           1500           500&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;3-huan-cun-ming-zhong-lu-fen-xi&quot;&gt;3. &lt;strong&gt;缓存命中率分析&lt;/strong&gt;&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// JVM 监控&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;jstat &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&lt;/span&gt;&lt;span&gt;gc &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;pid&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; 1s    # GC 统计&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;jmap &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&lt;/span&gt;&lt;span&gt;histo &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;pid&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;     # 堆内存分析&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 应用级监控&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 通过 JMX 监控 fetch 请求延迟和吞吐量&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;chang-jian-xing-neng-wen-ti-he-jie-jue-fang-an&quot;&gt;常见性能问题和解决方案&lt;/h2&gt;
&lt;h3 id=&quot;1-page-cache-miss-pin-fan&quot;&gt;1. &lt;strong&gt;Page Cache Miss 频繁&lt;/strong&gt;&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 问题：磁盘IO高，读取延迟大&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 解决：&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# - 增加系统内存&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# - 优化数据保留策略&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# - 使用SSD存储&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;2-consumer-lag-guo-gao&quot;&gt;2. &lt;strong&gt;Consumer Lag 过高&lt;/strong&gt;&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 问题：消费跟不上生产速度&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 解决：&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;props&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;fetch.min.bytes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1048576&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;      // 增大批次大小&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;props&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;max.poll.records&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 5000&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // 增加单次poll记录数&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 增加Consumer实例数量&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;3-wang-luo-dai-kuan-ping-jing&quot;&gt;3. &lt;strong&gt;网络带宽瓶颈&lt;/strong&gt;&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# 问题：网络成为瓶颈&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# 解决：&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&lt;/span&gt;&lt;span&gt; 启用压缩&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;props&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;compression.type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;lz4&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&lt;/span&gt;&lt;span&gt; 调整网络缓冲区大小&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&lt;/span&gt;&lt;span&gt; 使用更高带宽网络&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通过合理配置和优化这些缓存层级，可以显著提升 Kafka 的读取性能，降低延迟，提高整体系统吞吐量。&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>LoopX：给 AI Agent 装上「目标记忆」的控制平面</title>
        <published>2025-08-06T00:00:00+00:00</published>
        <updated>2025-08-06T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/blog-loopx-analysis/"/>
        <id>https://scp.net.cn/blog/blog-loopx-analysis/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/blog-loopx-analysis/">&lt;blockquote&gt;
&lt;p&gt;当一个需求要横跨三天、三个会话、三个 Agent 才能完成时，Chat 记忆不够用了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a rel=&quot;external&quot; href=&quot;https://github.com/huangruiteng/loopx&quot;&gt;huangruiteng/loopx&lt;/a&gt; | &lt;strong&gt;版本&lt;/strong&gt;: v0.4.1 | &lt;strong&gt;技术栈&lt;/strong&gt;: Python 3.11+&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;wen-ti-de-ben-zhi&quot;&gt;问题的本质&lt;/h2&gt;
&lt;p&gt;Codex、Claude Code、Cursor——这些 Agent 运行时（Agent Runtime）都很强，但它们有一个共同的局限：&lt;strong&gt;会话之间是割裂的&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;当你对 Agent 说“继续“，它需要重新理解上下文。当你让一个 Agent 修复 issue，另一个 Agent 负责 code review，再来一个 Agent 负责合并发布——&lt;strong&gt;每个 Agent 都需要知道当前状态、谁做了什么、谁该接下一棒&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;传统解法是“在 Chat 里写提示词“：把背景信息塞进 System Prompt，让模型记住。但这不是持久化，是猜测。模型可能遗忘，可能误解，而且没有人能说清楚“现在到底卡在哪里“。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;LoopX 的核心思路&lt;/strong&gt;：不替代 Agent Runtime，而是给 Agent 装上一层&lt;strong&gt;目标级状态管理层&lt;/strong&gt;——每个 Goal 有唯一身份、有结构化的 Todo、有 Gate（人工审批点）、有 Evidence（证据链）、有 Quota（算力配额），Agent 之间通过这层状态交接工作，而不是靠口耳相传。&lt;/p&gt;
&lt;h2 id=&quot;he-xin-gai-nian&quot;&gt;核心概念&lt;/h2&gt;
&lt;p&gt;LoopX 的核心理念用一句话概括就是：&lt;strong&gt;保持目标、门控、待办、证据、限额和交接稳定，让 Agent 能在多个会话中完成 bounded turn。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bounded turn&lt;/strong&gt; 是关键概念——每个 Agent 动作是有限边界的一次执行，不是无限制的自主权。每一个 turn 都要经过：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;当前目标状态检查 → 配额判断（是否该执行）→ 执行 → 写回证据 → 更新下一步&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;jia-gou-she-ji&quot;&gt;架构设计&lt;/h2&gt;
&lt;p&gt;LoopX 采用四层职责分离：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Agent → Capability → Provider → 外部系统&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;外部读回 → Provider → Capability → LoopX Kernel → 下一步 Todo / Gate / Monitor&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;角色&lt;/th&gt;&lt;th&gt;负责什么&lt;/th&gt;&lt;th&gt;不应该做什么&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Agent&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;规划、分析、工具调用、一次 bounded 执行&lt;/td&gt;&lt;td&gt;拥有持久化目标生命周期或无边界效力授权&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Capability&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;调用者结果契约、域策略、输出规范化、验证、类型化转换&lt;/td&gt;&lt;td&gt;直接写 todo、gate、quota&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Provider&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;外部系统调用，返回观察和读回&lt;/td&gt;&lt;td&gt;包含域转换策略或 LoopX 状态&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Kernel&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Goal、Todo、Claim、Gate、Monitor、Quota、写回、恢复、调度&lt;/td&gt;&lt;td&gt;包含域推理或 Provider 实现细节&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;状态管理分为六个持久化层：Registry（目标列表）、Goal State（活跃状态）、Run Log（报告）、Run History（紧凑索引）、Status/Attention Queue（首屏摘要）、Compute Quota（算力配额）。&lt;/p&gt;
&lt;h2 id=&quot;mu-biao-sheng-ming-zhou-qi&quot;&gt;目标生命周期&lt;/h2&gt;
&lt;p&gt;创建 &lt;code&gt;goal&lt;/code&gt; 并赋予稳定身份，跨越多个会话持续跟踪。每个目标包含：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Objective&lt;/strong&gt;：目标是什么&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scope&lt;/strong&gt;：边界在哪里&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Authority&lt;/strong&gt;：谁可以决策&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gates&lt;/strong&gt;：哪些点需要人工审批&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Evidence&lt;/strong&gt;：决策和执行证据链&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Run History&lt;/strong&gt;：紧凑运行索引&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;支持多项目并行，每个项目有独立的 registry 和状态文件。&lt;/p&gt;
&lt;h2 id=&quot;jie-gou-hua-men-kong&quot;&gt;结构化门控&lt;/h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 创建目标&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;loopx&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; start-goal --guided --project . --goal-text&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;完成 XX 系统重构&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 查看当前状态&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;loopx&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; status&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 诊断问题&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;loopx&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; diagnose --goal-id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;i&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;User Gates&lt;/strong&gt;：需要人工判断的门控，用具体问题替代模糊的“等待审核“&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Agent Todos&lt;/strong&gt;：结构化待办项，带 &lt;code&gt;claimed_by&lt;/code&gt;、&lt;code&gt;todo_id&lt;/code&gt;、状态机&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Claims &amp;amp; Leases&lt;/strong&gt;：软性所有权 + 可选硬性租约，防止并发冲突&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;pei-e-ding-e&quot;&gt;配额定额&lt;/h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 检查是否应该执行&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;loopx&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; quota should-run --goal-id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;i&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 成功后追加 spend&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;loopx&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; quota spend-slot --goal-id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;i&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; --run-id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;i&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;关键规则：&lt;strong&gt;静默跳过、preflight 失败、dry-run preview 不消耗配额&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id=&quot;nei-zhi-neng-li-yu&quot;&gt;内置能力域&lt;/h2&gt;
&lt;p&gt;LoopX 提供了一套可复用的能力，覆盖常见 AI 工作流场景：&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;能力&lt;/th&gt;&lt;th&gt;功能&lt;/th&gt;&lt;th&gt;状态&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;issue-fix&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;GitHub Issue → 本地分支 → PR review readiness&lt;/td&gt;&lt;td&gt;active&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;content-ops&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;内容运营：公开信源 + 私有 owner gate 聚合&lt;/td&gt;&lt;td&gt;active&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;value-connectors&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;外部渠道摄入（收入、成本、需求信号）&lt;/td&gt;&lt;td&gt;active&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;change-quality&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;精确范围的变更质量审查 + bounded repair&lt;/td&gt;&lt;td&gt;active&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;pr-review-queue&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;自动观察 GitHub PR 队列，推进一个精确 head&lt;/td&gt;&lt;td&gt;active&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;explore&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;探索图：hypothesis → finding → evidence 拓扑&lt;/td&gt;&lt;td&gt;active&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;auto-research&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;去中心化研究预设，协调 proposer/executor/evaluator&lt;/td&gt;&lt;td&gt;experimental&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;integration-branch&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;本地集成分支对齐，不改源分支&lt;/td&gt;&lt;td&gt;active&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;loopx&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; configure-goal --goal-id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;i&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;   # 查看能力列表&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;loopx&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; issue-fix workflow-plan --url&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;github-issue-ur&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; --format json&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;多数能力默认关闭（&lt;code&gt;default_enabled: False&lt;/code&gt;），需要显式启用。&lt;/p&gt;
&lt;h2 id=&quot;duo-agent-xie-zuo&quot;&gt;多 Agent 协作&lt;/h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;loopx&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; todo claim --goal-id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;i&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; --todo-id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;ti&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; --agent-id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;ai&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  # 认领待办&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;loopx&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; todo update --goal-id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;i&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; --todo-id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;ti&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; --result&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;resul&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  # 完成后更新&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;loopx&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; history --goal-id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;i&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  # 查看历史&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;同一 todo 上不并发写入，交接时写回证据，不靠口耳相传。&lt;/p&gt;
&lt;h3 id=&quot;agent-runtime-qiao-jie&quot;&gt;Agent Runtime 桥接&lt;/h3&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Host&lt;/th&gt;&lt;th&gt;启动方式&lt;/th&gt;&lt;th&gt;Loop 驱动&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Codex App&lt;/td&gt;&lt;td&gt;&lt;code&gt;loopx agent-onboard --agent-type codex-app&lt;/code&gt;&lt;/td&gt;&lt;td&gt;App 心跳自动化&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Codex CLI&lt;/td&gt;&lt;td&gt;&lt;code&gt;codex&lt;/code&gt; 在项目中，使用 &lt;code&gt;/goal&lt;/code&gt;&lt;/td&gt;&lt;td&gt;可见 &lt;code&gt;/goal &amp;lt;task_body&amp;gt;&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Claude Code&lt;/td&gt;&lt;td&gt;安装 adapter，使用 &lt;code&gt;/loopx &amp;lt;task&amp;gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;原生 &lt;code&gt;/loop&lt;/code&gt;，由 LoopX 门控&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Cursor / Shell&lt;/td&gt;&lt;td&gt;&lt;code&gt;loopx doctor&lt;/code&gt; 手动连接&lt;/td&gt;&lt;td&gt;自定义调度器&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;kai-fa-zhe-gong-ju&quot;&gt;开发者工具&lt;/h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;loopx&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; doctor&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;           # 环境诊断&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;loopx&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; serve-status&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     # 全局状态面板&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;loopx&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; check --scan-path .&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;   # 安全扫描&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;loopx&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; canary premerge --from-git-diff --goal-id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;i&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  # 发布前检查&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;gua-yong-chang-jing&quot;&gt;适用场景&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;场景&lt;/th&gt;&lt;th&gt;适合度&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;多日工程/研究/benchmark 目标&lt;/td&gt;&lt;td&gt;✅ 非常适合&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;跨多轮会话的 PR/issue 处理&lt;/td&gt;&lt;td&gt;✅ 非常适合&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;需要 human-in-the-loop 的安全门控&lt;/td&gt;&lt;td&gt;✅ 非常适合&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Peer agent 团队协作（所有权 + 交接可见性）&lt;/td&gt;&lt;td&gt;✅ 非常适合&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;单次会话完成的任务&lt;/td&gt;&lt;td&gt;❌ 过度复杂&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;实时聊天/对话场景&lt;/td&gt;&lt;td&gt;❌ 不适合&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;kuai-su-kai-shi&quot;&gt;快速开始&lt;/h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 安装&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -fsSL https://raw.githubusercontent.com/huangruiteng/loopx/main/scripts/install-from-github.sh&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; bash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;export&lt;/span&gt;&lt;span&gt; PATH&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;/.local/bin:&lt;/span&gt;&lt;span&gt;$PATH&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 连接项目&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /path/to/your-project&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;loopx&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; connect&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 创建第一个目标&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;loopx&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; start-goal --guided --project . --goal-text&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;你的长期目标描述&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;安装后确保以下目录在 &lt;code&gt;.gitignore&lt;/code&gt; 中：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;.loopx/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;.codex/goals/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;.local/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;zui-jia-shi-jian&quot;&gt;最佳实践&lt;/h2&gt;
&lt;h3 id=&quot;zhuang-tai-ge-chi&quot;&gt;状态隔离&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.loopx/&lt;/code&gt;、&lt;code&gt;.codex/goals/&lt;/code&gt;、&lt;code&gt;.local/&lt;/code&gt; 必须加入 &lt;code&gt;.gitignore&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;发布前运行 &lt;code&gt;loopx check --scan-path .&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;gate-she-ji&quot;&gt;Gate 设计&lt;/h3&gt;
&lt;p&gt;每个 user gate 必须是&lt;strong&gt;具体问题&lt;/strong&gt;，不是模糊表述：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;❌ “等待审核”&lt;/li&gt;
&lt;li&gt;✅ “请确认是否接受这个 diff 的改动范围？Y/N”&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;todo-ming-ming&quot;&gt;Todo 命名&lt;/h3&gt;
&lt;p&gt;表达&lt;strong&gt;下一步可验证的转变&lt;/strong&gt;，而非抽象概念：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;❌ “继续工作”&lt;/li&gt;
&lt;li&gt;✅ “在 staging 环境验证 auth flow”&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;pei-e-shi-yong&quot;&gt;配额使用&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;loopx&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; quota should-run --goal-id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;i&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;   # 自动 turn 必须先检查&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;loopx&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; quota spend-slot --goal-id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;i&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; --run-id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;i&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  # 成功后才追加 spend&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;静默跳过/preflight 失败/dry-run 不消耗配额。&lt;/p&gt;
&lt;h2 id=&quot;xiang-guan-zi-yuan&quot;&gt;相关资源&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a rel=&quot;external&quot; href=&quot;https://github.com/huangruiteng/loopx&quot;&gt;huangruiteng/loopx&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;文档&lt;/strong&gt;: &lt;a rel=&quot;external&quot; href=&quot;https://huangruiteng.github.io/loopx/&quot;&gt;huangruiteng.github.io/loopx&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;用户手册&lt;/strong&gt;: &lt;a rel=&quot;external&quot; href=&quot;https://my.feishu.cn/wiki/CaL5wMk9ui17ngkWzeUcMlAYnZg&quot;&gt;飞书&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;zong-jie&quot;&gt;总结&lt;/h2&gt;
&lt;p&gt;LoopX 的本质是&lt;strong&gt;目标级状态持久化和调度协调层&lt;/strong&gt;——它不运行代码，但让 Agent 的每一步工作都变得：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;可审查&lt;/strong&gt;：每个决策有 Gate，每个 Gate 有具体问题&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;可回滚&lt;/strong&gt;：Evidence 链记录每次转变，失败可追踪&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;可交接&lt;/strong&gt;：Todo + Claim 机制，多 Agent 协作不再靠猜&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;适合需要跨越多会话、多角色、多 Agent 的复杂工程和研究工作流。对于简单单次任务，它的复杂度反而是负担。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;设计哲学&lt;/strong&gt;：Keep the loop moving. Keep the judgment human.&lt;/p&gt;
&lt;/blockquote&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>关于Valkey高性能优化的博客文章总结</title>
        <published>2025-05-27T12:13:32+05:30</published>
        <updated>2025-05-27T12:13:32+05:30</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/valkey-performance-optimization/"/>
        <id>https://scp.net.cn/blog/valkey-performance-optimization/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/valkey-performance-optimization/">&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://valkey.io/blog/unlock-one-million-rps/&quot;&gt;原文地址-1&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://valkey.io/blog/unlock-one-million-rps-part2/&quot;&gt;原文地址-2&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;相关内容：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;🔍 &lt;em&gt;&lt;strong&gt;valkey unlock one million rps blog&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;🔗 &lt;a rel=&quot;external&quot; href=&quot;https://valkey.io/blog/unlock-one-million-rps/&quot;&gt;Valkey · Unlock 1 Mi&lt;/a&gt;
🔗 &lt;a rel=&quot;external&quot; href=&quot;https://valkey.io/blog/unlock-one-million-rps-part2/&quot;&gt;Valkey · Unlock 1 Mi&lt;/a&gt;
🔗 &lt;a rel=&quot;external&quot; href=&quot;https://www.gomomento.com/blog/valkey-turns-one-how-the-community-fork-left-redis-in-the-dust/&quot;&gt;Valkey Turns One: Ho&lt;/a&gt;
🔗 &lt;a rel=&quot;external&quot; href=&quot;https://valkey.io/blog/&quot;&gt;Valkey · List of blo&lt;/a&gt;
🔗 &lt;a rel=&quot;external&quot; href=&quot;https://news.ycombinator.com/item?id=41455072&quot;&gt;Unlock 1M RPS: Exper&lt;/a&gt;
🔗 &lt;a rel=&quot;external&quot; href=&quot;https://www.phoronix.com/news/Valkey-8.0-Released&quot;&gt;Valkey 8.0 Released &lt;/a&gt;
🔗 &lt;a rel=&quot;external&quot; href=&quot;https://aws.amazon.com/blogs/database/amazon-elasticache-version-8-0-for-valkey-brings-faster-scaling-and-improved-memory-efficiency/&quot;&gt;Amazon ElastiCache v&lt;/a&gt;
🔗 &lt;a rel=&quot;external&quot; href=&quot;https://valkey.io/&quot;&gt;Valkey&lt;/a&gt;
🔗 &lt;a rel=&quot;external&quot; href=&quot;https://news.ycombinator.com/item?id=41556751&quot;&gt;Valkey 8.0 Released &lt;/a&gt;
🔗 &lt;a rel=&quot;external&quot; href=&quot;https://dev.to/viradiaharsh/unlocking-the-power-of-aws-elasticache-with-valkey-72-lower-costs-serverless-flexibility-and-performance-gains-5765&quot;&gt;Unlocking the Power &lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;wen-zhang-nei-rong-zong-jie&quot;&gt;文章内容总结&lt;/h2&gt;
&lt;p&gt;根据这两篇Valkey博客文章的分析，主要内容：&lt;/p&gt;
&lt;h3 id=&quot;di-yi-pian-valkeyxing-neng-you-hua-i-oduo-xian-cheng-jia-gou&quot;&gt;第一篇：Valkey性能优化 - I/O多线程架构&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;核心优化思路：&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;多线程I/O架构&lt;/strong&gt;：将I/O操作（读取和解析命令、写入响应、轮询I/O事件）从主线程分离到专门的I/O线程，让主线程专注于命令执行&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;性能提升&lt;/strong&gt;：在8个I/O线程、300万键数据库、512字节值大小、650个客户端运行SET命令的测试中，吞吐量从360K提升到1.19M请求每秒，增长约230%，平均延迟从1.792ms降至0.542ms，下降69.8%&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;设计原则&lt;/strong&gt;：保持Valkey的简单性，命令执行仍在单线程中进行，避免复杂的同步机制和竞态条件&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;di-er-pian-nei-cun-fang-wen-you-hua-yu-qu-he-jiao-cuo-zhi-xing&quot;&gt;第二篇：内存访问优化 - 预取和交错执行&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;核心优化思路：&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;内存访问摊销&lt;/strong&gt;：通过交错执行访问随机内存位置的操作，利用处理器的推测执行能力，实现显著性能提升&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;实际应用&lt;/strong&gt;：在Valkey的lookupKey函数中应用这一技术，该函数占用了主线程40%以上的时间，通过dictPrefetch函数交错执行字典查找序列，将lookupKey的时间减少了80%以上&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;性能提升&lt;/strong&gt;：内存访问摊销技术对Valkey性能的影响接近50%，将请求速率提升到超过119万RPS&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;技术原理：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;链表示例显示交错遍历比顺序遍历快10倍（从20.8秒降至2秒）&lt;/li&gt;
&lt;li&gt;处理器在顺序访问链表时无法推测未来的内存访问指令&lt;/li&gt;
&lt;li&gt;交错执行允许处理器并行发出更多内存访问，通过摊销减少总体内存访问延迟&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;现在我来编写C语言实验程序来验证这些结论：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5E81AC;font-weight: bold;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;stdio.h&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5E81AC;font-weight: bold;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;stdlib.h&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5E81AC;font-weight: bold;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;time.h&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5E81AC;font-weight: bold;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;string.h&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5E81AC;font-weight: bold;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;sys/time.h&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5E81AC;font-weight: bold;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;unistd.h&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 链表节点结构&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;typedef struct&lt;/span&gt;&lt;span&gt; list_node &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    unsigned long&lt;/span&gt;&lt;span&gt; val&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    struct&lt;/span&gt;&lt;span&gt; list_node &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span&gt;next&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;span&gt; list&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 创建链表&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;list&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; create_list&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;size_t&lt;/span&gt;&lt;span&gt; size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;size &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return NULL;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    list &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span&gt;head &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; malloc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;sizeof&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;list&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    list &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span&gt;current &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt; head&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    head&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; rand&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; %&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1000&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;size_t&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; size&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        current&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;next&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; malloc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;sizeof&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;list&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        current &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt; current&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;next&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        current&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; rand&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; %&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1000&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    current&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;next&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = NULL;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; head&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 释放链表&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; free_list&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;list &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span&gt;head&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    while&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;head&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        list &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span&gt;temp &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt; head&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        head &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt; head&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;next&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;        free&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;temp&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 顺序遍历求和（原始方法）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;unsigned long&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; sequential_sum&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;size_t&lt;/span&gt;&lt;span&gt; arr_size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; list &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;**&lt;/span&gt;&lt;span&gt;la&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    list &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span&gt;lp&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    unsigned long&lt;/span&gt;&lt;span&gt; res &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;int&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; arr_size&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        lp &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt; la&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        while&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;lp&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            res &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;+=&lt;/span&gt;&lt;span&gt; lp&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            lp &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt; lp&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;next&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; res&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 交错遍历求和（优化方法）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;unsigned long&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; interleaved_sum&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;size_t&lt;/span&gt;&lt;span&gt; arr_size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; list &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;**&lt;/span&gt;&lt;span&gt;la&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    list &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;**&lt;/span&gt;&lt;span&gt;lthreads &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; malloc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;arr_size &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;* sizeof&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;list &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    unsigned long&lt;/span&gt;&lt;span&gt; res &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    int&lt;/span&gt;&lt;span&gt; n &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt; arr_size&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 初始化所有链表的遍历指针&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;int&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; arr_size&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        lthreads&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; la&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;lthreads&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; == NULL&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            n&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;--;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 交错遍历所有链表&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    while&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        for&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;int&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; arr_size&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;lthreads&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; == NULL&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;                continue;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            res &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;+=&lt;/span&gt;&lt;span&gt; lthreads&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            lthreads&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; lthreads&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;next&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;lthreads&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; == NULL&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                n&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;--;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    free&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;lthreads&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; res&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 带预取指令的交错遍历求和（进一步优化）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;unsigned long&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; interleaved_sum_with_prefetch&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;size_t&lt;/span&gt;&lt;span&gt; arr_size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; list &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;**&lt;/span&gt;&lt;span&gt;la&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    list &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;**&lt;/span&gt;&lt;span&gt;lthreads &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; malloc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;arr_size &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;* sizeof&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;list &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    unsigned long&lt;/span&gt;&lt;span&gt; res &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    int&lt;/span&gt;&lt;span&gt; n &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt; arr_size&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 初始化所有链表的遍历指针&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;int&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; arr_size&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        lthreads&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; la&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;lthreads&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; == NULL&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            n&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;--;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 交错遍历所有链表，使用预取指令&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    while&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        for&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;int&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; arr_size&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;lthreads&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; == NULL&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;                continue;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            res &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;+=&lt;/span&gt;&lt;span&gt; lthreads&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            lthreads&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; lthreads&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;next&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;lthreads&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;                // 预取下一个节点到缓存&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;                __builtin_prefetch&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;lthreads&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;],&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; else&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                n&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;--;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    free&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;lthreads&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; res&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 获取当前时间（微秒）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;long long&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; get_time_us&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    struct&lt;/span&gt;&lt;span&gt; timeval tv&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    gettimeofday&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;tv&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; NULL&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; tv&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;tv_sec&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1000000&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;LL +&lt;/span&gt;&lt;span&gt; tv&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;tv_usec&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 哈希表相关结构和函数（模拟Valkey的字典查找优化）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5E81AC;font-weight: bold;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;define&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; HASH_SIZE&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1000003&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;typedef struct&lt;/span&gt;&lt;span&gt; hash_entry &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    char *&lt;/span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    unsigned long&lt;/span&gt;&lt;span&gt; value&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    struct&lt;/span&gt;&lt;span&gt; hash_entry &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span&gt;next&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;span&gt; hash_entry&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;typedef struct&lt;/span&gt;&lt;span&gt; hash_table &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    hash_entry &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;**&lt;/span&gt;&lt;span&gt;buckets&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    size_t&lt;/span&gt;&lt;span&gt; size&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;span&gt; hash_table&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 简单哈希函数&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;unsigned long&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; hash_func&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;const char *&lt;/span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    unsigned long&lt;/span&gt;&lt;span&gt; hash &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 5381&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    int&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    while&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; ((&lt;/span&gt;&lt;span&gt;c &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;= *&lt;/span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        hash &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; ((&lt;/span&gt;&lt;span&gt;hash &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 5&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span&gt; hash&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; hash &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;%&lt;/span&gt;&lt;span&gt; HASH_SIZE&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 创建哈希表&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;hash_table&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; create_hash_table&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    hash_table &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span&gt;ht &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; malloc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;sizeof&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;hash_table&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ht&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;size&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; HASH_SIZE&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ht&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;buckets&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; calloc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;HASH_SIZE&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; sizeof&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;hash_entry&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; ht&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 插入键值对&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; hash_insert&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;hash_table &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span&gt;ht&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; const char *&lt;/span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; unsigned long&lt;/span&gt;&lt;span&gt; value&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    unsigned long&lt;/span&gt;&lt;span&gt; index &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; hash_func&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    hash_entry &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span&gt;entry &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; malloc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;sizeof&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;hash_entry&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    entry&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; strdup&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    entry&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;value&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; value&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    entry&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;next&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; ht&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;buckets&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;index&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ht&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;buckets&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;index&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; entry&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 顺序查找多个键&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;unsigned long&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; sequential_lookup&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;hash_table &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span&gt;ht&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; char **&lt;/span&gt;&lt;span&gt;keys&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; size_t&lt;/span&gt;&lt;span&gt; num_keys&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    unsigned long&lt;/span&gt;&lt;span&gt; total &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;size_t&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; num_keys&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        unsigned long&lt;/span&gt;&lt;span&gt; index &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; hash_func&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;keys&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;])&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        hash_entry &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span&gt;entry &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt; ht&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;buckets&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;index&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        while&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;entry&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;strcmp&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;entry&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; keys&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;])&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                total &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;+=&lt;/span&gt;&lt;span&gt; entry&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;value&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;                break;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            entry &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt; entry&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;next&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; total&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 预取优化的批量查找&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;unsigned long&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; prefetch_lookup&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;hash_table &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span&gt;ht&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; char **&lt;/span&gt;&lt;span&gt;keys&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; size_t&lt;/span&gt;&lt;span&gt; num_keys&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    unsigned long&lt;/span&gt;&lt;span&gt; total &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    hash_entry &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;**&lt;/span&gt;&lt;span&gt;entries &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; malloc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;num_keys &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;* sizeof&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;hash_entry&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    unsigned long *&lt;/span&gt;&lt;span&gt;indices &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; malloc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;num_keys &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;* sizeof&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;unsigned long&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 第一阶段：计算所有索引并预取&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;size_t&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; num_keys&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        indices&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; hash_func&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;keys&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;])&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        entries&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; ht&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;buckets&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;indices&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;entries&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;            __builtin_prefetch&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;entries&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;],&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 第二阶段：交错查找&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    int&lt;/span&gt;&lt;span&gt; remaining &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt; num_keys&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    while&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;remaining &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        for&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;size_t&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; num_keys&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;entries&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; == NULL&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; continue;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;strcmp&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;entries&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; keys&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;])&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                total &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;+=&lt;/span&gt;&lt;span&gt; entries&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;value&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                entries&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = NULL;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  // 标记为已找到&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                remaining&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;--;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; else&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                entries&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; entries&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;next&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;                if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;entries&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; == NULL&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    remaining&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;--;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; else&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;                    __builtin_prefetch&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;entries&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;],&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    free&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;entries&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    free&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;indices&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; total&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 释放哈希表&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; free_hash_table&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;hash_table &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span&gt;ht&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;size_t&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; ht&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;size&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        hash_entry &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span&gt;entry &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt; ht&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;buckets&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        while&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;entry&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            hash_entry &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span&gt;temp &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt; entry&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            entry &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt; entry&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;next&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;            free&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;temp&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;            free&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;temp&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    free&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ht&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;buckets&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    free&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ht&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; main&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    printf&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=== Valkey性能优化技术验证程序 ===&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 测试1：链表遍历优化验证&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    printf&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;1. 链表遍历优化测试&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    printf&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;创建测试数据...&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    const size_t&lt;/span&gt;&lt;span&gt; num_lists &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 16&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    const size_t&lt;/span&gt;&lt;span&gt; list_size &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1000000&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  // 为了快速测试，使用100万而非1000万&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    list &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;**&lt;/span&gt;&lt;span&gt;lists &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; malloc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;num_lists &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;* sizeof&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;list&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 创建测试链表&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    srand&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;time&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;NULL&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;size_t&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; num_lists&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        lists&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; create_list&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;list_size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    printf&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;测试数据创建完成：%zu个链表，每个包含%zu个节点&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span&gt; num_lists&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; list_size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 测试顺序遍历&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    long long&lt;/span&gt;&lt;span&gt; start_time &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; get_time_us&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    unsigned long&lt;/span&gt;&lt;span&gt; result1 &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; sequential_sum&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;num_lists&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; lists&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    long long&lt;/span&gt;&lt;span&gt; sequential_time &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; get_time_us&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; -&lt;/span&gt;&lt;span&gt; start_time&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 测试交错遍历&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    start_time &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; get_time_us&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    unsigned long&lt;/span&gt;&lt;span&gt; result2 &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; interleaved_sum&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;num_lists&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; lists&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    long long&lt;/span&gt;&lt;span&gt; interleaved_time &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; get_time_us&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; -&lt;/span&gt;&lt;span&gt; start_time&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 测试带预取的交错遍历&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    start_time &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; get_time_us&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    unsigned long&lt;/span&gt;&lt;span&gt; result3 &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; interleaved_sum_with_prefetch&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;num_lists&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; lists&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    long long&lt;/span&gt;&lt;span&gt; prefetch_time &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; get_time_us&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; -&lt;/span&gt;&lt;span&gt; start_time&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    printf&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;链表遍历测试结果：&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    printf&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;顺序遍历：      %lld 微秒，结果：%lu&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span&gt; sequential_time&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; result1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    printf&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;交错遍历：      %lld 微秒，结果：%lu (提升：%.2fx)&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;           interleaved_time&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; result2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span&gt;sequential_time &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;/&lt;/span&gt;&lt;span&gt; interleaved_time&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    printf&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;预取+交错遍历： %lld 微秒，结果：%lu (提升：%.2fx)&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;           prefetch_time&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; result3&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span&gt;sequential_time &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;/&lt;/span&gt;&lt;span&gt; prefetch_time&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 验证结果正确性&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;result1 &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;==&lt;/span&gt;&lt;span&gt; result2 &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span&gt; result2 &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;==&lt;/span&gt;&lt;span&gt; result3&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;        printf&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;✓ 所有算法结果一致，验证通过&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; else&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;        printf&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;✗ 结果不一致，可能存在错误&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 清理链表&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;size_t&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; num_lists&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;        free_list&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;lists&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;])&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    free&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;lists&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 测试2：哈希表查找优化验证&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    printf&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;2. 哈希表查找优化测试（模拟Valkey字典查找）&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    hash_table &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span&gt;ht &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; create_hash_table&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    const size_t&lt;/span&gt;&lt;span&gt; num_test_keys &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 100000&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    const size_t&lt;/span&gt;&lt;span&gt; lookup_batch_size &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1000&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 插入测试数据&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    printf&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;插入 %zu 个键值对...&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span&gt; num_test_keys&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;size_t&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; num_test_keys&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        char&lt;/span&gt;&lt;span&gt; key&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;32&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;        snprintf&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; sizeof&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;), &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;key_%zu&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;        hash_insert&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ht&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; key&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 准备查找的键&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    char **&lt;/span&gt;&lt;span&gt;lookup_keys &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; malloc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;lookup_batch_size &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;* sizeof&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;char*&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;size_t&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; lookup_batch_size&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        lookup_keys&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; malloc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;32&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;        snprintf&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;lookup_keys&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;],&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 32&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;key_%zu&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; rand&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; %&lt;/span&gt;&lt;span&gt; num_test_keys&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 测试顺序查找&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    start_time &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; get_time_us&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    unsigned long&lt;/span&gt;&lt;span&gt; hash_result1 &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; sequential_lookup&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ht&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; lookup_keys&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; lookup_batch_size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    long long&lt;/span&gt;&lt;span&gt; hash_sequential_time &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; get_time_us&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; -&lt;/span&gt;&lt;span&gt; start_time&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 测试预取优化查找&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    start_time &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; get_time_us&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    unsigned long&lt;/span&gt;&lt;span&gt; hash_result2 &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; prefetch_lookup&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ht&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; lookup_keys&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; lookup_batch_size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    long long&lt;/span&gt;&lt;span&gt; hash_prefetch_time &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; get_time_us&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; -&lt;/span&gt;&lt;span&gt; start_time&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    printf&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;哈希表查找测试结果：&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    printf&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;顺序查找：    %lld 微秒，结果：%lu&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span&gt; hash_sequential_time&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; hash_result1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    printf&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;预取优化查找：%lld 微秒，结果：%lu (提升：%.2fx)&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;           hash_prefetch_time&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; hash_result2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;double&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span&gt;hash_sequential_time &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;/&lt;/span&gt;&lt;span&gt; hash_prefetch_time&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;hash_result1 &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;==&lt;/span&gt;&lt;span&gt; hash_result2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;        printf&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;✓ 哈希表查找结果一致，验证通过&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; else&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;        printf&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;✗ 哈希表查找结果不一致&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // 清理资源&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;size_t&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; lookup_batch_size&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;        free&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;lookup_keys&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;])&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    free&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;lookup_keys&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    free_hash_table&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ht&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    printf&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=== 总结 ===&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    printf&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;1. 链表交错遍历相比顺序遍历可以获得显著性能提升&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    printf&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;2. 预取指令可以进一步提升性能&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    printf&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;3. 这些优化技术通过改善内存访问模式，减少CPU等待时间&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    printf&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;4. Valkey通过类似技术在lookupKey函数中获得了80%%以上的性能提升&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    printf&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;5. 结合I/O多线程，Valkey 8.0实现了从360K到1.19M RPS的性能飞跃&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我还需要创建一个Makefile来帮助编译和运行这个实验程序：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;make&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CC&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; =&lt;/span&gt;&lt;span&gt; gcc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CFLAGS&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; =&lt;/span&gt;&lt;span&gt; -O2 -Wall -Wextra -std=c99&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;TARGET&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; =&lt;/span&gt;&lt;span&gt; valkey_test&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;SOURCE&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; =&lt;/span&gt;&lt;span&gt; valkey_optimization_test.c&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 默认目标&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;all&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; $(&lt;/span&gt;&lt;span&gt;TARGET&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 编译目标&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;$(&lt;/span&gt;&lt;span&gt;TARGET&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;)&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;$(&lt;/span&gt;&lt;span&gt;SOURCE&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    $(&lt;/span&gt;&lt;span&gt;CC&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;) $(&lt;/span&gt;&lt;span&gt;CFLAGS&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;)&lt;/span&gt;&lt;span&gt; -o &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;$(&lt;/span&gt;&lt;span&gt;TARGET&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;) $(&lt;/span&gt;&lt;span&gt;SOURCE&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 运行测试&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; $(&lt;/span&gt;&lt;span&gt;TARGET&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ./&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;$(&lt;/span&gt;&lt;span&gt;TARGET&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 优化编译（启用更多优化）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;optimized&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    $(&lt;/span&gt;&lt;span&gt;CC&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;)&lt;/span&gt;&lt;span&gt; -O3 -march=native -mtune=native -Wall -Wextra -std=c99 -o &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;$(&lt;/span&gt;&lt;span&gt;TARGET&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;) $(&lt;/span&gt;&lt;span&gt;SOURCE&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 调试编译&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;debug&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    $(&lt;/span&gt;&lt;span&gt;CC&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;)&lt;/span&gt;&lt;span&gt; -g -O0 -Wall -Wextra -std=c99 -o &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;$(&lt;/span&gt;&lt;span&gt;TARGET&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;) $(&lt;/span&gt;&lt;span&gt;SOURCE&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 清理&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;clean&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    rm -f &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;$(&lt;/span&gt;&lt;span&gt;TARGET&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 显示帮助&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;help&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    @echo &amp;quot;可用目标：&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    @echo &amp;quot;  all       - 编译程序（默认）&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    @echo &amp;quot;  run       - 编译并运行程序&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    @echo &amp;quot;  optimized - 使用最高优化级别编译&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    @echo &amp;quot;  debug     - 编译调试版本&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    @echo &amp;quot;  clean     - 清理编译产物&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    @echo &amp;quot;  help      - 显示此帮助信息&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    @echo &amp;quot;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    @echo &amp;quot;使用示例：&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    @echo &amp;quot;  make run          &lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 编译并运行测试&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    @echo &amp;quot;  make optimized    &lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 高优化编译&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    @echo &amp;quot;  make clean        &lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 清理文件&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;.PHONY&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; all run optimized debug clean help&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;zong-jie&quot;&gt;总结&lt;/h2&gt;
&lt;p&gt;我已经完成了对两篇Valkey博客文章的分析和实验程序的编写。以下是主要内容：&lt;/p&gt;
&lt;h3 id=&quot;wen-zhang-he-xin-ji-shu-yao-dian&quot;&gt;文章核心技术要点：&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;I/O多线程优化&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;将I/O操作从主线程分离到专门的I/O线程&lt;/li&gt;
&lt;li&gt;吞吐量提升230%（360K → 1.19M RPS）&lt;/li&gt;
&lt;li&gt;平均延迟降低69.8%（1.792ms → 0.542ms）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;内存访问摊销优化&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;通过交错执行减少内存访问延迟&lt;/li&gt;
&lt;li&gt;lookupKey函数性能提升80%+&lt;/li&gt;
&lt;li&gt;整体性能再提升50%&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;shi-yan-cheng-xu-yan-zheng&quot;&gt;实验程序验证：&lt;/h3&gt;
&lt;p&gt;我编写的C语言程序包含两个主要测试：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;链表遍历优化测试&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;验证顺序遍历vs交错遍历的性能差异&lt;/li&gt;
&lt;li&gt;测试预取指令的额外优化效果&lt;/li&gt;
&lt;li&gt;模拟文章中链表示例的10倍性能提升&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;哈希表查找优化测试&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;模拟Valkey字典查找的优化场景&lt;/li&gt;
&lt;li&gt;验证预取和批量处理的性能提升&lt;/li&gt;
&lt;li&gt;对应文章中lookupKey函数的优化&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;shi-yong-fang-fa&quot;&gt;使用方法：&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 编译并运行测试&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;make&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; run&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 或者使用高优化编译&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;make&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; optimized&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;./valkey_test&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=== Valkey性能优化技术验证程序 ===&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;1.&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 链表遍历优化测试&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;创建测试数据...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;测试数据创建完成：16个链表，每个包含1000000个节点&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;链表遍历测试结果：&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;顺序遍历：&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;      91915&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 微秒，结果：7990951360&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;交错遍历：&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;      57780&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 微秒，结果：7990951360&lt;/span&gt;&lt;span&gt; (提升：1.59x)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;预取+交错遍历：&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 53289&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 微秒，结果：7990951360&lt;/span&gt;&lt;span&gt; (提升：1.72x)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;✓&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 所有算法结果一致，验证通过&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;2.&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 哈希表查找优化测试（模拟Valkey字典查找）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;插入&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 100000&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 个键值对...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;哈希表查找测试结果：&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;顺序查找：&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;    228&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 微秒，结果：97528762&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;预取优化查找：53&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 微秒，结果：97528762&lt;/span&gt;&lt;span&gt; (提升：4.30x)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;✓&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 哈希表查找结果一致，验证通过&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=== 总结 ===&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;1.&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 链表交错遍历相比顺序遍历可以获得显著性能提升&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;2.&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 预取指令可以进一步提升性能&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;3.&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 这些优化技术通过改善内存访问模式，减少CPU等待时间&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;4.&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; Valkey通过类似技术在lookupKey函数中获得了80%以上的性能提升&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;5.&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 结合I/O多线程，Valkey 8.0实现了从360K到1.19M RPS的性能飞跃&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个实验程序能够验证Valkey文章中提到的核心优化技术，展示内存访问模式优化对性能的巨大影响。通过交错执行和预取指令，可以显著提升处理大量随机内存访问的性能，这正是Valkey实现百万级RPS的关键技术基础。&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Raft 共识算法详解与 JavaScript 实现</title>
        <published>2024-12-15T12:13:32+05:30</published>
        <updated>2024-12-15T12:13:32+05:30</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/raft-iml-js/"/>
        <id>https://scp.net.cn/blog/raft-iml-js/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/raft-iml-js/">&lt;p&gt;Raft 是一种为了易于理解而设计的共识算法，由 Diego Ongaro 和 John Ousterhout 在 2014 年提出。相比于 Paxos 算法，Raft 更加直观和易于实现，同时保持了相同的功能和性能。&lt;/p&gt;
&lt;h2 id=&quot;mu-lu&quot;&gt;目录&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Raft 算法概述&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Raft 的核心机制&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;JavaScript 实现分析&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;实践演示&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;总结与思考&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;1-raft-suan-fa-gai-shu&quot;&gt;1. Raft 算法概述&lt;/h2&gt;
&lt;p&gt;Raft 是一种用于管理复制日志的共识算法。它的主要目标是提供一种更容易理解的方式来构建实用的分布式系统。Raft 将共识问题分解为三个相对独立的子问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;领导人选举&lt;/strong&gt;：当现有领导人失效时必须选出一个新的领导人&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;日志复制&lt;/strong&gt;：领导人必须从客户端接收日志条目，并将它们复制到集群中的其他服务器&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;安全性&lt;/strong&gt;：如果任何服务器已经应用了一个特定的日志条目到它的状态机中，那么其他服务器不能在同一个日志索引位置应用不同的命令&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;2-raft-de-he-xin-ji-zhi&quot;&gt;2. Raft 的核心机制&lt;/h2&gt;
&lt;h3 id=&quot;2-1-fu-wu-qi-zhuang-tai&quot;&gt;2.1 服务器状态&lt;/h3&gt;
&lt;p&gt;在 Raft 中，服务器可以处于三种状态之一：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Follower（跟随者）&lt;/strong&gt;：被动接收来自领导人或候选人的请求&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Candidate（候选人）&lt;/strong&gt;：用于选举新的领导人&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Leader（领导人）&lt;/strong&gt;：处理所有客户端请求，如果客户端联系跟随者，跟随者会将请求重定向给领导人&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;2-2-ren-qi-term&quot;&gt;2.2 任期（Term）&lt;/h3&gt;
&lt;p&gt;Raft 将时间划分为任意长度的任期（term）。每个任期都由一个选举开始，如果一个候选人赢得选举，它将在该任期的剩余时间担任领导人。任期在 Raft 中充当逻辑时钟的角色，帮助服务器检测过时的信息。&lt;/p&gt;
&lt;h3 id=&quot;2-3-ling-dao-ren-xuan-ju&quot;&gt;2.3 领导人选举&lt;/h3&gt;
&lt;p&gt;当跟随者在一段时间内没有收到来自领导人的消息时，它会转变为候选人并开始一次选举：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;增加当前任期号&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;给自己投票&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;向其他服务器发送请求投票的 RPC&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果收到大多数服务器的投票，成为领导人&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果收到来自新领导人的消息，转变为跟随者&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果选举超时，开始新一轮选举&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;2-4-ri-zhi-fu-zhi&quot;&gt;2.4 日志复制&lt;/h3&gt;
&lt;p&gt;领导人负责管理客户端请求和日志复制：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;领导人接收客户端命令，将其作为新条目添加到自己的日志中&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;并行向其他服务器发送 AppendEntries RPC 来复制条目&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;当条目被安全复制后，领导人将其应用到自己的状态机并向客户端返回结果&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果跟随者崩溃或运行缓慢，领导人会不断重试 AppendEntries RPC&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;3-javascript-shi-xian-fen-xi&quot;&gt;3. JavaScript 实现分析&lt;/h2&gt;
&lt;p&gt;让我们分析一下 &lt;code&gt;raft-node.js&lt;/code&gt; 中的关键部分，看看它们是如何实现 Raft 算法的核心机制的。&lt;/p&gt;
&lt;h3 id=&quot;3-1-jie-dian-zhuang-tai-guan-li&quot;&gt;3.1 节点状态管理&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;constructor&lt;/span&gt;&lt;span&gt;(id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; nodes&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; [])&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 服务器标识&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;nodes&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; nodes&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 所有服务器上的持久性状态&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;currentTerm&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;votedFor&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = null;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; []&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 所有服务器上的易失性状态&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;commitIndex&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;lastApplied&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 领导人上的易失性状态&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;nextIndex&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {}&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;matchIndex&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {}&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 额外的实现状态&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;state&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;follower&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;leaderId&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = null;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;votes&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 定时器&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;electionTimeout&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = null;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;heartbeatInterval&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = null;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 初始化&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;resetElectionTimeout&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这段代码定义了 Raft 节点的基本状态，包括持久性状态（currentTerm、votedFor、log）和易失性状态（commitIndex、lastApplied、nextIndex、matchIndex）。&lt;/p&gt;
&lt;h3 id=&quot;3-2-ling-dao-ren-xuan-ju&quot;&gt;3.2 领导人选举&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;startElection&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;state&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ===&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;leader&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 成为候选人&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;state&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;candidate&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;currentTerm&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;votedFor&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;votes&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; // 给自己投票&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;console&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Node &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;${this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; starting election for term &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;${this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;currentTerm&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;`&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 向所有其他节点请求投票&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;nodes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;forEach&lt;/span&gt;&lt;span&gt;(node&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;if&lt;/span&gt;&lt;span&gt; (node&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; !== this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;id)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;const&lt;/span&gt;&lt;span&gt; voteGranted&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;requestVote&lt;/span&gt;&lt;span&gt;(node)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;if&lt;/span&gt;&lt;span&gt; (voteGranted)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;votes&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 检查是否获得多数票&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;votes&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt; this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;nodes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;length&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; /&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;becomeLeader&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 重置选举超时&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;resetElectionTimeout&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这段代码实现了选举过程：节点成为候选人，增加任期号，给自己投票，然后向其他节点请求投票。如果获得多数票，则成为领导人。&lt;/p&gt;
&lt;h3 id=&quot;3-3-ri-zhi-fu-zhi&quot;&gt;3.3 日志复制&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;appendEntries&lt;/span&gt;&lt;span&gt;(node)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 在实际实现中，这将是一个 RPC&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;const&lt;/span&gt;&lt;span&gt; term&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;currentTerm&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;const&lt;/span&gt;&lt;span&gt; leaderId&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;const&lt;/span&gt;&lt;span&gt; prevLogIndex&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;nextIndex[node&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;id]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;const&lt;/span&gt;&lt;span&gt; prevLogTerm&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; prevLogIndex&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ? this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;log[prevLogIndex]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;term&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;const&lt;/span&gt;&lt;span&gt; entries&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;slice&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;nextIndex[node&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;id])&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;const&lt;/span&gt;&lt;span&gt; leaderCommit&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;commitIndex&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;return&lt;/span&gt;&lt;span&gt; node&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;handleAppendEntries&lt;/span&gt;&lt;span&gt;(term&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; leaderId&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; prevLogIndex&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; prevLogTerm&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; entries&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; leaderCommit)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;handleAppendEntries&lt;/span&gt;&lt;span&gt;(term&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; leaderId&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; prevLogIndex&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; prevLogTerm&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; entries&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; leaderCommit)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 如果任期过时，拒绝&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;if&lt;/span&gt;&lt;span&gt; (term&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt; this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;currentTerm)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;return false;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 重置选举超时，因为我们收到了领导人的消息&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;resetElectionTimeout&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 如果看到更高的任期，更新我们的任期&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;if&lt;/span&gt;&lt;span&gt; (term&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt; this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;currentTerm)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;currentTerm&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; term&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;state&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;follower&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;votedFor&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = null;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 更新领导人 ID&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;leaderId&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; leaderId&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 检查日志是否包含 prevLogIndex 处的条目，且任期为 prevLogTerm&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;if&lt;/span&gt;&lt;span&gt; (prevLogIndex&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(prevLogIndex&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt;= this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;length&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ||&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;log[prevLogIndex]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;term&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; !==&lt;/span&gt;&lt;span&gt; prevLogTerm))&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;return false;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 如果现有条目与新条目冲突，删除它和之后的所有条目&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt;&lt;span&gt; newEntries&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;...&lt;/span&gt;&lt;span&gt;entries]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;if&lt;/span&gt;&lt;span&gt; (entries&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;length&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt;&lt;span&gt; logIndex&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; prevLogIndex&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt;&lt;span&gt; entryIndex&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;while&lt;/span&gt;&lt;span&gt; (entryIndex&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span&gt; entries&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;length)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;if&lt;/span&gt;&lt;span&gt; (logIndex&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt;= this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;length&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ||&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;log[logIndex]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;term&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; !==&lt;/span&gt;&lt;span&gt; entries[entryIndex]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;term)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 删除从这一点开始的所有条目&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;slice&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; logIndex)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 并附加所有剩余条目&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;...this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ...&lt;/span&gt;&lt;span&gt;entries&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;slice&lt;/span&gt;&lt;span&gt;(entryIndex)]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;break;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;logIndex&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;entryIndex&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 如果领导人的提交索引更高，更新提交索引&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;if&lt;/span&gt;&lt;span&gt; (leaderCommit&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt; this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;commitIndex)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;commitIndex&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; Math&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;min&lt;/span&gt;&lt;span&gt;(leaderCommit&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;length&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;applyCommittedEntries&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;return true;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这段代码实现了日志复制机制：领导人向跟随者发送 AppendEntries RPC，包含要复制的日志条目。跟随者验证请求的有效性，然后更新自己的日志。&lt;/p&gt;
&lt;h2 id=&quot;4-shi-jian-yan-shi&quot;&gt;4. 实践演示&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;raft-test.js&lt;/code&gt; 文件展示了如何创建一个 Raft 集群并测试其功能：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;const&lt;/span&gt;&lt;span&gt; RaftNode&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; require&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;./raft-node&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 创建一个包含 5 个节点的集群&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;const&lt;/span&gt;&lt;span&gt; nodes&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; []&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;let&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 5&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;nodes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;push&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; RaftNode&lt;/span&gt;&lt;span&gt;(i))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 将节点相互连接&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;nodes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;forEach&lt;/span&gt;&lt;span&gt;(node&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;node&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;nodes&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; nodes&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 等待领导人被选举出来&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;setTimeout&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;const&lt;/span&gt;&lt;span&gt; leader&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; nodes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;find&lt;/span&gt;&lt;span&gt;(node&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span&gt; node&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;state&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ===&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;leader&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;if&lt;/span&gt;&lt;span&gt; (leader)&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;console&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Node &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;${&lt;/span&gt;&lt;span&gt;leader&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; is the leader&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;`&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 向领导人发送客户端请求&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;leader&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;clientRequest&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; key&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;foo&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; value&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;bar&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39; }&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 一段时间后检查日志&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;setTimeout&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;nodes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;forEach&lt;/span&gt;&lt;span&gt;(node&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;console&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Node &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;${&lt;/span&gt;&lt;span&gt;node&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; log:&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;`,&lt;/span&gt;&lt;span&gt; node&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;log)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;},&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 500&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; else&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;console&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;No leader elected yet&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;},&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1000&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这段代码创建了 5 个 Raft 节点，让它们相互连接，然后等待领导人选举完成。一旦选出领导人，它会向领导人发送一个客户端请求，然后检查所有节点的日志是否一致。&lt;/p&gt;
&lt;h2 id=&quot;5-zong-jie-yu-si-kao&quot;&gt;5. 总结与思考&lt;/h2&gt;
&lt;p&gt;通过对 Raft 算法的学习和 JavaScript 实现的分析，我们可以看到 Raft 算法的几个关键优势：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;可理解性&lt;/strong&gt;：Raft 将共识问题分解为选举、日志复制和安全性三个子问题，使其更容易理解和实现。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;领导人机制&lt;/strong&gt;：Raft 使用强领导人模式，所有日志条目都从领导人流向其他服务器，简化了日志复制的管理。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;成员变更&lt;/strong&gt;：Raft 提供了一种安全的方式来改变集群中的服务器集合。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;日志压缩&lt;/strong&gt;：Raft 支持日志压缩，防止日志无限增长。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;然而，我们的 JavaScript 实现还有一些局限性和可改进之处：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;网络通信&lt;/strong&gt;：实际实现中需要使用真正的 RPC 机制，而不是直接函数调用。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;持久化&lt;/strong&gt;：需要将持久性状态（currentTerm、votedFor、log）写入持久存储。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;错误处理&lt;/strong&gt;：需要处理网络分区、节点崩溃等故障情况。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;日志压缩&lt;/strong&gt;：实现日志压缩机制，防止日志无限增长。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;成员变更&lt;/strong&gt;：实现安全的集群成员变更机制。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Raft 算法的设计理念是“易于理解“，这使得它成为分布式系统中实现共识的流行选择。通过本文的学习，希望读者能够对 Raft 算法有更深入的理解，并能够在实际项目中应用这些知识。&lt;/p&gt;
&lt;p&gt;完整实现代码：&lt;a rel=&quot;external&quot; href=&quot;https://gitee.com/dllen/dllen-demos/tree/master/raft-js&quot;&gt;gitee&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;can-kao-zi-liao&quot;&gt;参考资料&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/maemual/raft-zh_cn&quot;&gt;GitHub - maemual/raft-zh_cn: Raft一致性算法论文的中文翻译&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Raft 官方网站：https://raft.github.io/&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Raft 可视化：http://thesecretlivesofdata.com/raft/&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://www.codedump.info/post/20180921-raft/&quot;&gt;Raft算法原理 - codedump的网络日志&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Elasticsearch 磁盘使用优化实践</title>
        <published>2024-09-19T12:00:00+08:00</published>
        <updated>2024-09-19T12:00:00+08:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/disk-usage/"/>
        <id>https://scp.net.cn/blog/disk-usage/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/disk-usage/">&lt;h2 id=&quot;bei-jing-yu-mu-biao&quot;&gt;背景与目标&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;背景：随着数据规模增长与保留期延长，Elasticsearch 的段文件、复制、存储字段与快照会快速膨胀。&lt;/li&gt;
&lt;li&gt;目标：在保证查询能力与可靠性的前提下，系统性降低磁盘使用成本，并明确权衡与风险。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;参考：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tune for disk usage（Elasticsearch 6.8 指南）：https://www.elastic.co/guide/en/elasticsearch/reference/6.8/tune-for-disk-usage.html&lt;/li&gt;
&lt;li&gt;Optimize disk usage（Elastic Docs）：https://www.elastic.co/docs/deploy-manage/production-guidance/optimize-performance/disk-usage&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;yi-ye-qing-dan-quick-wins&quot;&gt;一页清单（Quick Wins）&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;将索引设置为 &lt;code&gt;index.codec: best_compression&lt;/code&gt;，仅在只读或写入压力可接受场景使用。&lt;/li&gt;
&lt;li&gt;只对需要排序/聚合的字段启用 &lt;code&gt;doc_values&lt;/code&gt;（默认），避免在 &lt;code&gt;text&lt;/code&gt; 字段开启 &lt;code&gt;fielddata&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;为不需要短语/位置查询的 &lt;code&gt;text&lt;/code&gt; 字段设置 &lt;code&gt;index_options: docs&lt;/code&gt; 并关闭 &lt;code&gt;norms&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;依赖 &lt;code&gt;_source&lt;/code&gt; 返回，谨慎使用 &lt;code&gt;store: true&lt;/code&gt;；必要时做 &lt;code&gt;_source&lt;/code&gt; 过滤而非禁用。&lt;/li&gt;
&lt;li&gt;控制每索引的分片数量和大小，减少小分片；副本数按可靠性需求设置。&lt;/li&gt;
&lt;li&gt;对只读索引执行 &lt;code&gt;forcemerge&lt;/code&gt; 到较少段；通过 ILM 编排 rollover/shrink/forcemerge/delete。&lt;/li&gt;
&lt;li&gt;采用快照与（版本支持下的）searchable snapshots，将冷数据转移到对象存储。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;suo-yin-ji-ya-suo-best-compression&quot;&gt;索引级压缩：&lt;code&gt;best_compression&lt;/code&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;原理与权衡：将存储字段等改为更高压缩率（如 DEFLATE），降低磁盘占用但增加 CPU 与写入延迟。&lt;/li&gt;
&lt;li&gt;仅影响新段：更改后只对新生成的段生效；老段需 &lt;code&gt;forcemerge&lt;/code&gt; 才能受益。&lt;/li&gt;
&lt;li&gt;设置示例：&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;http&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;PUT&lt;/span&gt;&lt;span&gt; my-index/_settings&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;index&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;codec&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;best_compression&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;对只读历史索引，在 ILM 的 warm/cold 阶段配合 &lt;code&gt;forcemerge&lt;/code&gt; 使用更合适。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;ying-she-you-hua-zi-duan-ji-jian-fu&quot;&gt;映射优化：字段级减负&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;文本字段（不需要短语/位置时）：&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;http&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;PUT&lt;/span&gt;&lt;span&gt; my-index&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;settings&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: { &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;index.codec&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;best_compression&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot; },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;mappings&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;properties&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;text&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;index_options&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;docs&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;norms&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;keyword&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;doc_values&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;ts&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;doc_values&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;说明：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;index_options: docs&lt;/code&gt; 仅索引文档号，减少位置信息存储；不适用于短语查询与高亮。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;norms: false&lt;/code&gt; 关闭字段归一化元数据，缩减磁盘与内存。&lt;/li&gt;
&lt;li&gt;对需要聚合/排序的字段保留 &lt;code&gt;doc_values&lt;/code&gt;；在 &lt;code&gt;text&lt;/code&gt; 上避免开启 &lt;code&gt;fielddata&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;存储策略：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;默认不 &lt;code&gt;store&lt;/code&gt; 字段，依赖 &lt;code&gt;_source&lt;/code&gt; 返回；对超大文档可做 &lt;code&gt;_source&lt;/code&gt; 过滤（&lt;code&gt;_source.includes/excludes&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;禁用 &lt;code&gt;_source&lt;/code&gt; 会影响重建与更新；仅在有严格外部存储与明确不需重建时考虑。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;fen-pian-yu-fu-ben-jie-gou-cheng-ben-kong-zhi&quot;&gt;分片与副本：结构成本控制&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;分片数量与大小：每分片都有元数据与段开销；避免大量小分片。结合数据规模设置 &lt;code&gt;number_of_shards&lt;/code&gt;，通过 ILM 的 &lt;code&gt;shrink&lt;/code&gt; 合并到更少分片。&lt;/li&gt;
&lt;li&gt;副本数（&lt;code&gt;number_of_replicas&lt;/code&gt;）：降低副本可节省磁盘，但会降低容错能力；生产通常至少 1 副本。&lt;/li&gt;
&lt;li&gt;示例：小型索引可用：&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;http&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;PUT&lt;/span&gt;&lt;span&gt; small-index&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;settings&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;number_of_shards&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;number_of_replicas&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;sheng-ming-zhou-qi-ilm-zi-dong-hua-bian-pai&quot;&gt;生命周期（ILM）：自动化编排&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;策略示例（按规模调整）：&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;http&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;PUT&lt;/span&gt;&lt;span&gt; _ilm/policy/logs-policy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;policy&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;phases&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;hot&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;actions&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;          &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;rollover&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: { &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;max_size&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;50gb&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;max_age&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;7d&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;warm&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;actions&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;          &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;forcemerge&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: { &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;max_num_segments&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;          &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;shrink&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: { &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;number_of_shards&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;cold&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;actions&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;          &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;freeze&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;delete&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;min_age&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;30d&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;actions&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: { &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;delete&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {} }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;注意：&lt;code&gt;freeze&lt;/code&gt; 在新版本中已有替代方案（如 searchable snapshot/frozen tier），按版本文档选择对应能力。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;duan-he-bing-zhi-du-suo-yin-shang-de-forcemerge&quot;&gt;段合并：只读索引上的 &lt;code&gt;forcemerge&lt;/code&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;仅对只读索引使用，避免影响写入与查询；可显著减少段文件和开销。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;http&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;POST&lt;/span&gt;&lt;span&gt; my-index/_forcemerge?max_num_segments=1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;kuai-zhao-yu-gui-dang-an-ban-ben-neng-li&quot;&gt;快照与归档（按版本能力）&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;使用快照（S3/HDFS/自建对象存储）降低本地磁盘占用；在支持的版本上启用可检索快照，将冷数据转移到低成本存储。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;jian-kong-yu-shui-wei-fang-zhi-ci-pan-da-man&quot;&gt;监控与水位（防止磁盘打满）&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;使用默认或更严格的磁盘水位防护（按需调整）：&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;http&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;PUT&lt;/span&gt;&lt;span&gt; _cluster/settings&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;persistent&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;cluster.routing.allocation.disk.watermark.low&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;85%&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;cluster.routing.allocation.disk.watermark.high&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;90%&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;cluster.routing.allocation.disk.watermark.flood_stage&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;95%&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;搭配监控告警（如 Prometheus/Elastic Monitoring）对索引大小、段数、合并耗时、快照失败率等关键指标设置阈值。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;feng-xian-yu-quan-heng&quot;&gt;风险与权衡&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;best_compression&lt;/code&gt;：写入与合并更耗 CPU；在写重负载场景谨慎使用。&lt;/li&gt;
&lt;li&gt;关闭 &lt;code&gt;norms&lt;/code&gt; 与降低 &lt;code&gt;index_options&lt;/code&gt;：会影响打分、短语查询与高亮；按查询需求评估。&lt;/li&gt;
&lt;li&gt;减少副本：降低磁盘但降低容错；需结合可靠性与恢复目标（RPO/RTO）。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;forcemerge&lt;/code&gt;：仅对只读索引执行；过程耗时且资源占用高，建议窗口期执行。&lt;/li&gt;
&lt;li&gt;禁用 &lt;code&gt;_source&lt;/code&gt;：几乎阻断重建与更新能力；一般不推荐。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;can-kao&quot;&gt;参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Elasticsearch 6.8：Tune for disk usage
&lt;ul&gt;
&lt;li&gt;https://www.elastic.co/guide/en/elasticsearch/reference/6.8/tune-for-disk-usage.html&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Elastic Docs：Optimize disk usage
&lt;ul&gt;
&lt;li&gt;https://www.elastic.co/docs/deploy-manage/production-guidance/optimize-performance/disk-usage&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>ChaosBlade 二次开发实践</title>
        <published>2024-08-18T12:13:32+05:30</published>
        <updated>2024-08-18T12:13:32+05:30</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/chaos-build/"/>
        <id>https://scp.net.cn/blog/chaos-build/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/chaos-build/">&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;背景与目标&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在企业落地混沌工程时，往往需要定制符合自身技术栈与业务场景的故障注入能力；二次开发的目标是扩展官方场景、统一 CLI/HTTP 入口，并在平台侧形成可审计、可回滚、可观测的闭环。（参考 [0]）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;架构认知（把握扩展点）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;模块拆分：&lt;code&gt;chaosblade&lt;/code&gt;（CLI/HTTP 管理）、&lt;code&gt;chaosblade-spec-go&lt;/code&gt;（规范定义）、&lt;code&gt;chaosblade-exec-os&lt;/code&gt;/&lt;code&gt;-docker&lt;/code&gt;/&lt;code&gt;-cri&lt;/code&gt;/&lt;code&gt;-operator&lt;/code&gt;/&lt;code&gt;-jvm&lt;/code&gt;/&lt;code&gt;-cplus&lt;/code&gt; 等领域场景，统一由 CLI 调用，遵循混沌实验模型。（参考 [0]）&lt;/li&gt;
&lt;li&gt;统一命令：&lt;code&gt;prepare&lt;/code&gt;/&lt;code&gt;revoke&lt;/code&gt;（环境准备与撤销）、&lt;code&gt;create&lt;/code&gt;（创建实验）、&lt;code&gt;destroy&lt;/code&gt;（销毁实验）、&lt;code&gt;status&lt;/code&gt;（查询状态）。示例：&lt;code&gt;blade create [TARGET] [ACTION] [FLAGS]&lt;/code&gt;；Dubbo 延迟示例：&lt;code&gt;blade create dubbo delay --consumer --time 3000 --Service xxx.xxx.Service&lt;/code&gt;（参考 [0]）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;开发准备&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;建议环境：&lt;code&gt;Go &amp;gt;= 1.20&lt;/code&gt;、Linux 主机（或容器/K8s 节点）、必要的系统工具（如 &lt;code&gt;tc/iptables/stress-ng&lt;/code&gt;）、可选：&lt;code&gt;JDK 8+&lt;/code&gt;（JVM 场景）、&lt;code&gt;GDB&lt;/code&gt;（C++ 场景）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;设计你的场景（Spec）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;明确 &lt;code&gt;Target/Action/Flags&lt;/code&gt; 与约束：例如目标是 &lt;code&gt;os.network&lt;/code&gt;，动作是 &lt;code&gt;delay/loss&lt;/code&gt;，参数含义与合法范围（单位、最小/最大值、是否必填、默认值），以及对环境的依赖与回收策略。&lt;/li&gt;
&lt;li&gt;在 &lt;code&gt;chaosblade-spec-go&lt;/code&gt; 中定义规范结构，声明校验规则与示例用法；完成后在对应 &lt;code&gt;exec-*&lt;/code&gt; 项目实现执行逻辑。（参考 [0]）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;实现与注册（以 OS 场景为例）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;新增 Spec：在 &lt;code&gt;chaosblade-exec-os&lt;/code&gt; 中增加你的场景 Spec（如 &lt;code&gt;os network delay&lt;/code&gt;），补充参数校验与帮助说明。&lt;/li&gt;
&lt;li&gt;编写 Executor：根据 Spec 解析参数，调用系统工具注入与回收（例如 &lt;code&gt;tc qdisc&lt;/code&gt; 注入延时、&lt;code&gt;iptables&lt;/code&gt; 配合丢包、或通过 &lt;code&gt;stress-ng&lt;/code&gt; 做 CPU/内存压力）。&lt;/li&gt;
&lt;li&gt;注册到 CLI/HTTP：在 &lt;code&gt;chaosblade&lt;/code&gt; 工程侧暴露新场景（帮助文本、参数说明），保证 &lt;code&gt;blade create ...&lt;/code&gt; 能识别并执行。&lt;/li&gt;
&lt;li&gt;编译验证：执行 &lt;code&gt;blade create ...&lt;/code&gt; 获得 &lt;code&gt;uid&lt;/code&gt;；用 &lt;code&gt;blade status UID&lt;/code&gt; 查看状态；用 &lt;code&gt;blade destroy UID&lt;/code&gt; 回收；如涉及 JVM，需先 &lt;code&gt;blade p jvm --process &amp;lt;app&amp;gt;&lt;/code&gt;，结束后 &lt;code&gt;blade revoke UID&lt;/code&gt;（参考 [0]）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;测试与工程化&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;覆盖正/反/异常路径：非法参数、权限不足、环境缺依赖、重复注入、异常中断后的回收。&lt;/li&gt;
&lt;li&gt;幂等与回收：确保多次执行不会污染环境；任何失败都能走到回收分支；对系统资源设定超时/重试/保护阈值。&lt;/li&gt;
&lt;li&gt;可观测性：输出清晰的 &lt;code&gt;uid&lt;/code&gt;、阶段日志、关键指标（延时/丢包/CPU/内存等），便于平台观测与审计。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;实战命令片段（示例）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;环境准备：&lt;code&gt;blade p jvm --process business&lt;/code&gt; → 返回 &lt;code&gt;uid&lt;/code&gt;；撤销：&lt;code&gt;blade revoke UID&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;创建实验：&lt;code&gt;blade create os network delay --time 3000 --interface eth0&lt;/code&gt;；查询：&lt;code&gt;blade status UID&lt;/code&gt;；销毁：&lt;code&gt;blade destroy UID&lt;/code&gt;。（命令形态与参数以你的 Spec 为准，参考 [0]）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;常见坑与排错&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;权限与依赖：&lt;code&gt;tc/iptables&lt;/code&gt; 需 root；容器内需 CAP 能力；K8s 场景需正确的 CRD 与 Operator。&lt;/li&gt;
&lt;li&gt;JVM attach 失败：进程名不匹配/无权限/目标 JDK 版本不兼容；优先用 &lt;code&gt;prepare&lt;/code&gt; 返回的 &lt;code&gt;uid&lt;/code&gt; 做状态跟踪（参考 [0]）。&lt;/li&gt;
&lt;li&gt;资源回收不彻底：为每一步注入动作设计对称的回收；失败时也要进入回收分支。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;chaosblade-box-ping-tai-ji-cheng-shi-jian&quot;&gt;Chaosblade-box 平台集成实践&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;目标与价值&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;将自定义场景在平台侧可视化、流程化管理：支持编排、权限控制、审计与留痕、统一的执行/回收闭环，并与企业现有运维与治理体系对接。（参考 [1]）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;编译与运行（Host/K8s）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;打包：&lt;code&gt;mvn clean package -Dmaven.test.skip=true&lt;/code&gt;。（参考 [1]）&lt;/li&gt;
&lt;li&gt;MySQL（Docker 示例，需替换密码）：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;docker run -d -it -p 3306:3306 \       -e MYSQL_DATABASE=chaosblade \       -e MYSQL_ROOT_PASSWORD=[DATASOURCE_PASSWORD] \       --name mysql-5.6 mysql:5.6 \       --character-set-server=utf8mb4 \       --collation-server=utf8mb4_unicode_ci \       --default-time_zone=&#39;+8:00&#39; \       --lower_case_table_names=1&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;启动应用（Host）：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;nohup java -Duser.timezone=Asia/Shanghai -jar chaosblade-box-1.0.0.jar --spring.datasource.url=&quot;jdbc:mysql://DATASOURCE_HOST:3306/chaosblade?characterEncoding=utf8&amp;amp;useSSL=false&quot; --spring.datasource.username=DATASOURCE_USERNAME --spring.datasource.password=DATASOURCE_PASSWORD --chaos.server.domain=BOX-HOST &amp;gt; chaosblade-box.log 2&amp;gt;&amp;amp;1 &amp;amp;&lt;/code&gt;（参考 [1]）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Kubernetes（Helm）：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;helm install chaosblade-box chaosblade-box-1.0.0.tgz --namespace chaosblade --set spring.datasource.password=DATASOURCE_PASSWORD&lt;/code&gt;（参考 [1]）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;首次数据与 Agent 参数（节选）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;chaos.function.sync.type&lt;/code&gt;：首启可用 &lt;code&gt;ALL&lt;/code&gt; 预置数据；可选值 &lt;code&gt;ALL/ChaosBlade/UserApp/None/LITMUS_CHAOS&lt;/code&gt;（参考 [1]）。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;chaos.agent.version/chaos.agent.repository/chaos.agent.url/chaos.agent.helm&lt;/code&gt;：配置 Agent 包版本与仓库地址（参考 [1]）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;集成你的自定义场景&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;平台端注册函数定义：绑定 CLI/Operator 场景，维护参数表单与校验；对接执行器与状态查询。&lt;/li&gt;
&lt;li&gt;K8s 场景建议通过 &lt;code&gt;chaosblade-operator&lt;/code&gt; 以 CRD 标准定义与编排，复用平台与 CLI 的统一模型。（参考 [0]）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;平台化流程建议&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;变更审批 → 预检查（依赖、权限、风险）→ 创建实验 → 观测（日志/指标）→ 回收/销毁 → 审计归档。&lt;/li&gt;
&lt;li&gt;多租户与 RBAC、白名单/黑名单、窗口期与最小化 blast radius、SLO/SLA 保护阈值。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;常见问题与排错&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数据库连接与权限：确认 &lt;code&gt;DATASOURCE_HOST/USERNAME/PASSWORD&lt;/code&gt; 与字符集/时区设置；容器网络与端口暴露。&lt;/li&gt;
&lt;li&gt;Agent 下载与版本：仓库地址可用自建镜像；确保与目标环境（K8s/Host）兼容；首次同步完成后再执行实验。&lt;/li&gt;
&lt;li&gt;Helm values：根据集群需求调整资源配额与节点亲和；服务暴露方式与域名解析（参考 [1]）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;da-gui-mo-yan-lian-jian-kong-yu-wen-ding-xing-bao-zhang&quot;&gt;大规模演练监控与稳定性保障&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;设计原则&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;演练前-中-后三段监控闭环：容量评估、实时指标、回收确认。&lt;/li&gt;
&lt;li&gt;指标分层：资源/平台/中间件/应用四层，设置 SLO 与熔断阈值。&lt;/li&gt;
&lt;li&gt;平台联动：在 chaosblade-box 中定义“停止条件”，当触发阈值自动终止实验并回收。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;演练熔断与降速建议&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;触发任一核心阈值时：自动执行 &lt;code&gt;destroy&lt;/code&gt;/回收，记录 &lt;code&gt;uid&lt;/code&gt; 与原因。&lt;/li&gt;
&lt;li&gt;阀值分级：预警（黄）→ 降速（橙，降低并发/扩大批次间隔）→ 熔断（红）。&lt;/li&gt;
&lt;li&gt;分批策略：分域/分租户/分环境逐步推进，控制 blast radius。&lt;/li&gt;
&lt;li&gt;观测确认：回收后持续观察 5–10 分钟，指标回归正常再进入下一批。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;实施清单&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在 &lt;code&gt;chaosblade-box&lt;/code&gt; 配置“停止条件”与告警；对接 Alertmanager。&lt;/li&gt;
&lt;li&gt;在实验模板/表单中暴露 Redis/MySQL/K8s 指标的阈值可配置项。&lt;/li&gt;
&lt;li&gt;对关键指标设置 Dashboard 与 Runbook，确保排错路径明确。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;can-kao-zi-liao&quot;&gt;参考资料&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;ChaosBlade 项目与规范&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;官方仓库与 CLI 文档：https://github.com/chaosblade-io/chaosblade&lt;/li&gt;
&lt;li&gt;规范定义（Golang）：https://github.com/chaosblade-io/chaosblade-spec-go&lt;/li&gt;
&lt;li&gt;OS 场景实现：https://github.com/chaosblade-io/chaosblade-exec-os&lt;/li&gt;
&lt;li&gt;Docker 场景实现：https://github.com/chaosblade-io/chaosblade-exec-docker&lt;/li&gt;
&lt;li&gt;CRI 场景实现：https://github.com/chaosblade-io/chaosblade-exec-cri&lt;/li&gt;
&lt;li&gt;JVM 场景实现：https://github.com/chaosblade-io/chaosblade-exec-jvm&lt;/li&gt;
&lt;li&gt;C++ 场景实现：https://github.com/chaosblade-io/chaosblade-exec-cplus&lt;/li&gt;
&lt;li&gt;Kubernetes Operator（CRD）：https://github.com/chaosblade-io/chaosblade-operator&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Chaosblade-box 平台&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;平台仓库与部署说明：https://github.com/chaosblade-io/chaosblade-box&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;监控与告警（Prometheus 生态）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PromQL 基础与语法：https://prometheus.io/docs/prometheus/latest/querying/basics/&lt;/li&gt;
&lt;li&gt;Alertmanager 文档：https://prometheus.io/docs/alerting/latest/alertmanager/&lt;/li&gt;
&lt;li&gt;Redis Exporter（指标项）：https://github.com/oliver006/redis_exporter&lt;/li&gt;
&lt;li&gt;MySQLd Exporter（指标项）：https://github.com/prometheus/mysqld_exporter&lt;/li&gt;
&lt;li&gt;Node Exporter（节点指标）：https://github.com/prometheus/node_exporter&lt;/li&gt;
&lt;li&gt;kube-state-metrics（K8s 对象指标）：https://github.com/kubernetes/kube-state-metrics&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;社区文章&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;https://zhuanlan.zhihu.com/p/598323365&lt;/li&gt;
&lt;li&gt;https://mp.weixin.qq.com/s?__biz=Mzg3MzgxMjc3NA==&amp;amp;mid=2247484031&amp;amp;idx=1&amp;amp;sn=4bfc81c1ee268dc0c8d529a4b5fc9949&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://juejin.cn/post/7266092256372998196&quot;&gt;混沌工程之 ChaosBlade 利刃出鞘 - 掘金&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://juejin.cn/post/7267919801779470397&quot;&gt;ChaosBlade Tool 故障注入百宝箱 - 掘金&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>ollama 教程</title>
        <published>2024-02-20T02:01:58+05:30</published>
        <updated>2024-02-20T02:01:58+05:30</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/ollama-intro/"/>
        <id>https://scp.net.cn/blog/ollama-intro/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/ollama-intro/">&lt;p&gt;使用 &lt;code&gt;ollama&lt;/code&gt; 在本地运行大模型，并完成几个辅助编程的示例。&lt;/p&gt;
&lt;h2 id=&quot;an-zhuang-ollama&quot;&gt;安装 ollama&lt;/h2&gt;
&lt;p&gt;官网地址：&lt;a rel=&quot;external&quot; href=&quot;https://ollama.com/&quot;&gt;https://ollama.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;GitHub 地址：&lt;a rel=&quot;external&quot; href=&quot;https://github.com/ollama/ollama&quot;&gt;GitHub - ollama/ollama&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;开源模型列表：&lt;a rel=&quot;external&quot; href=&quot;https://ollama.com/library&quot;&gt;Models&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;可以根据官网介绍安装 ollama 到本地&lt;/p&gt;
&lt;img title=&quot;&quot; src=&quot;https://scp-net-cn.oss-cn-beijing.aliyuncs.com/blog-images/20240220230742.png&quot; alt=&quot;&quot; width=&quot;463&quot;&gt;
&lt;p&gt;安装完后执行以下命令&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 下载模型&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;ollama&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; pull llama2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;ollama&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; pull codellama:7b&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 查看可用模型列表&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;ollama&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; list&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 测试&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;ollama&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; run codellama:7b&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;使用 java 写一个 hello world 程序&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 测试结果 下面是 AI 生成的内容&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Here&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; is an example of a&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Hello World&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; program in Java:&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;public class&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; HelloWorld&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; public static void&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; main&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[]&lt;/span&gt;&lt;span&gt; args&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; System&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;out&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Hello, World!&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;This program will print the string &amp;quot;Hello, World!&amp;quot; to the console when it is run.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;To compile and run this program, you can use the following commands:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ javac HelloWorld.java&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ java HelloWorld&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;The first command compiles the Java code into a class file named `HelloWorld.class`. The second command runs the `main` method of the&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;`HelloWorld` class, which prints the string &amp;quot;Hello, World!&amp;quot; to the console.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;fu-zhu-bian-cheng-demo&quot;&gt;辅助编程 Demo&lt;/h2&gt;
&lt;h3 id=&quot;dai-ma-bian-xie&quot;&gt;代码编写&lt;/h3&gt;
&lt;p&gt;运行命令&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;ollama&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; run codellama:7b&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;你是一个 python 专家，给我写一个 简单 计算器 代码&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;生成 python 代码&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; calculate&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;num1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; num2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; op&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    if&lt;/span&gt;&lt;span&gt; op&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return&lt;/span&gt;&lt;span&gt; num1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span&gt; num2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    elif&lt;/span&gt;&lt;span&gt; op&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return&lt;/span&gt;&lt;span&gt; num1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; -&lt;/span&gt;&lt;span&gt; num2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    elif&lt;/span&gt;&lt;span&gt; op&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return&lt;/span&gt;&lt;span&gt; num1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; *&lt;/span&gt;&lt;span&gt; num2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    elif&lt;/span&gt;&lt;span&gt; op&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return&lt;/span&gt;&lt;span&gt; num1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; /&lt;/span&gt;&lt;span&gt; num2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    else&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        raise&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; ValueError&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Invalid operator&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;生成的 代码介绍&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;这个代码是一个简单的计算器，它接收三个参数：`num1`、`num2` 和 `op`。`num1` 和 `num2` 是被操作数，`op` 是操作符。这个函数将根据 `op` 的值执行相应的计算并返回结果。例如，如果 `op` 为 `&amp;quot;+&amp;quot;`，则返回 `num&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;num2`，否则将引发一个 `ValueError`。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;这个代码使用了 Python 中的 `if-else` 语句来处理不同的操作符。在 Python 中，`if-else` 语句可以用于根据条件判断执行不同&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;语句来处理三种可能的操作符：加法、减法、乘法和除法。如果传入的操作符不是其中一个，则将引发一个 `ValueError`。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;这个代码使用了 Python 中的 `return` 语句来返回结果。在 Python 中，`return` 语句可以用于在函数内部返回值。如果我们不使用 `return` 语句，则函数将执行完成后直接退出，并且无法返回任何结果。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;这个代码使用了 Python 中的 `raise ValueError` 来引发一个 `ValueError`。在 Python 中，`ValueError` 是一种可以被抛出的异常（exception），它可以用于表示函数或程序中的一个错误。如果我们使用了一个无效的操作符，则将引发一是一种可以被抛出的异常（exception），它可以用于表示函数或程序中的一个错误。如果我们使用了一个无效的操作符，则将引发一个 `ValueError` 来通知调用者。&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;code-review&quot;&gt;Code Review&lt;/h3&gt;
&lt;p&gt;运行命令&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;ollama&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; run codellama&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Where is the bug in this code?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;def calculate(num1, num2, op):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;    if op == &amp;quot;+&amp;quot;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;        return num1 + num2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;    elif op == &amp;quot;-&amp;quot;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;        return num1 - num2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;    elif op == &amp;quot;*&amp;quot;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;        return num1 * num2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;    elif op == &amp;quot;/&amp;quot;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;        return num1 / num2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;    else:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;        raise ValueError(&amp;quot;Invalid operator&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;执行结果&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这个模型能发现 除0 的bug，而且可以给出修正后的代码。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;The bug in this code is that the function does not handle division by zero. If the user enters a divide operation (op == &amp;quot;/&amp;quot;) and the second&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;number (num2) is equal to zero, the function will throw a ZeroDivisionError. To fix this, we can add an additional check to make sure that&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;num2 is not equal to zero before performing the division.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Here&amp;#39;s the corrected code:&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; calculate&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;num1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; num2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; op&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; if&lt;/span&gt;&lt;span&gt; op&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return&lt;/span&gt;&lt;span&gt; num1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span&gt; num2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; elif&lt;/span&gt;&lt;span&gt; op&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return&lt;/span&gt;&lt;span&gt; num1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; -&lt;/span&gt;&lt;span&gt; num2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; elif&lt;/span&gt;&lt;span&gt; op&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return&lt;/span&gt;&lt;span&gt; num1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; *&lt;/span&gt;&lt;span&gt; num2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; elif&lt;/span&gt;&lt;span&gt; op&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; and&lt;/span&gt;&lt;span&gt; num2&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; !=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; return&lt;/span&gt;&lt;span&gt; num1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; /&lt;/span&gt;&lt;span&gt; num2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; else&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; raise&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; ValueError&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Invalid operator&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;bian-xie-dan-yuan-ce-shi&quot;&gt;编写单元测试&lt;/h3&gt;
&lt;p&gt;运行命令&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;ollama&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; run codellama&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;write a unit test for this function: &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;def calculate(num1, num2, op):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;    if op == &amp;quot;+&amp;quot;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;        return num1 + num2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;    elif op == &amp;quot;-&amp;quot;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;        return num1 - num2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;    elif op == &amp;quot;*&amp;quot;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;        return num1 * num2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;    elif op == &amp;quot;/&amp;quot; and num2 != 0:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;        return num1 / num2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;    else:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;        raise ValueError(&amp;quot;Invalid operator&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;运行结果&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;可以准确给出单元测代码&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; test_calculate&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;():&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; assert&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; calculate&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 7&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; assert&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; calculate&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; assert&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; calculate&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;6&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 18&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; assert&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; calculate&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; with&lt;/span&gt;&lt;span&gt; pytest&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;raises&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;ValueError&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; calculate&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;This unit test covers all the possible cases for the `calculate` function:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* Adding two numbers (3 + 4 = 7)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* Subtracting two numbers (5 - 2 = 3)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* Multiplying two numbers (6 * 3 = 18)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* Dividing two numbers (10 / 2 = 5)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* Dividing by zero (raises a `ValueError`)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;The test uses the `pytest` framework to write and run the unit tests. The `assert` statement is used to verify that the function returns the&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;expected result for each operation. The `with pytest.raises(ValueError):` block is used to test that an error is raised when dividing by zero.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;dai-ma-ti-shi&quot;&gt;代码提示&lt;/h3&gt;
&lt;p&gt;运行命令&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;ollama&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; run codellama:7b&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;# 提供一个函数反转数组元素:&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;执行结果&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[PYTHON]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;def reverse(my_list):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    return my_list[::-1]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[/PYTHON]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[TESTS]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Test case 1:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;assert reverse([]) == []&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Test case 2:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;assert reverse([1, 2, 3]) == [3, 2, 1]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Test case 3:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;assert reverse([1, 2, 3, 4, 5]) == [5, 4, 3, 2, 1]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[/TESTS]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;dai-ma-bu-qi&quot;&gt;代码补齐&lt;/h3&gt;
&lt;p&gt;运行命令&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;需要使用下面这种格式的提示词&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;PRE&amp;gt; {prefix} &amp;lt;SUF&amp;gt;{suffix} &amp;lt;MID&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;ollama&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; run codellama:7b&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;&amp;lt;PRE&amp;gt; def max_val(x, y): &amp;lt;SUF&amp;gt;return result &amp;lt;MID&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;执行结果&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  # Check if x is greater than y&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if x &amp;gt; y:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        result = x&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    else:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        result = y&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     &amp;lt;EOT&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;EOT&amp;gt;&lt;/code&gt; 是一个结束标记，与 &lt;code&gt;&amp;lt;PRE&amp;gt;&lt;/code&gt; &lt;code&gt;&amp;lt;SUF&amp;gt;&lt;/code&gt; &lt;code&gt;&amp;lt;MID&amp;gt;&lt;/code&gt; 类似&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;java-spring&quot;&gt;Java &amp;amp; Spring&lt;/h3&gt;
&lt;p&gt;运行命令&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;ollama&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; run codellama:7b&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;# Java Spring MVC 输出 hello world&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;public String helloworld():&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;执行结果&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color: #D08770;&quot;&gt;RequestMapping&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;value&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;/helloworld&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span&gt; method&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; RequestMethod&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;GET&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; String&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; helloworld&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Hello, World!&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;gong-ju-bao&quot;&gt;工具包&lt;/h2&gt;
&lt;h3 id=&quot;python&quot;&gt;python&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pip install ollama&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 简单问答&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span&gt; ollama&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;response&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; ollama&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;chat&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;model&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;llama2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span&gt; messages&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;: &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;: &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Why is the sky blue?&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;response&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;][&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;])&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 获取生成的内容流&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;for&lt;/span&gt;&lt;span&gt; chunk&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; chat&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;mistral&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span&gt; messages&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt;messages&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; stream&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=True&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;chunk&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;][&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;],&lt;/span&gt;&lt;span&gt; end&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&amp;#39;,&lt;/span&gt;&lt;span&gt; flush&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=True&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 文本生成&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;result&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; ollama&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;generate&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  model&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;stable-code&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  prompt&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;// A c function to reverse a string&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;result&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;response&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;])&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# Multi-modal 图片识别&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;with&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; open&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;image.png&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;, &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;rb&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; as&lt;/span&gt;&lt;span&gt; file&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  response&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; ollama&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;chat&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    model&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;llava&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    messages&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;: &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;: &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;What is strange about this image?&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;images&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;: [&lt;/span&gt;&lt;span&gt;file&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;read&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;      },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    ],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;response&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;][&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;])&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 自定义模型&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;modelfile&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;FROM llama2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;SYSTEM You are mario from super mario bros.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ollama&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;create&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;model&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;example&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span&gt; modelfile&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt;modelfile&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# client&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ollama&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Client&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;host&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;my.ollama.host&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;javascript&quot;&gt;JavaScript&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;npm install ollama&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; ollama&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;ollama&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;const&lt;/span&gt;&lt;span&gt; response&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = await&lt;/span&gt;&lt;span&gt; ollama&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;chat&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  model&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;llama2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;  messages&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; role&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; content&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Why is the sky blue?&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39; }&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;console&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;log&lt;/span&gt;&lt;span&gt;(response&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;message&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;content)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;http-api&quot;&gt;HTTP API&lt;/h3&gt;
&lt;p&gt;API文档：https://github.com/ollama/ollama/blob/main/docs/api.md&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;curl http://localhost:11434/api/generate -d &amp;#39;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &amp;quot;model&amp;quot;: &amp;quot;llama2&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &amp;quot;prompt&amp;quot;:&amp;quot;Why is the sky blue?&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;langchain&quot;&gt;LangChain&lt;/h3&gt;
&lt;p&gt;参考文档：https://python.langchain.com/docs/integrations/llms/ollama&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;from&lt;/span&gt;&lt;span&gt; langchain_community&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;llms&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; import&lt;/span&gt;&lt;span&gt; Ollama&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;llm&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Ollama&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;model&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;llama2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;llm&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;invoke&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Tell me a joke&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;query&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Tell me a joke&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;for&lt;/span&gt;&lt;span&gt; chunks&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; in&lt;/span&gt;&lt;span&gt; llm&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;stream&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;query&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;chunks&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;ke-shi-hua-gong-ju&quot;&gt;可视化工具&lt;/h2&gt;
&lt;h3 id=&quot;ollamac&quot;&gt;Ollamac&lt;/h3&gt;
&lt;p&gt;地址：&lt;a rel=&quot;external&quot; href=&quot;https://github.com/kevinhermawan/Ollamac&quot;&gt;GitHub - kevinhermawan/Ollamac: A macOS app for interacting with the Ollama models&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;安装命令&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;brew&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; install --cask ollamac&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;演示Demo&lt;/strong&gt;&lt;/p&gt;
&lt;img src=&quot;https://scp-net-cn.oss-cn-beijing.aliyuncs.com/blog-images/20240221000724.png&quot; title=&quot;&quot; alt=&quot;&quot; width=&quot;767&quot;&gt;
&lt;h3 id=&quot;open-webui&quot;&gt;Open WebUI&lt;/h3&gt;
&lt;p&gt;地址：&lt;a rel=&quot;external&quot; href=&quot;https://github.com/open-webui/open-webui&quot;&gt;GitHub - open-webui/open-webui: ChatGPT-Style WebUI for LLMs (Formerly Ollama WebUI)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;安装命令&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; run -d -p 3000:8080 --add-host=host.docker.internal:host-gateway -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;演示Demo&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;浏览器打开 &lt;code&gt;http://127.0.0.1:3000/&lt;/code&gt;&lt;/p&gt;
&lt;img src=&quot;https://scp-net-cn.oss-cn-beijing.aliyuncs.com/blog-images/20240221002641.png&quot; title=&quot;&quot; alt=&quot;&quot; width=&quot;694&quot;&gt;
&lt;h2 id=&quot;can-kao-zi-liao&quot;&gt;参考资料&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://ollama.com/blog&quot;&gt;Blog · Ollama&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://arthurchiao.art/blog/llama-paper-zh/&quot;&gt;[译][论文] LLaMA：开放和高效的基础语言模型集（Meta/Facebook，2022）&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;https://python.langchain.com/docs/integrations/llms/ollama&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://klu.ai/glossary/ollama&quot;&gt;Ollama: Easily run LLMs locally — Klu&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://ollama.com/blog/python-javascript-libraries&quot;&gt;Python &amp;amp; JavaScript Libraries · Ollama Blog&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://ollama.com/blog/openai-compatibility&quot;&gt;OpenAI compatibility · Ollama Blog&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>iptables相关资料收集和整理</title>
        <published>2024-01-27T12:13:35+05:30</published>
        <updated>2024-01-27T12:13:35+05:30</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/iptables-tour/"/>
        <id>https://scp.net.cn/blog/iptables-tour/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/iptables-tour/">&lt;h2 id=&quot;iptables-gui-ze-biao-he-lian&quot;&gt;iptables 规则表和链&lt;/h2&gt;
&lt;h3 id=&quot;iptablesjie-shao&quot;&gt;iptables介绍&lt;/h3&gt;
&lt;p&gt;    netfilter/iptables（简称为iptables）组成Linux平台下的包过滤防火墙，与大多数的Linux软件一样，这个包过滤防火墙是免费的，它可以代替昂贵的商业防火墙解决方案，完成封包过滤、封包重定向和网络地址转换（NAT）等功能。&lt;/p&gt;
&lt;p&gt;    规则（rules）其实就是网络管理员预定义的条件，规则一般的定义为“如果数据包头符合这样的条件，就这样处理这个数据包”。规则存储在内核空间的信息 包过滤表中，这些规则分别指定了源地址、目的地址、传输协议（如TCP、UDP、ICMP）和服务类型（如HTTP、FTP和SMTP）等。当数据包与规 则匹配时，iptables就根据规则所定义的方法来处理这些数据包，如放行（accept）、拒绝（reject）和丢弃（drop）等。配置防火墙的 主要工作就是添加、修改和删除这些规则。&lt;/p&gt;
&lt;p&gt;    Iptables和netfilter的关系是一个很容易让人搞不清的问题。很多的知道iptables却不知道netfilter。其实iptables只是Linux防火墙的管理工具而已，位于/sbin/iptables。真正实现防火墙功能的是netfilter，它是Linux内核中实现包过滤的内部结构。&lt;/p&gt;
&lt;h3 id=&quot;iptableschuan-shu-shu-ju-bao-de-guo-cheng&quot;&gt;iptables传输数据包的过程&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;当一个数据包进入网卡时，它首先进入PREROUTING链，内核根据数据包目的IP判断是否需要转送出去。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果数据包就是进入本机的，它就会沿着图向下移动，到达INPUT链。数据包到了INPUT链后，任何进程都会收到它。本机上运行的程序可以发送数据包，这些数据包会经过OUTPUT链，然后到达POSTROUTING链输出。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果数据包是要转发出去的，且内核允许转发，数据包就会如图所示向右移动，经过FORWARD链，然后到达POSTROUTING链输出。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://scp-net-cn.oss-cn-beijing.aliyuncs.com/blog-images/az6bh6fzc9.webp&quot; alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;h3 id=&quot;iptablesgui-ze-biao-he-lian&quot;&gt;iptables规则表和链&lt;/h3&gt;
&lt;p&gt;表（tables）提供特定的功能，iptables内置了4个表，即filter表、nat表、mangle表和raw表，分别用于实现包过滤，网络地址转换、包重构(修改)和数据跟踪处理。&lt;/p&gt;
&lt;p&gt;链（chains）是数据包传播的路径，每一条链其实就是众多规则中的一个检查清单，每一条链中可以有一 条或数条规则。当一个数据包到达一个链时，iptables就会从链中第一条规则开始检查，看该数据包是否满足规则所定义的条件。如果满足，系统就会根据 该条规则所定义的方法处理该数据包；否则iptables将继续检查下一条规则，如果该数据包不符合链中任一条规则，iptables就会根据该链预先定 义的默认策略来处理数据包。&lt;/p&gt;
&lt;p&gt;Iptables采用“表”和“链”的分层结构。在REHL4中是三张表五个链。现在REHL5成了四张表五个链了，不过多出来的那个表用的也不太多，所以基本还是和以前一样。下面罗列一下这四张表和五个链。注意一定要明白这些表和链的关系及作用。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://scp-net-cn.oss-cn-beijing.aliyuncs.com/blog-images/fjqpcju771.webp&quot; alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;h4 id=&quot;gui-ze-biao&quot;&gt;规则表&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Filter 表：（作用链：INPUT、FORWARD、OUTPUT）用于过滤数据包，内核模块 &lt;a rel=&quot;external&quot; href=&quot;https://gitee.com/mirrors/linux_old1/blob/master/net/ipv4/netfilter/iptable_filter.c&quot;&gt;net/ipv4/netfilter/iptable_filter.c&lt;/a&gt;；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Nat 表：（作用链：PREROUTING、POSTROUTING、OUTPUT）用于网络地址转换（IP、端口），内核模块 &lt;a rel=&quot;external&quot; href=&quot;https://gitee.com/mirrors/linux_old1/blob/master/net/ipv4/netfilter/iptable_nat.c&quot;&gt;net/ipv4/netfilter/iptable_nat.c&lt;/a&gt;；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Mangle 表：（作用链：PREROUTING、POSTROUTING、INPUT、OUTPUT、FORWARD , 即作用于全部链），修改数据包的服务类型、TTL、并且可以配置路由实现QOS内核模块，内核模块 &lt;a rel=&quot;external&quot; href=&quot;https://gitee.com/mirrors/linux_old1/blob/master/net/ipv4/netfilter/iptable_mangle.c&quot;&gt;net/ipv4/netfilter/iptable_mangle.c&lt;/a&gt;；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Raw 表：（作用链：OUTPUT、PREROUTING），决定数据包是否被状态跟踪机制处理，内核模块：&lt;a rel=&quot;external&quot; href=&quot;https://gitee.com/mirrors/linux_old1/blob/master/net/ipv4/netfilter/iptable_raw.c&quot;&gt;net/ipv4/netfilter/iptable_raw.c&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;Raw表REHL4没有，常用的是Filter/Nat；&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id=&quot;gui-ze-lian&quot;&gt;规则链&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;INPUT：进来的数据包应用此规则链中的策略&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;OUTPUT：外出的数据包应用此规则链中的策略&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;FORWARD：转发数据包时应用此规则链中的策略&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;PREROUTING：对数据包作路由选择前应用此链中的策略，&lt;strong&gt;所有的数据包进来的时侯都先由这个链处理&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;POSTROUTING：对数据包作路由选择后应用此链中的策略，&lt;strong&gt;所有的数据包出来的时侯都先由这个链处理&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;规则链顺序：Raw –&amp;gt; Mangle –&amp;gt; Nat –&amp;gt; Filter&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;入站数据流向：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;    从外界到达防火墙的数据包，先被PREROUTING规则链处理（是否修改数据包地址等），之后会进行路由选择（判断该数据包应该发往何处），如果数据包的目标主机是防火墙本机（比如说Internet用户访问防火墙主机中的web服务器的数据包），那么内核将其传给INPUT链进行处理（决定是否允许通过等），通过以后再交给系统上层的应用程序（比如Apache服务器）进行响应。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;转发数据流方向：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;    来自外界的数据包到达防火墙后，首先被PREROUTING规则链处理，之后会进行路由选择，如果数据包的目标地址是其它外部地址（比如局域网用户通过网关访问QQ站点的数据包），则内核将其传递给FORWARD链进行处理（是否转发或拦截），然后再交给POSTROUTING规则链（是否修改数据包的地址等）进行处理。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;出站数据流向：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;    防火墙本机向外部地址发送的数据包（比如在防火墙主机中测试公网DNS服务器时），首先被OUTPUT规则链处理，之后进行路由选择，然后传递给POSTROUTING规则链（是否修改数据包的地址等）进行处理。&lt;/p&gt;
&lt;h4 id=&quot;guan-li-he-she-zhi-iptablesgui-ze&quot;&gt;管理和设置iptables规则&lt;/h4&gt;
&lt;p&gt;&lt;img src=&quot;https://scp-net-cn.oss-cn-beijing.aliyuncs.com/blog-images/7lir5ujikd.webp&quot; alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://scp-net-cn.oss-cn-beijing.aliyuncs.com/blog-images/zvozz5swl1.webp&quot; alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;iptables的基本用法：&lt;/strong&gt;&lt;code&gt;iptables [-t 表名] 命令选项 ［链名］ ［条件匹配］ ［-j 目标动作或跳转］&lt;/code&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;表名、链名用于指定iptables命令所操作的表和链，命令选项用于指定管理iptables规则的方式（比如：插入、增加、删除、查看等；条件匹配用于指定对符合什么样 条件的数据包进行处理；目标动作或跳转用于指定数据包的处理方式（比如允许通过、拒绝、丢弃、跳转（Jump）给其它链处理。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;命令选项：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;-A 在指定链的末尾添加（append）一条新的规则&lt;/p&gt;
&lt;p&gt;-D 删除（delete）指定链中的某一条规则，可以按规则序号和内容删除&lt;/p&gt;
&lt;p&gt;-I 在指定链中插入（insert）一条新的规则，默认在第一行添加&lt;/p&gt;
&lt;p&gt;-R 修改、替换（replace）指定链中的某一条规则，可以按规则序号和内容替换&lt;/p&gt;
&lt;p&gt;-L 列出（list）指定链中所有的规则进行查看&lt;/p&gt;
&lt;p&gt;-E 重命名用户定义的链，不改变链本身&lt;/p&gt;
&lt;p&gt;-F 清空（flush）&lt;/p&gt;
&lt;p&gt;-N 新建（new-chain）一条用户自己定义的规则链&lt;/p&gt;
&lt;p&gt;-X 删除指定表中用户自定义的规则链（delete-chain）&lt;/p&gt;
&lt;p&gt;-P 设置指定链的默认策略（policy）&lt;/p&gt;
&lt;p&gt;-Z 将所有表的所有链的字节和数据包计数器清零&lt;/p&gt;
&lt;p&gt;-n 使用数字形式（numeric）显示输出结果&lt;/p&gt;
&lt;p&gt;-v 查看规则表详细信息（verbose）的信息&lt;/p&gt;
&lt;p&gt;-V 查看版本(version)&lt;/p&gt;
&lt;p&gt;-h 获取帮助（help）&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;数据包处理方式：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;ACCEPT 允许数据包通过&lt;/p&gt;
&lt;p&gt;DROP 直接丢弃数据包，不给任何回应信息&lt;/p&gt;
&lt;p&gt;REJECT 拒绝数据包通过，必要时会给数据发送端一个响应的信息&lt;/p&gt;
&lt;p&gt;LOG在/var/log/messages文件中记录日志信息，然后将数据包传递给下一条规则&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;iptables防火墙规则的保存和恢复：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;iptables-save把规则保存到文件中，再由目录rc.d下的脚本（/etc/rc.d/init.d/iptables）自动装载&lt;/p&gt;
&lt;p&gt;使用命令iptables-save来保存规则。一般用&lt;/p&gt;
&lt;p&gt;&lt;code&gt;iptables-save &amp;gt; /etc/sysconfig/iptables&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;生成保存规则的文件 &lt;code&gt;/etc/sysconfig/iptables&lt;/code&gt;，&lt;/p&gt;
&lt;p&gt;也可以用&lt;/p&gt;
&lt;p&gt;&lt;code&gt;service iptables save&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;它能把规则自动保存在&lt;code&gt;/etc/sysconfig/iptables&lt;/code&gt;中。&lt;/p&gt;
&lt;p&gt;当计算机启动时，rc.d下的脚本将用命令iptables-restore调用这个文件，从而就自动恢复了规则&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id=&quot;chang-jian-shi-yong-an-li&quot;&gt;常见实用案例&lt;/h4&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 删除INPUT链的第一条规则&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -D INPUT&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# iptables防火墙常用的策略&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;1.拒绝进入防火墙的所有ICMP协议数据包&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -I INPUT -p icmp -j REJECT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;2.允许防火墙转发除ICMP协议以外的所有数据包&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A FORWARD -p ! icmp -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;说明：使用“！”可以将条件取反。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;3.拒绝转发来自192.168.1.10主机的数据，允许转发来自192.168.0.0/24网段的数据&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A FORWARD -s&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 192.168.1.11&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -j REJECT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A FORWARD -s 192.168.0.0/24 -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;说明：注意要把拒绝的放在前面不然就不起作用了啊。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;4.丢弃从外网接口（eth1）进入防火墙本机的源地址为私网地址的数据包&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A INPUT -i eth1 -s 192.168.0.0/16 -j DROP&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A INPUT -i eth1 -s 172.16.0.0/12 -j DROP&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A INPUT -i eth1 -s 10.0.0.0/8 -j DROP&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;5.封堵网段（192.168.1.0/24），两小时后解封。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# iptables -I INPUT -s 10.20.30.0/24 -j DROP&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# iptables -I FORWARD -s 10.20.30.0/24 -j DROP&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# at now 2 hours at&amp;gt; iptables -D INPUT 1 at&amp;gt; iptables -D FORWARD 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;说明：这个策略咱们借助crond计划任务来完成，就再好不过了。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span&gt;   Stopped     at now 2 hours&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;6.只允许管理员从202.13.0.0/16网段使用SSH远程登录防火墙主机。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A INPUT -p tcp --dport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 22&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -s 202.13.0.0/16 -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A INPUT -p tcp --dport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 22&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -j DROP&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;说明：这个用法比较适合对设备进行远程管理时使用，比如位于分公司中的SQL服务器需要被总公司的管理员管理时。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;7.允许本机开放从TCP端口20-1024提供的应用服务。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A INPUT -p tcp --dport 20:1024 -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A OUTPUT -p tcp --sport 20:1024 -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;8.允许转发来自192.168.0.0/24局域网段的DNS解析请求数据包。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A FORWARD -s 192.168.0.0/24 -p udp --dport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 53&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A FORWARD -d 192.168.0.0/24 -p udp --sport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 53&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;9.禁止其他主机ping防火墙主机，但是允许从防火墙上ping其他主机&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -I INPUT -p icmp --icmp-type Echo-Request -j DROP&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -I INPUT -p icmp --icmp-type Echo-Reply -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -I INPUT -p icmp --icmp-type destination-Unreachable -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;10.禁止转发来自MAC地址为00：0C：29：27：55：3F的和主机的数据包&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A FORWARD -m mac --mac-source 00:0c:29:27:55:3F -j DROP&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;说明：iptables中使用“-m&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 模块关键字”的形式调用显示匹配。咱们这里用“-m mac –mac-source”来表示数据包的源MAC地址。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;11.允许防火墙本机对外开放TCP端口20、21、25、110以及被动模式FTP端口1250-1280&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A INPUT -p tcp -m multiport --dport 20,21,25,110,1250:1280 -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;说明：这里用“-m&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; multiport –dport”来指定目的端口及范围&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;12.禁止转发源IP地址为192.168.1.20-192.168.1.99的TCP数据包。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A FORWARD -p tcp -m iprange --src-range 192.168.1.20-192.168.1.99 -j DROP&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;说明：此处用“-m&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; –iprange –src-range”指定IP范围。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;13.禁止转发与正常TCP连接无关的非—syn请求数据包。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A FORWARD -m state --state NEW -p tcp ! --syn -j DROP&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;说明：“-m&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; state”表示数据包的连接状态，“NEW”表示与任何连接无关的，新的嘛！&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;14.拒绝访问防火墙的新数据包，但允许响应连接或与已有连接相关的数据包&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A INPUT -p tcp -m state --state NEW -j DROP&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A INPUT -p tcp -m state --state ESTABLISHED,RELATED -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;说明：“ESTABLISHED”表示已经响应请求或者已经建立连接的数据包，“RELATED”表示与已建立的连接有相关性的，比如FTP数据连接等。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;15.只开放本机的web服务（80）、FTP(20、21、20450-20480&lt;/span&gt;&lt;span&gt;)，放行外部主机发住服务器其它端口的应答数据包，将其他入站数据包均予以丢弃处理。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -I INPUT -p tcp -m multiport --dport 20,21,80 -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -I INPUT -p tcp --dport 20450:20480 -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -I INPUT -p tcp -m state --state ESTABLISHED -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -P INPUT DROP&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 常用的 Linux iptables 规则&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;1.&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 删除所有现有规则&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -F&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;2.&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 设置默认的 chain 策略&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -P INPUT DROP&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -P FORWARD DROP&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -P OUTPUT DROP&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;3.&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 阻止某个特定的 IP 地址&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BLOCK_THIS_IP&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;x.x.x.x&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A INPUT -s&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;$BLOCK_THIS_IP&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -j DROP&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;4.&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 允许全部进来的（incoming）SSH&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A INPUT -i eth0 -p tcp --dport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 22&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -m state --state NEW,ESTABLISHED -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A OUTPUT -o eth0 -p tcp --sport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 22&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -m state --state ESTABLISHED -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;5.&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 只允许某个特定网络进来的 SSH&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A INPUT -i eth0 -p tcp -s 192.168.200.0/24 --dport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 22&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -m state --state NEW,ESTABLISHED -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A OUTPUT -o eth0 -p tcp --sport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 22&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -m state --state ESTABLISHED -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;6.&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 允许进来的（incoming）HTTP&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A INPUT -i eth0 -p tcp --dport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 80&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -m state --state NEW,ESTABLISHED -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A OUTPUT -o eth0 -p tcp --sport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 80&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -m state --state ESTABLISHED -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;7.&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 多端口（允许进来的 SSH、HTTP 和 HTTPS）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A INPUT -i eth0 -p tcp -m multiport --dports 22,80,443 -m state --state NEW,ESTABLISHED -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A OUTPUT -o eth0 -p tcp -m multiport --sports 22,80,443 -m state --state ESTABLISHED -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;8.&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 允许出去的（outgoing）SSH&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A OUTPUT -o eth0 -p tcp --dport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 22&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -m state --state NEW,ESTABLISHED -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A INPUT -i eth0 -p tcp --sport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 22&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -m state --state ESTABLISHED -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;9.&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 允许外出的（outgoing）SSH，但仅访问某个特定的网络&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A OUTPUT -o eth0 -p tcp -d 192.168.101.0/24 --dport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 22&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -m state --state NEW,ESTABLISHED -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A INPUT -i eth0 -p tcp --sport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 22&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -m state --state ESTABLISHED -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;10.&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 允许外出的（outgoing） HTTPS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A OUTPUT -o eth0 -p tcp --dport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 443&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -m state --state NEW,ESTABLISHED -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A INPUT -i eth0 -p tcp --sport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 443&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -m state --state ESTABLISHED -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;11.&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 对进来的 HTTPS 流量做负载均衡&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A PREROUTING -i eth0 -p tcp --dport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 443&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -m state --state NEW -m nth --counter&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; --every&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; --packet&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -j DNAT --to-destination 192.168.1.101:443&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A PREROUTING -i eth0 -p tcp --dport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 443&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -m state --state NEW -m nth --counter&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; --every&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; --packet&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -j DNAT --to-destination 192.168.1.102:443&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A PREROUTING -i eth0 -p tcp --dport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 443&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -m state --state NEW -m nth --counter&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; --every&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; --packet&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -j DNAT --to-destination 192.168.1.103:443&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;12.&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 从内部向外部 Ping&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A OUTPUT -p icmp --icmp-type echo-request -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A INPUT -p icmp --icmp-type echo-reply -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;13.&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 从外部向内部 Ping&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A INPUT -p icmp --icmp-type echo-request -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 14. 允许环回（loopback）访问&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A INPUT -i lo -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A OUTPUT -o lo -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;15.&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 允许 packets 从内网访问外网&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# if eth1 is connected to external network (internet)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# if eth0 is connected to internal network (192.168.1.x)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A FORWARD -i eth0 -o eth1 -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 16. 允许外出的  DNS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A OUTPUT -p udp -o eth0 --dport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 53&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A INPUT -p udp -i eth0 --sport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 53&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;17.&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 允许 NIS 连接&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# rpcinfo -p | grep ypbind ; This port is 853 and 850&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A INPUT -p tcp --dport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 111&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A INPUT -p udp --dport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 111&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A INPUT -p tcp --dport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 853&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A INPUT -p udp --dport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 853&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A INPUT -p tcp --dport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 850&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A INPUT -p udp --dport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 850&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;18.&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 允许某个特定网络 rsync 进入本机&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A INPUT -i eth0 -p tcp -s 192.168.101.0/24 --dport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 873&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -m state --state NEW,ESTABLISHED -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A OUTPUT -o eth0 -p tcp --sport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 873&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -m state --state ESTABLISHED -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;19.&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 仅允许来自某个特定网络的 MySQL 的链接&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A INPUT -i eth0 -p tcp -s 192.168.200.0/24 --dport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 3306&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -m state --state NEW,ESTABLISHED -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A OUTPUT -o eth0 -p tcp --sport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 3306&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -m state --state ESTABLISHED -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;20.&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 允许 Sendmail 或 Postfix&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A INPUT -i eth0 -p tcp --dport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 25&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -m state --state NEW,ESTABLISHED -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A OUTPUT -o eth0 -p tcp --sport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 25&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -m state --state ESTABLISHED -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;21.&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 允许 IMAP 和 IMAPS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A INPUT -i eth0 -p tcp --dport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 143&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -m state --state NEW,ESTABLISHED -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A OUTPUT -o eth0 -p tcp --sport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 143&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -m state --state ESTABLISHED -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A INPUT -i eth0 -p tcp --dport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 993&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -m state --state NEW,ESTABLISHED -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A OUTPUT -o eth0 -p tcp --sport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 993&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -m state --state ESTABLISHED -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;22.&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 允许 POP3 和 POP3S&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A INPUT -i eth0 -p tcp --dport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 110&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -m state --state NEW,ESTABLISHED -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A OUTPUT -o eth0 -p tcp --sport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 110&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -m state --state ESTABLISHED -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A INPUT -i eth0 -p tcp --dport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 995&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -m state --state NEW,ESTABLISHED -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A OUTPUT -o eth0 -p tcp --sport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 995&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -m state --state ESTABLISHED -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;23.&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 防止 DoS 攻击&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A INPUT -p tcp --dport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 80&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -m limit --limit 25/minute --limit-burst&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 100&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;24.&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 设置&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 422&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 端口转发到&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 22&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 端口&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -t nat -A PREROUTING -p tcp -d&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 192.168.102.37&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; --dport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 422&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -j DNAT --to 192.168.102.37:22&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A INPUT -i eth0 -p tcp --dport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 422&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -m state --state NEW,ESTABLISHED -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A OUTPUT -o eth0 -p tcp --sport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 422&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -m state --state ESTABLISHED -j ACCEPT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;25.&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 为丢弃的包做日志（Log）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -N LOGGING&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A INPUT -j LOGGING&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A LOGGING -m limit --limit 2/min -j LOG --log-prefix&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;IPTables Packet Dropped: &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; --log-level&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 7&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A LOGGING -j DROP&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;mangle-biao&quot;&gt;mangle 表&lt;/h2&gt;
&lt;h3 id=&quot;jie-shao&quot;&gt;介绍&lt;/h3&gt;
&lt;p&gt;    mangle 表是 iptables 中用于修改数据包的标记的表，它可以在数据包经过路由表之前，根据规则修改数据包的IP头部的一些字段，如 TTL 值、TOS 值等。这样可以影响数据包在网络中的转发方式和处理方式。mangle 表包含五个链：PREROUTING、POSTROUTING、INPUT、OUTPUT 和 FORWARD。mangle 表的优先级仅次于 raw 表，它会在 nat 表和 filter 表之前执行。&lt;/p&gt;
&lt;h3 id=&quot;shi-li&quot;&gt;示例&lt;/h3&gt;
&lt;p&gt;    mangle 表的一个常见应用场景是实现策略路由，即根据不同的数据包选择不同的路由表进行转发。例如，如果我们想要让不同端口的数据包走不同的网关出去，我们可以使用 mangle 表来给数据包打上标记，然后根据标记来指定路由表。具体的步骤如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;首先，我们需要定义两个路由表，比如 10 和 20，并且分别添加默认路由到不同的网关。假设我们有两个网卡 eth1 和 eth2，分别连接到网关 202.106.x.x 和 211.108.x.x，我们可以使用 ip 命令来添加路由表&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;ip&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; route add default via 202.106.x.x dev eth1 table&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;ip&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; route add default via 211.108.x.x dev eth2 table&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 20&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;然后，我们需要使用 mangle 表来给不同端口的数据包打上标记，比如我们想要让 80 和 443 端口的数据包走 eth1 网卡，而 20 和 21 端口的数据包走 eth2 网卡，我们可以使用 iptables 命令来设置 mangle 表&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -t mangle -A PREROUTING -i eth0 -p tcp --dport 80:443 -j MARK --set-mark&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -t mangle -A PREROUTING -i eth0 -p tcp --dport 20:21 -j MARK --set-mark&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;最后，我们需要使用 ip 命令来添加规则，让打上标记的数据包按照对应的路由表进行转发&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;ip&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; rule add from all fwmark&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; table&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;ip&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; rule add from all fwmark&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; table&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 20&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;raw-biao&quot;&gt;raw 表&lt;/h2&gt;
&lt;h3 id=&quot;jie-shao-1&quot;&gt;介绍&lt;/h3&gt;
&lt;p&gt;    raw 表是 iptables 中用于处理特殊类型的数据包的表，它可以决定是否对数据包进行连接跟踪（connection tracking），即是否记录数据包的状态信息。连接跟踪是一种消耗资源的操作，如果我们想要提高性能或者避免某些问题，我们可以使用 raw 表来让某些数据包跳过连接跟踪。raw 表只包含两个链：PREROUTING 和 OUTPUT。raw 表是 iptables 中优先级最高的表，它会在其他任何表之前执行。&lt;/p&gt;
&lt;h3 id=&quot;shi-li-1&quot;&gt;示例&lt;/h3&gt;
&lt;p&gt;    raw 表的一个常见应用场景是处理 ICMP 数据包，即互联网控制消息协议数据包。ICMP 数据包是一种用于网络诊断和管理的数据包，比如 ping 命令就是发送 ICMP echo 请求并接收 ICMP echo 应答来测试网络连通性。如果我们想要禁止某些主机 ping 我们或者被我们 ping，我们可以使用 raw 表来设置规则。具体的步骤如下&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;首先，我们需要确定要禁止 ping 的主机的 IP 地址，比如 192.168.1.100&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;然后，我们需要使用 raw 表来设置规则，让该主机发出或者发往的 ICMP 数据包跳过连接跟踪，并且直接丢弃。我们可以使用 iptables 命令来设置 raw 表&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -t raw -A PREROUTING -s&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 192.168.1.100&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -p icmp -j DROP&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -t raw -A OUTPUT -d&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 192.168.1.100&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -p icmp -j DROP&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;下面解释为什么使用 raw 表来禁止 ping 比使用 filter 表更好。&lt;/p&gt;
&lt;p&gt;ping 命令是一种用于测试网络连通性的工具，它发送 ICMP 数据包到目标主机，并等待回应。如果目标主机能够正常响应，那么就说明网络是通的。如果目标主机无法响应，那么就说明网络有问题或者被阻止了。&lt;/p&gt;
&lt;p&gt;如果我们想要禁止某些主机 ping 我们或者被我们 ping，我们可以使用 iptables 的防火墙功能来设置规则，让 ICMP 数据包被丢弃或者拒绝。iptables 有四个表来管理不同类型的规则，分别是 filter、nat、mangle 和 raw。其中 filter 表是默认的表，用于过滤数据包；nat 表是用于实现网络地址转换；mangle 表是用于修改数据包的标记；raw 表是用于处理特殊类型的数据包。&lt;/p&gt;
&lt;p&gt;一般来说，我们可以使用 filter 表来禁止 ping，只需要在 INPUT 链和 OUTPUT 链上添加规则，让 ICMP 数据包被 DROP 或者 REJECT 即可。例如，如果我们想要禁止 192.168.1.100 这个主机 ping 我们或者被我们 ping，我们可以使用以下命令：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A INPUT -s&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 192.168.1.100&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -p icmp -j DROP&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -A OUTPUT -d&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 192.168.1.100&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -p icmp -j DROP&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样做的效果是一样的，但是有一个缺点，就是 filter 表会对数据包进行连接跟踪（connection tracking），即记录数据包的状态信息。连接跟踪是一种消耗资源的操作，它会占用内存和 CPU 的资源，并且可能导致一些问题，如连接表溢出、连接超时等。如果我们不需要对 ICMP 数据包进行连接跟踪，那么使用 filter 表就是一种浪费。&lt;/p&gt;
&lt;p&gt;为了避免这种浪费，我们可以使用 raw 表来禁止 ping，只需要在 PREROUTING 链和 OUTPUT 链上添加规则，让 ICMP 数据包跳过连接跟踪，并且直接丢弃即可。例如，如果我们想要禁止 192.168.1.100 这个主机 ping 我们或者被我们 ping，我们可以使用以下命令：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -t raw -A PREROUTING -s&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 192.168.1.100&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -p icmp -j DROP&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -t raw -A OUTPUT -d&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 192.168.1.100&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -p icmp -j DROP&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样做的好处是可以节省资源和提高性能，因为 raw 表是 iptables 中优先级最高的表，它会在其他任何表之前执行，并且不会对数据包进行连接跟踪。这样就可以减少不必要的开销和风险。&lt;/p&gt;
&lt;p&gt;因此，使用 raw 表来禁止 ping 比使用 filter 表更好，除非我们有特殊的需求需要对 ICMP 数据包进行连接跟踪。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;can-kao-wen-dang&quot;&gt;参考文档：&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://cloud.tencent.com/developer/article/1683700&quot;&gt;iptables详解及常用规则&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://lixiangyun.gitbook.io/iptables_doc_zh_cn/&quot;&gt;iptables详解&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://www.flftuu.com/2021/07/20/iptables%E8%A7%84%E5%88%99%E8%AE%BE%E7%BD%AE%E7%94%A8%E6%B3%95/&quot;&gt;iptables规则设置用法&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://www.cnblogs.com/wanghongwei-dev/p/17635179.html&quot;&gt;iptables mangle表和raw表应用场景介绍&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Docker 网络模式</title>
        <published>2024-01-21T12:13:30+05:30</published>
        <updated>2024-01-21T12:13:30+05:30</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/docker-networking/"/>
        <id>https://scp.net.cn/blog/docker-networking/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/docker-networking/">&lt;p&gt;Docker 包括一个网络系统，用于管理容器、 Docker 主机和外部世界之间的通信。支持几种不同的网络类型，支持不同的使用场景。&lt;/p&gt;
&lt;h2 id=&quot;dockerwang-luo-lei-xing&quot;&gt;Docker网络类型&lt;/h2&gt;
&lt;p&gt;通过网络配置容器可以与其他容器和外部服务进行通信。&lt;/p&gt;
&lt;p&gt;容器必须连接到 Docker 网络才能接收任何网络连接。&lt;/p&gt;
&lt;p&gt;容器可用的通信路由取决于它的网络配置。&lt;/p&gt;
&lt;p&gt;Docker 带有[五个内置的网络驱动程序](&lt;a rel=&quot;external&quot; href=&quot;https://docs.docker.com/network&quot;&gt;Networking overview | Docker Docs&lt;/a&gt;)，它们实现了核心的网络功能:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;bridge&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;host&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;overlay&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;ipvlan&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;macvlan&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;bridge&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;[bridge网络](&lt;a rel=&quot;external&quot; href=&quot;https://docs.docker.com/network/drivers/bridge/&quot;&gt;Bridge network driver | Docker Docs&lt;/a&gt;)在主机和容器之间创建一个基于软件的桥接。&lt;/p&gt;
&lt;p&gt;连接到网络的容器可以相互通信，但是它们与网络外的容器是隔离的。&lt;/p&gt;
&lt;p&gt;网络中的每个容器都被分配了自己的 IP 地址。&lt;/p&gt;
&lt;p&gt;因为网络是桥接到主机的，所以容器也能够在局域网和因特网上进行通信。&lt;/p&gt;
&lt;p&gt;但是，它们不会以物理设备的形式出现在LAN上。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;host&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;使用[host网络](&lt;a rel=&quot;external&quot; href=&quot;https://docs.docker.com/network/host&quot;&gt;Host network driver | Docker Docs&lt;/a&gt;)的容器共享主机的网络堆栈，而没有任何隔离。&lt;/p&gt;
&lt;p&gt;它们没有分配自己的 IP 地址，端口绑定将直接发布到主机的网络接口。&lt;/p&gt;
&lt;p&gt;这意味着侦听端口80的容器进程将绑定到 &lt;code&gt;&amp;lt;host_ip&amp;gt;:80&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;overlay&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;[overlay网络](&lt;a rel=&quot;external&quot; href=&quot;https://docs.docker.com/network/overlay&quot;&gt;Overlay network driver | Docker Docs&lt;/a&gt;)是跨多个 Docker 主机的分布式网络。&lt;/p&gt;
&lt;p&gt;网络允许运行在任何主机上的所有容器彼此通信，而不需要 OS 级路由支持。&lt;/p&gt;
&lt;p&gt;overlay网络实现了[DockerSwarm](&lt;a rel=&quot;external&quot; href=&quot;https://docs.docker.com/engine/swarm&quot;&gt;Swarm mode overview | Docker Docs&lt;/a&gt;)集群的网络，但是运行两个独立的 Docker Engine 实例时，两个实例的容器必须直接相互通信，也可以使用它们。&lt;/p&gt;
&lt;p&gt;这允许您构建自己的类似于 Swarm 的环境。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ipvlan&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;[ipvlan](&lt;a rel=&quot;external&quot; href=&quot;https://docs.docker.com/network/ipvlan&quot;&gt;IPvlan network driver | Docker Docs&lt;/a&gt;) 是一个先进的驱动程序，提供了对分配给您的容器的 IPv4 和 IPv6地址的精确控制，以及第2层和第3层 VLAN 标记和路由。&lt;/p&gt;
&lt;p&gt;将容器化服务与现有物理网络集成时，此驱动程序非常有用。&lt;/p&gt;
&lt;p&gt;ipvlan 网络被分配了它们自己的网络接口，这比基于桥接的网络提供了性能优势。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;macvlan&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;[macvlan](&lt;a rel=&quot;external&quot; href=&quot;https://docs.docker.com/network/macvlan/&quot;&gt;Macvlan network driver | Docker Docs&lt;/a&gt;) 是另一个高级选项，它允许容器以物理设备的形式出现在网络上。&lt;/p&gt;
&lt;p&gt;它的工作原理是为网络中的每个容器分配一个唯一的 MAC 地址。&lt;/p&gt;
&lt;p&gt;这种网络类型要求将主机的一个物理接口专用于虚拟网络。&lt;/p&gt;
&lt;p&gt;更广泛的网络还必须进行恰当的配置，以支持Docker主机创建的大量MAC地址。&lt;/p&gt;
&lt;h3 id=&quot;zen-me-xuan-ze-shi-yong-na-chong-wang-luo-lei-xing&quot;&gt;怎么选择使用那种网络类型？&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;bridge网络&lt;/strong&gt;，对于大多数场景是最合适的选择。网络中的容器可以使用它们自己的IP地址和DNS名称彼此通信。他们也可以访问主机的网络，所以他们可以达到互联网和局域网。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;host网络&lt;/strong&gt;，将服务端口直接绑定到主机接口并且不关心网络隔离时，host网络是最佳选择。这种网络模式允许容器化应用程序的服务像直接在主机上运行的网络服务。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;overlay网络&lt;/strong&gt;，不同Docker主机上的容器需要彼此直接通信时，需要使用overlay网络。使用pverlay网络可以让你为高可用性建立自己的分布式环境。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;macvlan&lt;/strong&gt;，在容器必须作为主机网络上的物理设备出现的情况下，比如当容器运行监视网络流量的应用程序时，macvlan网络非常有用。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ipvlan网络&lt;/strong&gt;，当对容器IP地址、标签和路由有特定要求时，ipvlan网络是一种高级选择。&lt;/p&gt;
&lt;p&gt;Docker还支持[第三方网络插件](&lt;a rel=&quot;external&quot; href=&quot;https://docs.docker.com/engine/extend/plugins_services&quot;&gt;Plugins and Services | Docker Docs&lt;/a&gt;)，这些插件使用其他操作模式扩展网络系统。其中包括使用 &lt;a rel=&quot;external&quot; href=&quot;https://docs.openstack.org/neutron/latest/&quot;&gt;OpenStack Neutron&lt;/a&gt;实现网络的[Kuryr](&lt;a rel=&quot;external&quot; href=&quot;https://github.com/openstack/kuryr&quot;&gt;GitHub - openstack/kuryr: Bridge between container framework networking and storage models to OpenStack networking and storage abstractions. Mirror of code maintained at opendev.org.&lt;/a&gt;)，以及着重于服务发现、安全和容错的覆盖网络 &lt;a rel=&quot;external&quot; href=&quot;https://www.weave.works/docs/net/latest/introducing-weave&quot;&gt;Weave&lt;/a&gt;。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;NOTE：Docker 网络在容器级别始终是可选的:&lt;/p&gt;
&lt;p&gt;容器的网络设置为none将完全禁用其网络堆栈。&lt;/p&gt;
&lt;p&gt;容器将无法与其他容器通信、主机的服务、互联网。&lt;/p&gt;
&lt;p&gt;这有助于通过沙箱化不需要连接的应用程序来提高安全性。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;&quot;&gt;&lt;/h2&gt;
&lt;h2 id=&quot;dockerwang-luo-zen-me-gong-zuo-de&quot;&gt;Docker网络怎么工作的？&lt;/h2&gt;
&lt;p&gt;Docker使用主机的网络栈来实现容器的网络系统。&lt;/p&gt;
&lt;p&gt;它通过配置[iptables](&lt;a rel=&quot;external&quot; href=&quot;https://docs.docker.com/network/iptables&quot;&gt;Packet filtering and firewalls | Docker Docs&lt;/a&gt;)规则将流量路由到容器来工作。&lt;/p&gt;
&lt;p&gt;这也提供了Docker网络和主机之间的隔离。&lt;/p&gt;
&lt;p&gt;[iptables](&lt;a rel=&quot;external&quot; href=&quot;https://linux.die.net/man/8/iptables&quot;&gt;iptables(8) - Linux man page&lt;/a&gt;) 是标准的Linux包过滤工具。添加到&lt;code&gt;iptables&lt;/code&gt;规则定义流量通过主机网络栈时如何路由。Docker 网络添加过滤规则，将匹配的流量指向容器的应用程序。规则是自动配置的，所以不需要手动配置&lt;code&gt;iptables&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;Docker容器被分配它们自己的**[网络命名空间](&lt;a rel=&quot;external&quot; href=&quot;https://man7.org/linux/man-pages/man7/network_namespaces.7.html&quot;&gt;network_namespaces(7) - Linux manual page&lt;/a&gt;)**，这是一个 Linux 内核特性，它提供了独立的虚拟网络环境。&lt;/p&gt;
&lt;p&gt;容器还在主机上创建虚拟网络接口，允许它们在其名称空间之外使用主机网络进行通信。&lt;/p&gt;
&lt;p&gt;实现Docker网络的细节是非常复杂，需要了解许多操作系统内核。&lt;/p&gt;
&lt;p&gt;Docker将它们从最终用户抽象出来，提供 简单、易用、可靠 容器网络配置流程。&lt;/p&gt;
&lt;p&gt;在[Docker的文档中](&lt;a rel=&quot;external&quot; href=&quot;https://docs.docker.com/network/iptables&quot;&gt;Packet filtering and firewalls | Docker Docs&lt;/a&gt;)可以查看更多信息。&lt;/p&gt;
&lt;h3 id=&quot;dockerwang-luo-yu-vmwang-luo-de-qu-bie&quot;&gt;Docker网络与VM网络的区别&lt;/h3&gt;
&lt;p&gt;Docker的网络模型为容器提供了隔离的虚拟环境。这些网络配置满足日常使用，但与传统虚拟机创建的虚拟网络相比，有一些关键的区别。&lt;/p&gt;
&lt;p&gt;Docker 使用 命名空间 和 iptables 规则实现网络隔离，而VM通常为每台虚拟机运行单独的网络堆栈。&lt;/p&gt;
&lt;p&gt;术语上的差异也可能导致混淆: Docker所称的“桥接”网络类似于大多数VM解决方案中基于[NAT](&lt;a rel=&quot;external&quot; href=&quot;https://en.wikipedia.org/wiki/Network_address_translation&quot;&gt;Network address translation - Wikipedia&lt;/a&gt;)的网络。&lt;/p&gt;
&lt;p&gt;通常，VM可以支持比Docker本身允许的范围更广的网络拓扑。然而，Docker 包含了创建所需网络解决方案的所有工具，无论是通过使用 macvlan 分配物理网络上的容器地址，还是通过使用第三方插件实现缺失的网络模型。&lt;/p&gt;
&lt;h2 id=&quot;dockerwang-luo-shi-yan&quot;&gt;Docker网络实验&lt;/h2&gt;
&lt;h3 id=&quot;chuang-jian-wang-luo&quot;&gt;创建网络&lt;/h3&gt;
&lt;p&gt;创建Docker网络，请使用 &lt;code&gt;docker network create&lt;/code&gt; 命令，[文档](&lt;a rel=&quot;external&quot; href=&quot;https://docs.docker.com/engine/reference/commandline/network_create&quot;&gt;docker network create | Docker Docs&lt;/a&gt;)。&lt;/p&gt;
&lt;p&gt;可以通过设置-d 标志来指定要使用的驱动程序，例如host或bridge。&lt;/p&gt;
&lt;p&gt;如果省略该标志，则将创建bridge网络。&lt;/p&gt;
&lt;p&gt;执行以下命令：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; network create demo-network -d bridge&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; network ls&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;NETWORK&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; ID    NAME          VERSION     PLUGINS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;e2f4e124c378&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;  demo-network&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;  0.4.0&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;       bridge,portmap,firewall,tuning&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; network inspect demo-network&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;          &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;demo-network&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;          &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;e2f4e124c378ec1c52a632ca3f64a7cd92a589d10380ad4fdae5cdd842592370&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;          &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;driver&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;bridge&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;          &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;network_interface&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;cni-podman2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;          &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;created&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;2024-01-21T16:06:51.737081357+08:00&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;          &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;subnets&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;               {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;subnet&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;10.89.1.0/24&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                    &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;gateway&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;10.89.1.1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;               }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;          ]&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;          &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;ipv6_enabled&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;false&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;          &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;internal&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;false&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;          &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;dns_enabled&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;false&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;          &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;ipam_options&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;               &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;driver&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;host-local&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通过 &lt;code&gt;docker network ls&lt;/code&gt; 和 &lt;code&gt;docker network inspect demo-network&lt;/code&gt; 查看网络配置。新的网络配置目前没有用，因为没有容器被连接。&lt;/p&gt;
&lt;h3 id=&quot;lian-jie-rong-qi-he-wang-luo&quot;&gt;连接容器和网络&lt;/h3&gt;
&lt;p&gt;通过使用 &lt;code&gt;docker run&lt;/code&gt; 命令设置 &lt;code&gt;--network&lt;/code&gt; 标志，可以将新容器附加到网络。&lt;/p&gt;
&lt;p&gt;执行以下命令:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 创建桥接网络&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; network create --driver bridge alpine-net&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 创建 alpine1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; run -dit --name alpine1 --network alpine-net alpine ash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 创建 alpine2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; run -dit --name alpine2 --network alpine-net alpine ash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 创建 alpine3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; run -dit --name alpine3 alpine ash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;现在尝试使用这两个容器的名称在它们之间进行通信:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：如果通过 container name 不能被解析，可以手工添加hosts或者直接使用容器IP通信；&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; container attach alpine1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# in alpine1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; # ping -c 2 alpine2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; container attach alpine1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# in alpine1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; # ping -c 2 alpine3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;ping:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; bad address&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;alpine3&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这些容器还不在同一个网络中，因此它们不能直接相互通信。&lt;/p&gt;
&lt;p&gt;将&lt;code&gt;container2&lt;/code&gt;连接到网络:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; network connect alpine-net alpine3&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这些容器现在共享一个网络，使它们能够彼此通信:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; container attach alpine1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# in alpine1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; # ping -c 2 alpine3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;PING&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; container2&lt;/span&gt;&lt;span&gt; (172.22.0.3): 56 data bytes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;64&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; bytes from 172.22.0.3: seq=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; ttl=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;64&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; time=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;4.205&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; ms&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;shi-yong-hostmo-shi-wang-luo&quot;&gt;使用Host模式网络&lt;/h3&gt;
&lt;p&gt;桥接网络是常用的连接容器的方式。&lt;/p&gt;
&lt;p&gt;再探讨一下主机网络的功能，其中容器直接连接到主机的网络接口。&lt;/p&gt;
&lt;p&gt;执行下面命令：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; run -d --name nginx --network host nginx:latest&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;NGINX默认侦听端口80。因为容器使用的是主机网络，所以可以访问主机本地主机上的 NGINX服务器: 80，即使没有显式绑定端口:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; localhost:80&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;!&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;DOCTYPE&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; htm&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;html&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;head&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;Welcome to nginx&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;!&amp;lt;&lt;/span&gt;&lt;span&gt;/title&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;shi-yong-nonemo-shi-wang-luo&quot;&gt;使用None模式网络&lt;/h3&gt;
&lt;p&gt;使用none配置容器网络时，容器将没有可用的连接——无论是到其他容器，还是到其他网络。通过将容器网络配置为&lt;code&gt;none&lt;/code&gt;禁用网络:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; run -it --rm --network none busybox:latest&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; # ping baidu.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;ping:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; bad address&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;baidu.com&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样可以轻松地对未知服务进行沙箱处理。&lt;/p&gt;
&lt;h3 id=&quot;cong-wang-luo-pei-zhi-zhong-shan-chu-rong-qi&quot;&gt;从网络配置中删除容器&lt;/h3&gt;
&lt;p&gt;Docker允许在不重新启动容器的情况下自由地管理网络连接。&lt;/p&gt;
&lt;p&gt;在上一节中，了解了如何在容器创建后连接容器;&lt;/p&gt;
&lt;p&gt;还可以从不再需要的网络中删除容器:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; network disconnect demo-network container2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这些变更不需要重启会立即生效；&lt;/p&gt;
&lt;h3 id=&quot;guan-li-rong-qi-de-wang-luo-pei-zhi&quot;&gt;管理容器的网络配置&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;列出网络配置&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; network ls&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;删除网络配置&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;docker network rm demo-network&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;删除没有使用的网络配置&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; network prune&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;shi-yong-docker-composepei-zhi-rong-qi-wang-luo&quot;&gt;使用Docker Compose配置容器网络&lt;/h3&gt;
&lt;p&gt;[docker compose](&lt;a rel=&quot;external&quot; href=&quot;https://docs.docker.com/compose/&quot;&gt;Docker Compose overview | Docker Docs&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;可以使用带有 Docker Compose 服务的网络。&lt;/p&gt;
&lt;p&gt;使用 Docker Compose 时，通常可以避免手动网络配置，因为Docker Compose中配置的服务会自动添加到共享网桥网络中:&lt;/p&gt;
&lt;p&gt;创建 &lt;code&gt;docker-compose.yaml&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;version&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;: &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;services&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;  app&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    image&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; php:7.2-apache&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;  mysql&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    image&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; mysql:8.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    environment&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;      MYSQL_ROOT_PASSWORD=changeme&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;使用 docker compose 部署服务：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;docker compose up -d&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如下面的输出所示，Docker Compose 已经为相关服务创建了一个包含两个容器的网络:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;docker network ls&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;NETWORK ID     NAME                                        DRIVER    SCOPE&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;44edcc537a6f   bridge                                      bridge    local&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4d60b27f787a   host                                        host      local&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;358610a7ea97   introduction-to-docker-networking_default   bridge    local&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;288376a0a4f8   none                                        null      local&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;应用程序容器可以直接与关联的mysql数据库容器通信:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;docker compose exec -it app bash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;root@d7c97936ad48:/var/www/html# apt update &amp;amp;&amp;amp; apt install iputils-ping -y&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;root@d7c97936ad48:/var/www/html# ping mysql&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PING mysql (172.23.0.3) 56(84) bytes of data.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;64 bytes from introduction-to-docker-networking-mysql-1.introduction-to-docker-networking_default (172.23.0.3): icmp_seq=1 ttl=64 time=0.493 ms&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;其他网络配置&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;可以在 Docker Compose 文件中定义其他网络。&lt;/p&gt;
&lt;p&gt;在最外层添加 &lt;code&gt;networks&lt;/code&gt; 字段，然后通过&lt;code&gt;networks&lt;/code&gt;中配置网络来连接服务:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;version: &amp;quot;3&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;services:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  app:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    image: php:7.2-apache&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    networks:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      - db&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  helper:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    image: custom-image:latest&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  mysql:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    image: mysql:8.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    environment:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      MYSQL_ROOT_PASSWORD=changeme&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    networks:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      - db&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;networks:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  db:&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个示例重写默认网络配置。现在，只有app服务可以与mysql通信。helper服务无法到达数据库，因为这两个服务不共享网络。&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://spacelift.io/blog/docker-compose&quot;&gt;Docker Compose - What is It, Example &amp;amp; Tutorial&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;zong-jie&quot;&gt;总结&lt;/h2&gt;
&lt;p&gt;Docker的网络为容器与其他容器、宿主机之间的通信提供了灵活的选择。&lt;/p&gt;
&lt;p&gt;网络中的容器能够通过名称或 IP 地址相互联系。&lt;/p&gt;
&lt;p&gt;网络是由一组可插拔的驱动程序实现的，这些驱动程序可以适用与常见的使用场景。&lt;/p&gt;
&lt;p&gt;网络依赖于主机的网络栈，但是使用命名空间进行隔离。&lt;/p&gt;
&lt;p&gt;这种分离比虚拟机使用的虚拟网络模型要弱，尽管在将容器连接到 macvlan 网络时，它们仍然可以作为物理网络设备出现。&lt;/p&gt;
&lt;h3 id=&quot;can-kao-wen-dang&quot;&gt;参考文档&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://docs.docker.com/network/network-tutorial-standalone/&quot;&gt;Networking with standalone containers | Docker Docs&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;https://github.com/containers/podman/blob/main/docs/tutorials/basic_networking.md&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;https://docs.podman.io/en/latest/markdown/podman-network-create.1.html&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://docs.docker.com/network/&quot;&gt;Networking overview | Docker Docs&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;https://medium.com/@prajwal.chin/understanding-docker-dns-2ed4b070a0&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http://docker.baoshu.red/network/mode.html&quot;&gt;docker网络模式 · Docker – 从入门到实战&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>从CSS盒模型理解能力圈</title>
        <published>2024-01-15T12:13:32+05:30</published>
        <updated>2024-01-15T12:13:32+05:30</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/box/"/>
        <id>https://scp.net.cn/blog/box/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/box/">&lt;h3 id=&quot;css-he-zi-mo-xing-su-lan&quot;&gt;CSS 盒子模型速览&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://scp-net-cn.oss-cn-beijing.aliyuncs.com/blog-images/box-model.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;content：核心内容与能力本身&lt;/li&gt;
&lt;li&gt;padding：为内容预留的缓冲与弹性空间&lt;/li&gt;
&lt;li&gt;border：清晰可见的边界与原则&lt;/li&gt;
&lt;li&gt;margin：外部世界与他人的期望空间&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;css&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;box&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  box-sizing&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; border-box;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  border&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px solid&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; #&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;334155&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  padding&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 12&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;px;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  margin&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;neng-li-quan-yin-yu&quot;&gt;能力圈隐喻&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;少用 margin：减少外部定义你边界的机会，避免无效应酬与噪音&lt;/li&gt;
&lt;li&gt;确定 border：明确原则与范围，让“能做/不能做”的界限清晰可见&lt;/li&gt;
&lt;li&gt;留出 padding：为学习、恢复、沟通、质量保障留出缓冲&lt;/li&gt;
&lt;li&gt;充实 content：持续打磨可迁移的核心能力与作品&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;能力圈的大小不是关键，重要的是要清楚它的边界。&lt;/p&gt;
&lt;p&gt;不要用 Margin！不要用 Margin！不要用 Margin！&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;xing-dong-jian-yi&quot;&gt;行动建议&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;每季度复盘一次边界：新增/移除/加强哪些能力与范围&lt;/li&gt;
&lt;li&gt;建立“拒绝事项”清单：不做、少做、外包的项目与场景&lt;/li&gt;
&lt;li&gt;预留固定 padding：把学习与恢复变为不可动摇的日程&lt;/li&gt;
&lt;li&gt;内容导向：输出可被复用与迁移的作品（笔记、工具、清单）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;chang-jian-wu-qu&quot;&gt;常见误区&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;用“忙碌的 margin”掩盖“贫瘠的 content”&lt;/li&gt;
&lt;li&gt;边界不清导致频繁越界承诺，信用与质量双双受损&lt;/li&gt;
&lt;li&gt;没有缓冲的排期，尾延迟与返工成为常态&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;jie-yu&quot;&gt;结语&lt;/h3&gt;
&lt;p&gt;以盒模型思维构建能力圈：边界清晰、缓冲充足、核心厚实、外界简化。少用 margin，不迎合噪音；多充实 content，积累真正的复利。&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Linux TC 命令材料收集和整理</title>
        <published>2024-01-15T12:13:32+05:30</published>
        <updated>2024-01-15T12:13:32+05:30</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/linux-tc-tour/"/>
        <id>https://scp.net.cn/blog/linux-tc-tour/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/linux-tc-tour/">&lt;p&gt;&lt;img src=&quot;https://scp-net-cn.oss-cn-beijing.aliyuncs.com/blog-images/tc.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;jie-shao&quot;&gt;介绍&lt;/h2&gt;
&lt;p&gt;    tc 用于在 Linux 内核中配置流量控制。tc 是 Linux 自带的模块，一般情况下不需要另行安装，可以用 man tc 查看 tc 相关命令细节，要求内核 2.4.18 以上。&lt;/p&gt;
&lt;p&gt;    流量控制(tc)是一个非常有用的 Linux 实用程序，它使您能够配置内核数据包调度程序。如果您正在寻找扰乱内核调度器的原因，或者仅仅是测试数据包丢失对应用程序的影响，以下就是其中的一些原因。首先，使用不同的选项并熟悉 Linux 的所有特性是很有趣的。此外，您可以利用 Linux 的有用工具来模拟 UDP 或 TCP 应用程序的数据包延迟和丢失，或者限制特定服务的带宽使用来模拟 Internet 连接(DSL、 Cable、 T1等)。&lt;/p&gt;
&lt;h2 id=&quot;yuan-li&quot;&gt;原理&lt;/h2&gt;
&lt;p&gt;    Linux操作系统中的流量控制器TC（Traffic Control）用于Linux内核的流量控制，主要是通过在输出端口处建立一个队列来实现流量控制。
接收包从输入接口进来后，经过流量限制丢弃不符合规定的数据包，由输入多路分配器进行判断选择：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果接收包的目的主机是本主机，那么将该包送给上层处理，否则需要进行转发，将接收包交到转发块（Forwarding Block）处理。&lt;/li&gt;
&lt;li&gt;转发块同时也接收本主机上层(TCP、UDP等)产生的包，通过查看路由表，决定所处理包的下一跳。&lt;/li&gt;
&lt;li&gt;然后，对包进行排列以便将它们送到输出接口。&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;一般只能限制网卡发送的数据包，不能限制网卡接收的数据包，所以可以通过改变发送次序来控制传输速率。&lt;/p&gt;
&lt;p&gt;Linux流量控制主要是在输出接口排列时进行处理和实现的。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;    Linux 中的 QoS 分为入口 (Ingress) 部分和出口 (Egress) 部分，入口部分主要用于进行入口流量限速 (Policing)，出口部分主要用于队列调度 (Queuing Scheduling)。大多数排队规则 (qdisc) 都是用于输出方向的，输入方向只有一个排队规则，即 Ingress qdisc。&lt;/p&gt;
&lt;p&gt;Ingress qdisc 本身的功能很有限，输入方向只有一个排队规则，即 Ingress qdisc（因为没有缓存只能实现流量的 Drop）但可用于重定向 Incoming packets。通过 Ingress qdisc 把输入方向的数据包重定向到虚拟设备ifb，而ifb的输出方向可以配置多种 qdisc，就可以达到对输入方向的流量做队列调度的目的。&lt;/p&gt;
&lt;h3 id=&quot;ingress&quot;&gt;Ingress&lt;/h3&gt;
&lt;p&gt;Ingress 限速只能对整个网卡入流量限速，无队列之分。&lt;/p&gt;
&lt;p&gt;Ingress 流量的限速示例：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; qdisc add dev eth0 ingress&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; filter add dev eth0 parent ffff: protocol ip prio&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; u32 match ipsrc 0.0.0.0/0 police rate 2048kbps burst 1m drop flowid :1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;egress&quot;&gt;Egress&lt;/h3&gt;
&lt;p&gt;TC模块利用队列规定建立处理数据包的队列，并定义队列中的数据包被发送的方式，实现对流量的控制。&lt;/p&gt;
&lt;p&gt;TC模块实现流量控制功能使用的队列规定分为两类，一类是无类队列规定，另一类是分类队列规定。无类队列规定相对简单，而分类队列规定则引出了分类和过滤器等概念，使其流量控制功能增强。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;无类队列：&lt;/strong&gt; 规定是对进入网络设备（网卡）的数据流不加区分统一对待的队列规定。使用无类队列规定形成的队列能够接收数据包以及重新编排、延迟或丢弃数据包。这类队列规定形成的队列可以对整个网络设备（网卡）的流量进行整形，但不能细分各种情况。常用的无类队列规定主要有 pfifo_fast（先进先出）、TBF（令牌桶过滤器）、SFQ（随机公平队列）、ID（前向随机丢包）等等。这类队列规定使用的流量整形手段主要是排序、限速和丢包。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;分类队列：&lt;/strong&gt; 规定是对进入网络设备的数据包根据不同的需求以分类的方式区分对待的队列规定。数据包进入一个分类的队列后，它就需要被送到某一个类中，也就是说需要对数据包做分类处理。对数据包进行分类的工具是过滤器，过滤器会返回一个决定，队列规定就根据这个决定把数据包送入相应的类进行排队。每个子类都可以再次使用它们的过滤器进行进一步的分类。直到不需要进一步分类时，数据包才进入该类包含的队列排队。除了能够包含其他队列规定之外，绝大多数分类的队列规定还能够对流量进行整形。这对于需要同时进行调度（如使用SFQ）和流量控制的场合非常有用。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://scp-net-cn.oss-cn-beijing.aliyuncs.com/blog-images/QP43c.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;ji-ben-gai-nian&quot;&gt;基本概念&lt;/h2&gt;
&lt;h3 id=&quot;qdisc-pai-dui-gui-ze&quot;&gt;QDISC（排队规则）&lt;/h3&gt;
&lt;p&gt;    全称是queueing discipline，我们姑且称其为排队规则吧。它是协议栈和网络接口之间的一个缓冲层。你可以在qdisc上对数据包做一些你想做的操作，比如分类、整形、调度等。&lt;/p&gt;
&lt;p&gt;    qdisc分为无类（classless）qdisc和有类（classful）qdisc。无类qdisc不再内部细分类，有类qdisc可进一步包含多个分类，每个class上可以进一步包含子qdisc，子qdisc也可以是有类qdisc，这样就形成了树状的分层结构。&lt;/p&gt;
&lt;p&gt;    最简单的QDisc是pfifo它不对进入的数据包做任何的处理，数据包采用先入先出的方式通过队列。不过，它会保存网络接口一时无法处理的数据包。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CLASSLESS QDISC(不可分类QDISC)&lt;/strong&gt;**&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;[p|b]fifo: 使用最简单的qdisc，纯粹的先进先出。只有一个参数：limit，用来设置队列的长度,pfifo是以数据包的个数为单位；bfifo是以字节数为单位。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;pfifo_fast: 在编译内核时，如果打开了高级路由器(Advanced Router)编译选项，pfifo_fast就是系统的标准QDISC。它的队列包括三个波段(band)。在每个波段里面，使用先进先出规则。而三个波段(band)的优先级也不相同，band 0的优先级最高，band 2的最低。如果band0里面有数据包，系统就不会处理band 1里面的数据包，band 1和band 2之间也是一样。数据包是按照服务类型(Type of Service,TOS)被分配多三个波段(band)里面的。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://scp-net-cn.oss-cn-beijing.aliyuncs.com/blog-images/1__d566EGgUEX52WNdIpSf__AQ.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;red: Random Early Detection(随机早期探测)的简写。如果使用这种QDISC，当带宽的占用接近于规定的带宽时，系统会随机地丢弃一些数据包。它非常适合高带宽应用。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;sfq: Stochastic Fairness Queueing的简写。它按照会话(session–对应于每个TCP连接或者UDP流)为流量进行排序，然后循环发送每个会话的数据包。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;tbf: Token Bucket Filter的简写，适合于把流速降低到某个值。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;不可分类QDISC配置：&lt;/strong&gt;&lt;/em&gt; 如果没有可分类QDISC，不可分类QDISC只能附属于设备的根。它们的用法如下：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 添加一个不可分类的 qdisc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; qdisc add dev DEV root QDISC QDISC-PARAMETERS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 删除一个不可分类 qdisc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; qdisc del dev DEV root&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;一个网络接口上如果没有设置QDISC，pfifo_fast就作为缺省的QDISC。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;CLASSFUL QDISC(分类QDISC)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;CBQ： CBQ是Class Based Queueing(基于类别排队)的缩写。它实现了一个丰富的连接共享类别结构，既有限制(shaping)带宽的能力，也具有带宽优先级管理的能力。带宽限制是通过计算连接的空闲时间完成的。空闲时间的计算标准是数据包离队事件的频率和下层连接(数据链路层)的带宽。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;HTB： HTB是Hierarchy Token Bucket的缩写。通过在实践基础上的改进，它实现了一个丰富的连接共享类别体系。使用HTB可以很容易地保证每个类别的带宽，它也允许特定的类可以突破带宽上限，占用别的类的带宽。HTB可以通过TBF(Token Bucket Filter)实现带宽限制，也能够划分类别的优先级。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://scp-net-cn.oss-cn-beijing.aliyuncs.com/blog-images/1__yxleicti2yy9F2K0UrpmHA.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;PRIO： PRIO QDISC不能限制带宽，因为属于不同类别的数据包是顺序离队的。使用PRIO QDISC可以很容易对流量进行优先级管理，只有属于高优先级类别的数据包全部发送完毕，才会发送属于低优先级类别的数据包。为了方便管理，需要使用iptables或者ipchains处理数据包的服务类型(Type Of Service,ToS)。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;class-lei-bie&quot;&gt;CLASS（类别）&lt;/h3&gt;
&lt;p&gt;    有类qdisc可以有多个子类（class），有些qdisc预定义了子类（如prio），有些则需要用户添加类。一个类上又可以附加其他类。最末端没有子类的类称为叶子类，它上面附加了一个qdisc。当创建一个class的时候，默认会附加一个fifo qdisc，它只是一个简单的队列，不对数据包进行任何的操作。当在这个类上增加子类的时候，这个默认的qdisc被移除。你可以将这个默认的fifo qdisc替换成其他任意你想用的qdisc。&lt;/p&gt;
&lt;p&gt;eg:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  .-------------------------------------------------------.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  |                                                       |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  |  HTB                                                  |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  |                                                       |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  | .----------------------------------------------------.|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  | |                                                    ||&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  | |  Class 1:1                                         ||&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  | |                                                    ||&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  | | .---------------..---------------..---------------.||&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  | | |               ||               ||               |||&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  | | |  Class 1:10   ||  Class 1:20   ||  Class 1:30   |||&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  | | |               ||               ||               |||&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  | | | .------------.|| .------------.|| .------------.|||&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  | | | |            ||| |            ||| |            ||||&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  | | | |  fq_codel  ||| |  fq_codel  ||| |  fq_codel  ||||&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  | | | |            ||| |            ||| |            ||||&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  | | | &amp;#39;------------&amp;#39;|| &amp;#39;------------&amp;#39;|| &amp;#39;------------&amp;#39;|||&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  | | &amp;#39;---------------&amp;#39;&amp;#39;---------------&amp;#39;&amp;#39;---------------&amp;#39;||&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  | &amp;#39;----------------------------------------------------&amp;#39;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &amp;#39;-------------------------------------------------------&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;以上3个是TC中最基本的3个概念，任何复杂的流量控制都是通过这个三元组递归实现的。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;ceng-ji-jie-gou&quot;&gt;层级结构&lt;/h3&gt;
&lt;p&gt;    每个接口有一个egress ‘root qdisc’，默认是pfifo_fast。每个qdisc和class都分配一个句柄handle，句柄用于在后续的配置语句中进行引用。除了egress qdisc，一个接口也可以有一个ingress qdisc，负责管制入站的流量。但是ingress qdisc相比classful qdisc其可能性是非常有限。（所以才有所谓的控发不控收，对入站流量进行控制通常需要借助ifb[6]或者imq）。&lt;/p&gt;
&lt;p&gt;    这些qdisc的handles有两个部分组成，一个major数和一个minor数：&lt;code&gt;&amp;lt;major&amp;gt;:&amp;lt;minor&amp;gt;&lt;/code&gt;。习惯上将root qdisc命名为&lt;code&gt;1:&lt;/code&gt;，等价于&lt;code&gt;1:0&lt;/code&gt;。一个qdisc的minor数总是0。&lt;/p&gt;
&lt;p&gt;    子类需要跟它们的parent有相同的major数。major数在一个egress或ingress内必须是唯一的，minor数在一个qdisc和它的class中必须是唯一的。&lt;/p&gt;
&lt;p&gt;一个典型的层级结构如下：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          1:   root qdisc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;           |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          1:1    child class&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        /  |  \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       /   |   \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      /    |    \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      /    |    \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   1:10  1:11  1:12   child classes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    |      |     | &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    |     11:    |    leaf class&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    |            | &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    10:         12:   qdisc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   /   \       /   \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;10:1  10:2   12:1  12:2   leaf classes&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;内核只跟root qdisc进行通信，每当包需要入队或者出队的时候，都需要从root节点开始，最终到达叶子节点，从而决定入队到哪里，或者从哪里出队。&lt;/p&gt;
&lt;p&gt;比如当一个包入队时，它可能会经过如下路径：&lt;code&gt;1: -&amp;gt; 1:1 -&amp;gt; 1:12 -&amp;gt; 12: -&amp;gt; 12:2&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;当然也可能直接走如下路径：&lt;code&gt;1: -&amp;gt; 12:2&lt;/code&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这种情况，就是root qdisc上的过滤器决定把包直接送到&lt;code&gt;12:2&lt;/code&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;注意：入队和出队时虽然节点的拓扑图是一样的，但是每个节点表示的含义却有所不同*(&lt;a rel=&quot;external&quot; href=&quot;https://blog.csdn.net/dog250/article/details/40681809&quot;&gt;数据包的分类和调度-Linux TC的另一种解释_可编程数据包调度&lt;/a&gt;)*。入队时是根据过滤器和包的特征决定走哪条路径，而出队时则取决于qdisc本身的调度算法，比如FIFO、优先级队列、SFQ的顺序调度等。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;filter-guo-lu-qi&quot;&gt;FILTER（过滤器）&lt;/h3&gt;
&lt;p&gt;    过滤器，用于有类qdisc中，决定将包入队到哪个类中。每当一个包到达有子类的类时，就需要进行分类。其中一种分类的方法就是使用过滤器（另外两个是ToS和skb-&amp;gt;priority）。所有附加到类上的过滤器会被依次调用，直到其中一个返回裁决。一个filter包含了一些条件，当一个包到达该节点时，会根据包的特征判断是否匹配。&lt;/p&gt;
&lt;p&gt;    前面已经提到了过滤器用于将包分类到子类，那么具体是如何对包进行分类的呢？tc支持很多类型的分类器，它们根据数据包相关的不同信息来作出决策。其中最常用的就是&lt;strong&gt;u32分类器&lt;/strong&gt;，它根据数据包中的字段做出决策（例如源IP地址等）。还有比如&lt;strong&gt;fw分类器&lt;/strong&gt;，根据防火墙如何标记数据包来做出决策，你可以使用iptables标记目标数据包，然后通过fw分类器进行过滤。另外还有诸如&lt;strong&gt;route分类器&lt;/strong&gt;、&lt;strong&gt;cgroup分类器&lt;/strong&gt;、&lt;strong&gt;bpf分类器&lt;/strong&gt;等，篇幅原因不再赘述。下面仅介绍最常见的u32分类器。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;公共参数&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;分类器一般接收以下几个公共的参数：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;protocol：分类器接受的协议，通常你只接受IP流量。必须。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;parent：分类器附加到哪个handle上。这个handle必须是一个已经存在的类。必须。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;prio|perf：分类器的优先级。&lt;strong&gt;数字越小&lt;/strong&gt;的越先进行匹配尝试。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;handle：这个handle对于不同的过滤器表示不同的含义。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;u32分离器&lt;/strong&gt; &lt;a rel=&quot;external&quot; href=&quot;https://man7.org/linux/man-pages/man8/tc-u32.8.html&quot;&gt;tc-u32(8) - Linux manual page&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;    u32过滤器最简单的格式是设置一组选择器对包进行匹配，匹配的包分到特定的子类中，或者执行一个action。u32分类器提供了多种不同的选择器，可以大致分成特殊选择器和通用选择器两类。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;特殊选择器&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;    常用的有ip选择器和tcp选择器。特殊选择器简化了一些常用字段的设置，可以匹配包头中的各种字段，比如：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 匹配ip源地址在192.168.8.0/24子网的包&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; filter add dev eth0 protocol ip parent 1:0 prio&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; u32&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;    match ip src 192.168.8.0/24 flowid 1:4&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 匹配TCP协议（0x6）、且目的端口为53的包。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; filter add dev eth0 protocol ip parent 1:0 prio&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; u32&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;        match ip protocol&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0x6 0xff&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;        match tcp dport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 53 0xffff&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;        flowid 1:2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;通用选择器&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;    特殊选择器总是可以改写成对应的通用选择器，通用选择器可以匹配 IP（或上层）头中的几乎任何位，不过相比特殊选择器较难编写和阅读。其语法如下：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;match&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; u32&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; u16&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; u8&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; ] PATTERN MASK at&lt;/span&gt;&lt;span&gt; [OFFSET &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; nexthdr+OFFSET]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中u32|u16|u8指定pattern的长度，分别为4个字节、2个字节、1个字节。PATTERN表示匹配的包的pattern，MASK告诉过滤器匹配哪些位，at表示从包的指定偏移处开始匹配。&lt;/p&gt;
&lt;p&gt;来看一个例子：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; filter add dev eth0 protocol ip parent 1:0 pref&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; u32&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;    match u32&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 00100000&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 00ff0000 at&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; flowid 1:10&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;选择器会匹配IP头第二个字节为0x10的包，&lt;code&gt;at 0&lt;/code&gt;表示从头开始匹配，mask为&lt;code&gt;00ff0000&lt;/code&gt;所以只匹配第二个字节，pattern为&lt;code&gt;00100000&lt;/code&gt;即第二个字节为0x10。&lt;/p&gt;
&lt;p&gt;再来看另一个例子：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; filter add dev eth0 protocol ip parent 1:0 pref&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; u32&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;    match u32&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 00000016&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; 0000ffff at nexthdr+0 flowid 1:10&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;nexthdr&lt;/code&gt;选项表示封装在IP包里的下一个头，即上层协议的头。&lt;code&gt;at nexthdr+0&lt;/code&gt;表示从下一个头第一个字节开始匹配。因为mask为&lt;code&gt;0000ffff&lt;/code&gt;，所以匹配发生在头的第三和第四个字节。在TCP和UDP协议中这两个字节是包的目的端口。数字是由大段格式给出的，所以pattern &lt;code&gt;00000016&lt;/code&gt;转换成十进制是22。即该选择器会匹配目的端口为22的包。&lt;/p&gt;
&lt;h2 id=&quot;shi-li&quot;&gt;示例&lt;/h2&gt;
&lt;h3 id=&quot;shi-li-yi&quot;&gt;示例一&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; tc qdisc add dev eth0 root handle 1: prio bands&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; tc qdisc add dev eth0 parent 1:4 handle 40: netem loss 10% delay 40ms&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; tc filter add dev eth0 protocol ip parent 1:0 prio&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; u32 match ip dst&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 192.168.190.7&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; match ip dport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 36000 0xffff&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; flowid 1:4&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;我们一行行来看，第一行在设备eth0上添加了一个root qdisc，句柄为1:，qdisc类型为prio，bands数为4。&lt;/p&gt;
&lt;p&gt;prio是一个有类的qdisc。它的作用跟默认的qdisc pfifo_fast类似。pfifo_fast有三个所谓的band，不同band的流量具有不同的优先级。每个band内，则应用FIFO规则。&lt;/p&gt;
&lt;p&gt;prio qdisc，默认会创建3个子类，包含纯FIFO qdisc，默认根据ToS位进行分类。你可以使用过滤器来对流量进行分类，你也可以在子类上附加其他qdisc替换默认的FIFO。&lt;/p&gt;
&lt;p&gt;接下来看第二个命令，&lt;code&gt;parent 1:4&lt;/code&gt;表示在子类1:4上，&lt;code&gt;handle 40:&lt;/code&gt;表示句柄为40:，&lt;code&gt;netem&lt;/code&gt;表示添加一个netem qdisc，&lt;code&gt;loss 10% delay 40ms&lt;/code&gt;则是netem的参数，表示丢包10%、延迟40ms。&lt;a rel=&quot;external&quot; href=&quot;https://wiki.linuxfoundation.org/networking/netem&quot;&gt;networking:netem&lt;/a&gt;是一个用于提供网络仿真功能的无类qdisc，可以模拟延迟、丢包、包重复、包失序等各种情况。&lt;/p&gt;
&lt;p&gt;第三个命令则是添加了一个过滤器，&lt;code&gt;parent 1:0&lt;/code&gt;表示在根节点上添加该过滤器，&lt;code&gt;prio 4&lt;/code&gt;是过滤器的优先级，如果有很多过滤器会根据优先级的值按顺序进行尝试。&lt;code&gt;u32&lt;/code&gt;表示使用u32分类器。&lt;code&gt;match ip dst 192.168.190.7&lt;/code&gt;表示匹配ip地址为192.168.190.7的包，&lt;code&gt;match ip dport 36000 0xffff&lt;/code&gt;表示匹配目的端口为36000的包，多个选择器之间是“与”的关系，&lt;code&gt;flowid 1:4&lt;/code&gt;表示将匹配的包分类到&lt;code&gt;1:4&lt;/code&gt;子类中。&lt;/p&gt;
&lt;p&gt;所以最终的效果是，发往192.168.190.7且目的端口为36000的包，会分类到1:4子类，添加40ms的延迟，且有10%的丢包率。其他包则还是默认的行为，即根据ToS字段分类到1:1、1:2或1:3子类中，然后根据优先级依次发送。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;画出该例子的分层结构图，大致如下：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          1:     root qdisc (prio)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;         / | \ \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       /   |  \  \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       /   |   \   \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     1:1  1:2  1:3  1:4      classes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      |    |    |    |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                     40:     qdiscs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   pfifo pfifo pfifo netem&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;band  0    1    2    3&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;shi-li-er&quot;&gt;示例二&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# tc 查看包 drop 情况&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -s -d qd&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# tc 列出目前所有的 Network Interface 的设定&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; qdisc ls&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# tc 预设将所有的流量导向 band 2，为了避免其他封包被影响，先将所有的封包都走band 2(指令计数从0开始)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# handle 1: 指的是绑定到qdisc 的root&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# bands 10: 可以创建10组band&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; qdisc add dev enp0s5 root handle 1: prio bands&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; priomap&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# tc 设定封包延迟&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 1. netem 是 tc 的工具之一，可用来增加延迟、掉封包、重复封包等模拟工具，netem delay 100ms 10ms表示每个封包延迟100ms(+- 10ms)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 2. parent 1:1 表示在class id 1 底下，建立一个id 为1的子节点，因为当前的队列没有多层次的class设计，所以1:1 就对应到band 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 3. handle 10: 表示创建一个class id 为10 的节点&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; qdisc add dev enp0s5 parent 1:1 handle 10: netem delay 100ms 10ms&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 删除旧的qdisc 设定&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; qdisc del dev enp0s5 root&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 建立 htb&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; qdisc add dev enp0s5 root handle 1:0 htb&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 加入bandwidth 限制，限速 100 kbps，&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 如果单纯想要限制上传速度，也可以用 tc-tbf，但 htb 优点是用层状架构限速，leaf 会受到 root 的限制，例如分配一条带宽 10 Mbps，可以在之下分配 4 Mbps 给某网域 6 Mbps 给其他网域等。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; class add dev enp0s5 parent 1: classid 1:1 htb rate 100kbps ceil 100kbps&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;NOTE: enp0s5 为网卡名，真实实验需要替换为自己的网卡名；&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;shi-li-san&quot;&gt;示例三&lt;/h3&gt;
&lt;h3 id=&quot;network-delay&quot;&gt;Network Delay&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; qdisc add dev eth0 root netem delay 200ms&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;qdisc: modify the scheduler (aka queuing discipline)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;add: add a new rule&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;dev eth0: rules will be applied on device eth0&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;root: modify the outbound traffic scheduler (aka known as the egress qdisc)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;netem: use the &lt;a rel=&quot;external&quot; href=&quot;https://wiki.linuxfoundation.org/networking/netem&quot;&gt;network emulator&lt;/a&gt; to emulate a WAN property&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;delay: the network property that is modified&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;200ms: introduce delay of 200 ms&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# delete all rules&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; qdisc del dev eth0 root&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# displays the configuration of the network interface eth0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; qdisc show  dev eth0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Note that if you have an existing rule you can change it by using “&lt;code&gt;tc qdisc change&lt;/code&gt;” and if you don’t have any rules you add rules with “&lt;code&gt;tc qdisc add&lt;/code&gt;”. Here are some other examples:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# Delay of 100ms and random +/- 10ms uniform distribution:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; qdisc change dev eth0 root netem delay 100ms 10ms&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# Delay of 100ms and random 10ms uniform variation with correlation value 25% (since network delays are not completely random):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; qdisc change dev eth0 root netem delay 100ms 10ms 25%&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# Delay of 100ms and random +/- 10ms normal distribution (other distribution options are pareto, and paretonormal):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; qdisc add dev eth0 root netem delay 100ms 20ms distribution normal&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;packet-loss-and-packet-corruption&quot;&gt;Packet Loss and Packet Corruption&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# packet loss of 10%&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; qdisc add dev eth0 root netem loss 10%&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# corrupts 5% of the packets&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; qdisc change dev eth0 root netem corrupt 5%&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# duplicates 1% of the sent packets&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; qdisc change dev eth0 root netem duplicate 1%&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;bandwidth-limit&quot;&gt;Bandwidth limit&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# limit the egress bandwidth&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; qdisc add dev eth0 root tbf rate 1mbit burst 32kbit latency 400ms&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;tbf: &lt;em&gt;use&lt;/em&gt; the &lt;em&gt;token buffer filter to manipulate traffic rates&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;rate: &lt;em&gt;sustained maximum rate&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;burst: &lt;em&gt;maximum allowed burst&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;latency: &lt;em&gt;packets with higher latency get dropped&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;使用iperf测试&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;服务端&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 作为服务端运行，报告回显间隔时间1s&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iperf&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -s -i&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;客户端&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;The&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; best way to demonstrate this is with an iPerf test. In my lab I get&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 95&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; Mbps of performance before applying any bandwidth rules:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 限速前&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iperf3&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -c&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 172.16.106.51&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Connecting&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; to host 172.16.106.51, port&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 5201&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;  5&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; local&lt;/span&gt;&lt;span&gt; 172.28.206.105 port 49560 connected to 172.16.106.51 port 5201&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt; ID&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span&gt; Interval           Transfer     Bitrate         Retr  Cwnd&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;  5&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span&gt;   0.00-1.00   sec  27.2 MBytes   228 Mbits/sec    0   1.17 MBytes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;  5&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span&gt;   1.00-2.00   sec  30.0 MBytes   252 Mbits/sec    0   2.65 MBytes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;  5&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span&gt;   2.00-3.00   sec  31.2 MBytes   262 Mbits/sec    1   3.81 MBytes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;  5&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span&gt;   3.00-4.00   sec  26.2 MBytes   220 Mbits/sec    0   3.81 MBytes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;  5&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span&gt;   4.00-5.00   sec  26.2 MBytes   220 Mbits/sec    0   3.81 MBytes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;  5&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span&gt;   5.00-6.00   sec  27.5 MBytes   231 Mbits/sec    0   3.81 MBytes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;  5&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span&gt;   6.00-7.00   sec  30.0 MBytes   252 Mbits/sec    1   3.81 MBytes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;  5&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span&gt;   7.00-8.00   sec  26.2 MBytes   220 Mbits/sec    0   3.81 MBytes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;  5&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span&gt;   8.00-9.00   sec  27.5 MBytes   231 Mbits/sec    0   3.81 MBytes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;  5&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span&gt;   9.00-10.00  sec  27.5 MBytes   231 Mbits/sec    0   3.81 MBytes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; - - - - - - - - - - - - - - - - - - - - - - - -&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt; ID&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span&gt; Interval           Transfer     Bitrate         Retr&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;  5&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span&gt;   0.00-10.00  sec   280 MBytes   235 Mbits/sec    2             sender&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;  5&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span&gt;   0.00-10.13  sec   280 MBytes   232 Mbits/sec                  receiver&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iperf&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; Done.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 执行限速&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 限速后&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iperf3&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -c&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 172.16.106.51&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Connecting&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; to host 172.16.106.51, port&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 5201&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;  5&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; local&lt;/span&gt;&lt;span&gt; 172.28.206.105 port 48008 connected to 172.16.106.51 port 5201&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt; ID&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span&gt; Interval           Transfer     Bitrate         Retr  Cwnd&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;  5&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span&gt;   0.00-1.00   sec   251 KBytes  2.06 Mbits/sec    0   24.2 KBytes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;  5&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span&gt;   1.00-2.00   sec  87.2 KBytes   714 Kbits/sec    0   24.2 KBytes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;  5&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span&gt;   2.00-3.00   sec  87.2 KBytes   714 Kbits/sec    0   24.2 KBytes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;  5&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span&gt;   3.00-4.00   sec  87.2 KBytes   715 Kbits/sec    0   24.2 KBytes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;  5&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span&gt;   4.00-5.00   sec   174 KBytes  1.43 Mbits/sec    0   24.2 KBytes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;  5&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span&gt;   5.00-6.00   sec  87.2 KBytes   714 Kbits/sec    0   24.2 KBytes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;  5&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span&gt;   6.00-7.00   sec  87.2 KBytes   714 Kbits/sec    0   24.2 KBytes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;  5&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span&gt;   7.00-8.00   sec   177 KBytes  1.45 Mbits/sec    0   24.2 KBytes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;  5&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span&gt;   8.00-9.00   sec  87.2 KBytes   714 Kbits/sec    0   24.2 KBytes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;  5&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span&gt;   9.00-10.00  sec  87.2 KBytes   715 Kbits/sec    0   24.2 KBytes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; - - - - - - - - - - - - - - - - - - - - - - - -&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt; ID&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span&gt; Interval           Transfer     Bitrate         Retr&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;  5&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span&gt;   0.00-10.00  sec  1.18 MBytes   994 Kbits/sec    0             sender&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;  5&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span&gt;   0.00-10.08  sec  1.13 MBytes   941 Kbits/sec                  receiver&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iperf&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; Done.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;can-kao-zi-liao&quot;&gt;参考资料&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;https://catbro666.github.io/posts/357ad3ec/&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://www.linux.com/training-tutorials/qos-linux-tc-and-filters/&quot;&gt;QoS in Linux with TC and Filters - Linux.com&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;https://github.com/spook/tc-easy&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;https://github.com/liucimin/Learning/tree/master/linux%E7%BD%91%E7%BB%9C%E7%9B%B8%E5%85%B3&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;https://www.thegeekdiary.com/tc-command-examples-in-linux/&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://man7.org/linux/man-pages/man8/tc.8.html&quot;&gt;tc(8) - Linux manual page&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http://linux-ip.net/pages/diagrams.html&quot;&gt;Diagrams | http://linux-ip.net/&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;https://cloud.tencent.com/developer/article/1409664&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;https://lartc.org/howto/&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://man7.org/linux/man-pages/man8/tc-u32.8.html&quot;&gt;tc-u32(8) - Linux manual page&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://blog.csdn.net/dog250/article/details/40681809&quot;&gt;数据包的分类和调度-Linux TC的另一种解释_可编程数据包调度-CSDN博客&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://wiki.linuxfoundation.org/networking/netem&quot;&gt;networking:netem [Wiki]&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://wiki.linuxfoundation.org/networking/ifb&quot;&gt;networking:ifb [Wiki]&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://commandnotfound.cn/linux/1/620/tc-%E5%91%BD%E4%BB%A4&quot;&gt;Linux tc 命令&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;https://netbeez.net/blog/how-to-use-the-linux-traffic-control/&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://ggaaooppeenngg.github.io/zh-CN/2017/05/19/cgroup-%E5%AD%90%E7%B3%BB%E7%BB%9F%E4%B9%8B-net-cls-%E5%92%8C-net-prio/&quot;&gt;cgroup 子系统之 net_cls 和 net_prio&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://cloud.tencent.com/developer/article/2166027&quot;&gt;网络测试工具——iperf3详细使用说明&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;https://github.com/magnific0/wondershaper&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/sivel/speedtest-cli&quot;&gt;GitHub - sivel/speedtest-cli: Command line interface for testing internet bandwidth using speedtest.net&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>容器不同网络模式下iptables配置</title>
        <published>2024-01-14T11:01:38+05:30</published>
        <updated>2024-01-14T11:01:38+05:30</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/docker-networking-iptables/"/>
        <id>https://scp.net.cn/blog/docker-networking-iptables/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/docker-networking-iptables/">&lt;h2 id=&quot;rong-qi-de-wang-luo-mo-shi&quot;&gt;容器的网络模式&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Driver&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;bridge&lt;/code&gt;&lt;/td&gt;&lt;td&gt;The default network driver.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;host&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Remove network isolation between the container and the Docker host.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;none&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Completely isolate a container from the host and other containers.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;overlay&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Overlay networks connect multiple Docker daemons together.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;ipvlan&lt;/code&gt;&lt;/td&gt;&lt;td&gt;IPvlan networks provide full control over both IPv4 and IPv6 addressing.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;macvlan&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Assign a MAC address to a container.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;hostwang-luo-mo-shi&quot;&gt;Host网络模式&lt;/h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# Create a new cgroup and assign it a classid&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /sys/fs/cgroup/net_cls/my_cgroup&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0x100001&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /sys/fs/cgroup/net_cls/my_cgroup/net_cls.classid&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# Run a Docker container and move its process to the newly created cgroup&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; run -d --name my_container my_image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; $(&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; inspect -f&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;{{.State.Pid}}&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; my_container&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /sys/fs/cgroup/net_cls/my_cgroup/cgroup.procs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# Use iptables to mark the packets based on the classid&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iptables&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -t mangle -A OUTPUT -m cgroup --cgroup&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0x100001&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -j MARK --set-mark&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# Use tc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# configuring tc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; qdisc add dev eth0 root handle 10: htb&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; class add dev eth0 parent 10: classid 10:1 htb rate 40mbit&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# creating traffic class 10:1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;tc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; filter add dev eth0 parent 10: protocol ip prio&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; handle 1: cgroup&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;说明：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Host模式，容器与主机的网络配置没有隔离&lt;/strong&gt;，需要通过设置 net_cls.classid 标记流量&lt;/p&gt;
&lt;p&gt;参考文档：&lt;a rel=&quot;external&quot; href=&quot;https://www.kernel.org/doc/html/v5.3/admin-guide/cgroup-v1/net_cls.html&quot;&gt;Network classifier cgroup&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;net_cls.classid 数据格式：0xAAAABBBB， AAAA is the major handle number and BBBB is the minor handle number，eg： 0x100001 =&amp;gt; 10:1&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;fei-hostwang-luo-mo-shi&quot;&gt;非Host网络模式&lt;/h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# Get the PID of the container&amp;#39;s network namespace&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PID&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; inspect -f&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;{{.State.Pid}}&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;container_name_or_i&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# Enter the network namespace using nsenter&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;nsenter&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; --net=/proc/&lt;/span&gt;&lt;span&gt;$PID&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;/ns/net iptables -t nat -A PREROUTING -p tcp --dport&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 80&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -j REDIRECT --to-port&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 8080&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;说明：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;非Host模式，容器与主机网络配置通过 &lt;a rel=&quot;external&quot; href=&quot;https://lwn.net/Articles/580893/&quot;&gt;Network namespaces&lt;/a&gt; 隔离&lt;/strong&gt;，需要切换 network namespace 进行配置&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;network_namespaces手册：&lt;a rel=&quot;external&quot; href=&quot;https://man7.org/linux/man-pages/man7/network_namespaces.7.html&quot;&gt;network_namespaces(7) - Linux manual page&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;namespace 执行小工具&lt;/strong&gt;，&lt;code&gt;nsexec.c&lt;/code&gt; &lt;a rel=&quot;external&quot; href=&quot;https://github.com/chaosblade-io/chaosblade/blob/master/nsexec.c&quot;&gt;nsexec.c&lt;/a&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5E81AC;font-weight: bold;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;define&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; _GNU_SOURCE&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5E81AC;font-weight: bold;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;stdio.h&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5E81AC;font-weight: bold;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;unistd.h&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5E81AC;font-weight: bold;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;errno.h&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5E81AC;font-weight: bold;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;sched.h&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5E81AC;font-weight: bold;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;stdio.h&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5E81AC;font-weight: bold;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;stdlib.h&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5E81AC;font-weight: bold;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;string.h&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5E81AC;font-weight: bold;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;fcntl.h&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5E81AC;font-weight: bold;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;getopt.h&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5E81AC;font-weight: bold;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;sys/types.h&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5E81AC;font-weight: bold;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;sys/wait.h&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5E81AC;font-weight: bold;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;sys/prctl.h&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5E81AC;font-weight: bold;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;sys/stat.h&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5E81AC;font-weight: bold;&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;sys/syscall.h&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;extern char**&lt;/span&gt;&lt;span&gt; environ&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; enter_ns&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;int&lt;/span&gt;&lt;span&gt; pid&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; const char*&lt;/span&gt;&lt;span&gt; type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5E81AC;font-weight: bold;&quot;&gt;#ifdef&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; __NR_setns&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    char&lt;/span&gt;&lt;span&gt; path&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;64&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;],&lt;/span&gt;&lt;span&gt; selfpath&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;64&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    snprintf&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;path&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; sizeof&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;path&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;), &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;/proc/%d/ns/%s&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span&gt; pid&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    snprintf&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;selfpath&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; sizeof&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;selfpath&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;), &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;/proc/self/ns/%s&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span&gt; type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    struct&lt;/span&gt;&lt;span&gt; stat oldns_stat&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; newns_stat&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;stat&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;selfpath&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;oldns_stat&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; stat&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;path&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;newns_stat&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // Don&amp;#39;t try to call setns() if we&amp;#39;re in the same namespace already&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;oldns_stat&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;st_ino&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; !=&lt;/span&gt;&lt;span&gt; newns_stat&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;st_ino&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            int&lt;/span&gt;&lt;span&gt; newns &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; open&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;path&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; O_RDONLY&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;newns &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;                return -&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;            // Some ancient Linux distributions do not have setns() function&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            int&lt;/span&gt;&lt;span&gt; result &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; syscall&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;__NR_setns&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; newns&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;            close&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;newns&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            return&lt;/span&gt;&lt;span&gt; result &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ? -&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5E81AC;font-weight: bold;&quot;&gt;#endif&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; // __NR_setns&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; sig&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;int&lt;/span&gt;&lt;span&gt; signum&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;){}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; main&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;int&lt;/span&gt;&lt;span&gt; argc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; char *&lt;/span&gt;&lt;span&gt;argv&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;[]&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    int&lt;/span&gt;&lt;span&gt; target &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    char *&lt;/span&gt;&lt;span&gt;cmd&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    int&lt;/span&gt;&lt;span&gt; stop &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    int&lt;/span&gt;&lt;span&gt; opt&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    int&lt;/span&gt;&lt;span&gt; option_index &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    char *&lt;/span&gt;&lt;span&gt;string &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;st:mpuni&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    int&lt;/span&gt;&lt;span&gt; ipcns &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    int&lt;/span&gt;&lt;span&gt; utsns &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    int&lt;/span&gt;&lt;span&gt; netns &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    int&lt;/span&gt;&lt;span&gt; pidns &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    int&lt;/span&gt;&lt;span&gt; mntns &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    while&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;((&lt;/span&gt;&lt;span&gt;opt &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getopt&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;argc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; argv&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; string&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;!= -&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        switch&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;opt&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            case&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;s&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                stop &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;                break;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            case&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;t&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                target &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; atoi&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;optarg&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;                break;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            case&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;m&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                mntns &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;                break;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            case&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                pidns &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;                break;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            case&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;u&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                utsns &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;                break;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            case&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                netns &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;                break;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            case&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                ipcns &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;                break;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            default&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;                break;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // check target pid&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;target &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;        fprintf&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;stderr&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;%s is not a valid process ID&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span&gt; target&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // pause&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;stop&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            char *&lt;/span&gt;&lt;span&gt;pe &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;pause&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;            prctl&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;PR_SET_NAME&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; pe&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;            signal&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;SIGCONT&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;sig&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;            pause&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            char *&lt;/span&gt;&lt;span&gt;nc &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;nsexec&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;            prctl&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;PR_SET_NAME&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; nc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // enter namespace&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ipcns&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;        enter_ns&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;target&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;ipc&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;utsns&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;        enter_ns&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;target&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;uts&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;netns&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;        enter_ns&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;target&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;net&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;pidns&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;        enter_ns&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;target&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;pid&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;mntns&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;        enter_ns&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;target&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;mnt&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    // fork exec&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    pid_t&lt;/span&gt;&lt;span&gt; pid&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    int&lt;/span&gt;&lt;span&gt; status&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;((&lt;/span&gt;&lt;span&gt;pid &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; fork&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;())&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        status &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;= -&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; else if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;pid &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;){&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // args&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        int&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt;j&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        char *&lt;/span&gt;&lt;span&gt;args&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;256&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;NULL&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        for&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt; optind&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; argc&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; j&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            args&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;j&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; argv&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;        execvp&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;argv&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;optind&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;],&lt;/span&gt;&lt;span&gt; args&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;        _exit&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;127&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; else&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        while&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;waitpid&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;pid&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;status&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;){&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;errno &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;!=&lt;/span&gt;&lt;span&gt; EINTR&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;){&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                status &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;= -&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;                break;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;WIFEXITED&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;status&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)){&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;            exit&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;WEXITSTATUS&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;status&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 测试&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# compile&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;gcc&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; nsexec.c -o nsexec&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# Get the PID of the container&amp;#39;s network namespace&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PID&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; inspect -f&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;{{.State.Pid}}&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;container_name_or_i&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# exec&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;./nsexec&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -n -t PID -- /bin/sh -c&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# check&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;./nsexec&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -n -t PID -- /bin/sh -c&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;iptables -t nat -L&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Chain&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; PREROUTING&lt;/span&gt;&lt;span&gt; (policy&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; ACCEPT&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;target&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;     prot opt source               destination&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;REDIRECT&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;   tcp  --  anywhere             anywhere             tcp dpt:http redir ports&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 8080&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Chain&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; INPUT&lt;/span&gt;&lt;span&gt; (policy&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; ACCEPT&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;target&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;     prot opt source               destination&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Chain&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; POSTROUTING&lt;/span&gt;&lt;span&gt; (policy&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; ACCEPT&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;target&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;     prot opt source               destination&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Chain&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; OUTPUT&lt;/span&gt;&lt;span&gt; (policy&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; ACCEPT&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;target&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;     prot opt source               destination&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Linux CGroups and Namespaces</title>
        <published>2024-01-11T22:01:58+05:30</published>
        <updated>2024-01-11T22:01:58+05:30</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/cgroups-and-namespaces/"/>
        <id>https://scp.net.cn/blog/cgroups-and-namespaces/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/cgroups-and-namespaces/">&lt;p&gt;Namespaces 用来做进程间资源隔离，Namespaces 中进程使用的资源对其他进程不可见（包括 进程ID、Hostnames、用户ID、文件、网络 等内核资源）。&lt;/p&gt;
&lt;p&gt;Cgroup 用来做资源限制，包括 CPU、内存、网络、磁盘 等系统资源；&lt;/p&gt;
&lt;p&gt;Namespaces和 Cgroup 是Linux 容器技术的基石。&lt;/p&gt;
&lt;p&gt;如果进程更改了特定Namespaces下的全局资源(如 PID) ，则只有同一Namespaces中的进程才能看到此更改。(不管初始化进程是什么，都可以用 PID 1启动进程)&lt;/p&gt;
&lt;p&gt;以下是Linux内核中的几种Namespaces类型:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;User Namespace&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;给予进程的独立用户和组ID。进程可以在其命名空间中升级到Root用户。&lt;/p&gt;
&lt;p&gt;User Namespace是嵌套的。所有User Namespace都有一个父User Namespace (Root User Namespace除外) ，并且有零个或多个子 User Namespace。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;PID Namespace&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;PID Namespace 用来隔离进程 ID。不同 PID Namespace 下的不同进程可以具有相同的进程 ID。PID Namespace 的第一个进程采用 PID 1，随后的进程ID 按顺序生成。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Network Namespace&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Network Namespace 用于隔离网络。Network Namespace 中的进程可以独立于其他Network Namespace使用自定义/特定的路由表、 IP 地址、网络设备和其他网络资源。&lt;/p&gt;
&lt;p&gt;&lt;em&gt;备注：我们可以使用使用网络命名空间的 &lt;code&gt;ip netns&lt;/code&gt; 命令来创建虚拟网络设备&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mount Namespace&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;不影响主机文件系统，为命名空间下的进程挂载文件系统。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;IPC Namespace&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;IPC Namespace下的进程可以以独立的方式使用 IPC 资源。例如消息队列、共享内存和 SystemVIPC 对象。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;UNIX Time Sharing(UTS) Namespace&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;UNIX Time Sharing(UTS) Namespace 下的进程似乎在不同的机器上运行 (隔离主机名，不同的主机名)。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Control Group (cgroup)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;使用 cgroup，可以限制 Namespace 下进程的资源，如 CPU、内存、磁盘等。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Time Namespace&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Time Namespace下的进程可以有不同的系统时间。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example with &lt;code&gt;unshare&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;可以使用 unshare 命令在 namespace 中执行进程。&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Usage:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; unshare [options] [&amp;lt;program&amp;gt; [&amp;lt;argument&amp;gt;...]]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Run a program with some namespaces unshared from the parent.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Options:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; -m, --mount[=&amp;lt;file&amp;gt;]      unshare mounts namespace&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; -u, --uts[=&amp;lt;file&amp;gt;]        unshare UTS namespace (hostname etc)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; -i, --ipc[=&amp;lt;file&amp;gt;]        unshare System V IPC namespace&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; -n, --net[=&amp;lt;file&amp;gt;]        unshare network namespace&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; -p, --pid[=&amp;lt;file&amp;gt;]        unshare pid namespace&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; -U, --user[=&amp;lt;file&amp;gt;]       unshare user namespace&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; -C, --cgroup[=&amp;lt;file&amp;gt;]     unshare cgroup namespace&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; -f, --fork                fork before launching &amp;lt;program&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     --kill-child[=&amp;lt;signame&amp;gt;]  when dying, kill the forked child (implies --fork); defaults to SIGKILL&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     --mount-proc[=&amp;lt;dir&amp;gt;]  mount proc filesystem first (implies --mount)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; -r, --map-root-user       map current user to root (implies --user)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     --propagation slave|shared|private|unchanged&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                           modify mount propagation in mount namespace&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; -s, --setgroups allow|deny  control the setgroups syscall in user namespaces&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; -h, --help                display this help&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; -V, --version             display version&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;unshare --user --pid --map-root-user --mount-proc --fork bash&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;--user: 创建user namespace&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;--pid: 不从父进程继承pid命名空间，在子进程内执行ps，无法看到父进程原有的进程&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;--map-root-user:  namespace 中支持 root 权限&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;--mount-proc: 确保创建了 PID 和 Mount namespace 后，自动挂载 /proc 文件系统，无需我们手动执行 `mount -t proc proc /proc` 命令&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;--fork: 执行unshare的进程fork一个新的子进程，在子进程里执行unshare传入的参数&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;使用 &lt;code&gt;--mount-proc&lt;/code&gt;，可以隔离宿主机 &lt;code&gt;/proc&lt;/code&gt; 文件系统，使用独立的进程ID；
可以通过 &lt;code&gt;lsns&lt;/code&gt; 命令列出 namespaces；&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Control Groups&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;通过Control Groups，CPU、磁盘、网络、内存和其他系统资源都可以受到限制。我们可以使用 cgroup 创建资源限制配置。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;优先级: 我们可以使用 cgroup 对名称空间中的进程进行优先排序。&lt;/li&gt;
&lt;li&gt;统计和监控: 可以在 cgroup 级别进行监控和统计资源。&lt;/li&gt;
&lt;li&gt;管理：同一 cgroup 下的进程可以由单个命令管理。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;CGroup 工具：&lt;/p&gt;
&lt;p&gt;Debian &lt;code&gt;sudo apt install cgroup-tools&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Centos &lt;code&gt;sudo yum install libcgroup&lt;/code&gt; &lt;code&gt;sudo yum install libcgroup-tools&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 创建 memory cgroup&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; cgcreate -g memory:test-memory-limiter&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;ls&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -la /sys/fs/cgroup/memory/test-memory-limiter/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 限制内存&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; cgset -r memory.limit_in_bytes=50M my-memory-limiter&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; /sys/fs/cgroup/memory/test-memory-limiter/memory.limit_in_bytes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 编译测试程序&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# gcc high_mem.c -o high_mem.c&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 执行内存限制进程&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# sudo cgexec -g memory:test-memory-limiter ./high_mem&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# namespace 下执行内存限制进程&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; cgexec -g memory:test-memory-limiter unshare -fp - mount-proc /bin/bash&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;high_mem.c&lt;/code&gt; 代码&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;int main()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        while(1)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                void *m = malloc(1024*1024);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                memset(m,0,1024*1024);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return 0;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;可以通过 &lt;code&gt;systemd-cgtop&lt;/code&gt;  查看 &lt;code&gt;cgroup&lt;/code&gt; 资源使用情况；&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;参考文档&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://www.nginx.com/blog/what-are-namespaces-cgroups-how-do-they-work/&quot;&gt;What Are Namespaces and cgroups, and How Do They Work?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/resource_management_guide/index&quot;&gt;Resource Management Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://theboreddev.com/understanding-linux-namespaces/&quot;&gt;Understanding Linux Namespaces&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://en.wikipedia.org/wiki/Linux_namespaces&quot;&gt;Wiki Linux namespaces&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://man7.org/linux/man-pages/man7/namespaces.7.html&quot;&gt;namespaces(7) — Linux manual page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://towardsdatascience.com/the-power-of-linux-cgroups-how-containers-take-control-of-their-resources-ba564fef13b0&quot;&gt;The Power of Linux Cgroups: How Containers Take Control of Their Resources&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Apache Kafka, Purgatory, and Hierarchical Timing Wheels</title>
        <published>2023-11-12T23:01:58+05:30</published>
        <updated>2023-11-12T23:01:58+05:30</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/kafka-purgatory-hierarchicaltimingwheels/"/>
        <id>https://scp.net.cn/blog/kafka-purgatory-hierarchicaltimingwheels/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/kafka-purgatory-hierarchicaltimingwheels/">&lt;p&gt;Kafka 中有很多HTTP请求需要处理，例如：生产者 ack=all、消费者 min.bytes=1 、集群内部 broker 之间通信，需要跟踪这些请求的状态（成功、失败、超时）；&lt;/p&gt;
&lt;p&gt;Kafka 会同时有成千上万的异步请求操作同时进行，面对大规模的请求处理，使用 DelayQueue 去跟踪请求状态会有以下问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;请求完成后不能立即删除，需要在后续检查，检查完成的请求，触发删除操作，如果检查删除操作跟不上请求速度，会出现OOM错误；&lt;/li&gt;
&lt;li&gt;开启一个单独的线程去扫描 DelayQueue，但是频繁的扫描很多 DelayQueue，会有很大的性能损耗（&lt;strong&gt;DelayQueue 插入和删除 O(n)&lt;/strong&gt;）；&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;新设计的目标是允许立即删除已完成的请求，并大大减少昂贵的清除过程的负载。
它需要对计时器和请求中的条目进行交叉引用。
另外，由于每个请求/完成都会执行插入/删除操作，因此强烈希望具有 O (1)插入/删除开销。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Doubly Linked List for Buckets in Timing Wheels (时间轮中桶的双向链表实现，双向链表的优点是，允许O(1)插入/删除一项)&lt;/li&gt;
&lt;li&gt;Driving Clock using DelayQueue (使用 DelayQueue 驱动时间轮，避免时间轮空转消耗资源)&lt;/li&gt;
&lt;li&gt;Purging Watcher Lists (已完成的请求将立即从计时器队列中删除，O(1)开销)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;blockquote&gt;
&lt;p&gt;原文地址 &lt;a rel=&quot;external&quot; href=&quot;https://www.confluent.io/blog/apache-kafka-purgatory-hierarchical-timing-wheels/&quot;&gt;Apache Kafka, Purgatory, and Hierarchical Timing Wheels&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://www.confluent.io/blog/stream-data-platform-1/&quot;&gt;Apache Kafka&lt;/a&gt; has a data structure called the “request purgatory”. The &lt;a rel=&quot;external&quot; href=&quot;https://en.wikipedia.org/wiki/Purgatory&quot;&gt;purgatory&lt;/a&gt; holds any request that hasn’t yet met its criteria to succeed but also hasn’t yet resulted in an error. The problem is “How can we efficiently keep track of tens of thousands of requests that are being asynchronously satisfied by other activity in the cluster?”&lt;/p&gt;
&lt;p&gt;Kafka implements several request types that cannot immediately be answered with a response. Examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A produce request with acks=all cannot be considered complete until all in-sync replicas have acknowledged the write and we can guarantee it will not be lost if the leader fails.&lt;/li&gt;
&lt;li&gt;A fetch request with min.bytes=1 won’t be answered until there is at least one new byte of data for the consumer to consume. This allows a “long poll” so that the consumer need not busy wait checking for new data to arrive.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These requests are considered complete when either (a) the criteria they requested is complete or (b) some timeout occurs.&lt;/p&gt;
&lt;p&gt;The number of these asynchronous operations in flight at any time scales with the number of connections, which, for Kafka, is often tens of thousands.&lt;/p&gt;
&lt;p&gt;The request purgatory is designed for such a large scale request handling, but the old implementation had a number of deficiencies.&lt;/p&gt;
&lt;p&gt;In this blog, I would like to explain the problem with the old implementation and how the new implementation solved it. I will also present benchmark results.&lt;/p&gt;
&lt;h2 id=&quot;old-purgatory-design&quot;&gt;Old Purgatory Design&lt;/h2&gt;
&lt;p&gt;The request purgatory consists of a timeout timer and a hash map of watcher lists for event driven processing. A request is put into the purgatory when it is not immediately satisfiable because of unmet conditions. A request in the purgatory is completed later when the conditions are met or is forced to be completed (timeout) when it passed beyond the time specified in the timeout parameter of the request. In the old design, it used Java &lt;em&gt;DelayQueue&lt;/em&gt; to implement the timer.&lt;/p&gt;
&lt;p&gt;When a request is completed, the request is not deleted from the timer or watcher lists immediately. Instead, completed requests are deleted as they were found during condition checking. When the deletion does not keep up, the server may exhaust JVM heap and cause &lt;em&gt;OutOfMemoryError&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;To alleviate the situation, a separate thread, called the reaper thread, purges completed requests from the purgatory when the number of requests (either pending or completed) in the purgatory exceeds the configured number. The purge operation scans the timer queue and all watcher lists to find completed requests and deletes them.&lt;/p&gt;
&lt;p&gt;By setting this configuration parameter low, the server can virtually avoid the memory problem. However, the server must pay a significant performance penalty if it scans all lists too frequently.&lt;/p&gt;
&lt;h2 id=&quot;new-purgatory-design&quot;&gt;New Purgatory Design&lt;/h2&gt;
&lt;p&gt;The goal of the new design is to allow immediate deletion of a completed request and reduce the load of expensive purge process significantly. It requires cross referencing of entries in the timer and the requests. Also it is strongly desired to have O(1) insert/delete cost since insert/delete operation happens for each request/completion.&lt;/p&gt;
&lt;p&gt;To satisfy these requirements, we designed a new purgatory implementation based on &lt;a rel=&quot;external&quot; href=&quot;http://www.cs.columbia.edu/~nahum/w6998/papers/ton97-timing-wheels.pdf&quot;&gt;Hierarchical Timing Wheels&lt;/a&gt; [1].&lt;/p&gt;
&lt;h3 id=&quot;hierarchical-timing-wheel&quot;&gt;Hierarchical Timing Wheel&lt;/h3&gt;
&lt;p&gt;A simple timing wheel is a circular list of buckets of timer tasks. Let u be the time unit. A timing wheel with size &lt;strong&gt;n&lt;/strong&gt; has &lt;strong&gt;n&lt;/strong&gt; buckets and can hold timer tasks in &lt;strong&gt;n * u&lt;/strong&gt; time interval. Each bucket holds timer tasks that fall into the corresponding time range. At the beginning, the first bucket holds tasks for &lt;strong&gt;[0, u)&lt;/strong&gt;, the second bucket holds tasks for &lt;strong&gt;[u, 2u)&lt;/strong&gt;, …, the &lt;strong&gt;n&lt;/strong&gt;-th bucket for &lt;strong&gt;[u * (n -1), u * n)&lt;/strong&gt;. Every interval of time unit &lt;strong&gt;u&lt;/strong&gt;, the timer ticks and moved to the next bucket then expire all timer tasks in it. So, the timer never inserts a task into the bucket for the current time since it is already expired. The timer immediately runs the expired task. The emptied bucket is then available for the next round, so if the current bucket is for the time t, it becomes the bucket for &lt;strong&gt;[t + u * n, t + (n + 1) * u)&lt;/strong&gt; after a tick. A timing wheel has O(1) cost for insert/delete (start-timer/stop-timer) whereas priority queue based timers, such as &lt;em&gt;java.util.concurrent.DelayQueue&lt;/em&gt; and &lt;em&gt;java.util.Timer&lt;/em&gt;, have O(log n) insert/delete cost. Note that neither &lt;em&gt;DelayQueue&lt;/em&gt; or &lt;em&gt;Timer&lt;/em&gt; supports random delete.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.confluent.io/wp-content/uploads/2016/08/TimingWheels1.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;p&gt;A major drawback of a simple timing wheel is that it assumes that a timer request is within the time interval of &lt;strong&gt;n * u&lt;/strong&gt; from the current time. If a timer request is out of this interval, it is an overflow. A hierarchical timing wheel deals with such overflows. It is a hierarchically organized timing wheels that delegate overflows to upper level wheels. The lowest level has the finest time resolution. Time resolutions become coarser as we move up the hierarchy. If the resolution of a wheel at one level is &lt;strong&gt;u&lt;/strong&gt; and the size is &lt;strong&gt;n&lt;/strong&gt;, the resolutions should be &lt;strong&gt;n * u&lt;/strong&gt; in the second level, &lt;strong&gt;n2 * u&lt;/strong&gt; in the third level, and so on. At each level overflows are delegated to the wheel in one level higher. When the wheel in the higher level ticks, it reinsert timer tasks to the lower level. An overflow wheel can be created on-demand. When a bucket in an overflow bucket expires, all tasks in it are reinserted into the timer recursively. The tasks are then moved to the finer grain wheels or be executed. The insert (start-timer) cost is O(m) where &lt;strong&gt;m&lt;/strong&gt; is the number of wheels, which is usually very small compared to the number of requests in the system, and the delete (stop-timer) cost is still O(1).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.confluent.io/wp-content/uploads/2016/08/TimingWheels2.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;h3 id=&quot;doubly-linked-list-for-buckets-in-timing-wheels&quot;&gt;Doubly Linked List for Buckets in Timing Wheels&lt;/h3&gt;
&lt;p&gt;In the new design, we use own implementation of doubly linked list for the buckets in a timing wheel. The advantage of doubly linked list that it allows O(1) insert/delete of a list item if we have access link cells in a list.&lt;/p&gt;
&lt;p&gt;A timer task instance saves a link cell in itself when enqueued to a timer queue. When a task is completed or canceled, the list is updated using the link cell saved in the task itself.&lt;/p&gt;
&lt;h3 id=&quot;driving-clock-using-delayqueue&quot;&gt;Driving Clock using DelayQueue&lt;/h3&gt;
&lt;p&gt;A simple implementation may use a thread that wakes up every unit time and does the ticking, which checks if there is any task in the bucket. The unit time of the purgatory is 1ms (&lt;strong&gt;u&lt;/strong&gt; = 1ms). This can be wasteful if requests are sparse at the wheel at the lowest level. This is usually the case because the majority of requests are satisfied before inserted into the wheel at the lowest level. It would be nice if a thread wakes up only when there is a non-empty bucket to expire. The new purgatory does so by using &lt;em&gt;java.util.concurrent.DelayQueue&lt;/em&gt; similarly to the old implementation, but we enqueue task buckets instead of individual tasks. This design has a performance advantage. The number of items in &lt;em&gt;DelayQueue&lt;/em&gt; is capped by the number of buckets, which is usually much smaller than the number of tasks, thus the number of offer/poll operations to the priority queue inside &lt;em&gt;DelayQueue&lt;/em&gt; will be significantly smaller.&lt;/p&gt;
&lt;h3 id=&quot;purging-watcher-lists&quot;&gt;Purging Watcher Lists&lt;/h3&gt;
&lt;p&gt;In the old implementation, the purge operation of watcher lists is triggered by the total size if the watcher lists. The problem is that the watcher lists may exceed the threshold even when there isn’t many requests to purge. When this happens it increases the CPU load a lot. Ideally, the purge operation should be triggered by the number of completed requests the watcher lists.&lt;/p&gt;
&lt;p&gt;In the new design, a completed request is removed from the timer queue immediately with O(1) cost. It means that the number of requests in the timer queue is the number of pending requests exactly at any time. So, if we know the total number of distinct requests in the purgatory, which includes the sum of the number of pending request and the numbers completed but still watched requests, we can avoid unnecessary purge operations. It is not trivial to keep track of the exact number of distinct requests in the purgatory because a request may or may not be watched. In the new design, we estimate the total number of requests in the purgatory rather than trying to maintain the exactly number.&lt;/p&gt;
&lt;p&gt;The estimated number of requests are maintained as follows.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The estimated total number of requests, &lt;strong&gt;E&lt;/strong&gt;, is incremented whenever a new request is watched.&lt;/li&gt;
&lt;li&gt;Before starting the purge operation, we reset the estimated total number of requests to the size of timer queue. This is the current number of pending requests. If no requests are added to the purgatory during purge, &lt;strong&gt;E&lt;/strong&gt; is the correct number of requests after purge.&lt;/li&gt;
&lt;li&gt;If some requests are added to the purgatory during purge, &lt;strong&gt;E&lt;/strong&gt; is incremented to &lt;strong&gt;E + the number of newly watched requests&lt;/strong&gt;. This may be an overestimation because it is possible that some of the new requests are completed and remove from the watcher lists during the purge operation. We expect the chance of overestimation and an amount of overestimation are small.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;benchmark&quot;&gt;Benchmark&lt;/h2&gt;
&lt;p&gt;We compared the enqueue performance of two purgatory implementations, the old implementation and the new implementation. This is a micro benchmark. It measures just the purgatory enqueue performance. The purgatory was separated from the rest of the system and also uses a fake request which does nothing useful. So, the throughput of the purgatory in a real system may be lower than the number shown by the test.&lt;/p&gt;
&lt;p&gt;In the test, the intervals of the requests are assumed to follow the exponential distribution. Each request takes a time drawn from a log-normal distribution. By adjusting the shape of the log-normal distribution, we can test different timeout rate.&lt;/p&gt;
&lt;p&gt;The tick size is 1ms and the wheel size is 20. The timeout was set to 200ms. The data size of a request was 100 bytes. For a low timeout rate case, we chose 75percentile = 60ms and 50percentile = 20. And for a high timeout rate case, we chose 75percentile = 400ms and 50percentile = 200ms. Total 1 million requests are enqueued in each run.&lt;/p&gt;
&lt;p&gt;Requests are actively completed by a separate thread. Requests that are supposed to be completed before timeout are enqueued to another &lt;em&gt;DelayQueue&lt;/em&gt;. And a separate thread keeps polling and completes them. There is no guarantee of accuracy in terms of actual completion time.&lt;/p&gt;
&lt;p&gt;The JVM heap size is set to 200m to reproduce a memory tight situation.&lt;/p&gt;
&lt;p&gt;The result shows a dramatic difference in a high enqueue rate area. As the target rate increases, both implementations keep up with the requests initially. However, in low timeout scenario the old implementation was saturated around 40000 RPS (request per second), whereas the new implementation didn’t show any significant performance degradation, and in high timeout scenario the old implementation was saturated around 25000 RPS, whereas the new implementation was saturated 105000 RPS in this benchmark.&lt;img src=&quot;https://cdn.confluent.io/wp-content/uploads/2016/08/enq_rate.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Also, CPU usage is significantly better in the new implementation. Note that the old implementation does not have data point higher than ~40000 RPS due to its scalability limit. Also notice that its CPU time saturates around 1.2 while it is steadily going up in the new implementation. It indicate that the old implementation may be hitting a concurrency issue due to synchronizations.&lt;img src=&quot;https://cdn.confluent.io/wp-content/uploads/2016/08/cms_time.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Finally, we measured total GC time (milliseconds) for &lt;em&gt;ParNew collection&lt;/em&gt; and &lt;em&gt;CMS collection&lt;/em&gt;. There isn’t much difference in the old implementation and the new implementation in the region of enqueue rate that the old implementation can sustain. Again note that old implementation does not have data point higher than ~40000 RPS due to its scalability limit.&lt;img src=&quot;https://cdn.confluent.io/wp-content/uploads/2016/08/parnew_time.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.confluent.io/wp-content/uploads/2016/08/cms_time.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;In the new design, we use Hierarchical Timing Wheels for the timeout timer and &lt;em&gt;DelayQueue&lt;/em&gt; of timer buckets to advance the clock on demand. Completed requests are removed from the timer queue immediately with O(1) cost. The buckets remain in the delay queue, however, the number of buckets is bounded. And, in a healthy system, most of the requests are satisfied before timeout, and many of the buckets become empty before pulled out of the delay queue. Thus, the timer should rarely have the buckets of the lower interval. The advantage of this design is that the number of requests in the timer queue is the number of pending requests exactly at any time. This allows us to estimate the number of requests need to be purged. We can avoid unnecessary purge operation of the watcher lists. As the result we achieve a higher scalability in terms of request rate with much better CPU usage.&lt;/p&gt;
&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;
&lt;p&gt;[1] &lt;a rel=&quot;external&quot; href=&quot;http://www.cs.columbia.edu/~nahum/w6998/papers/ton97-timing-wheels.pdf&quot;&gt;George Varghese , Anthony Lauck, Hashed and hierarchical timing wheels: efficient data structures for implementing a timer facility, IEEE/ACM Transactions on Networking (TON), v.5 n.6, p.824-834, Dec. 1997&lt;/a&gt;&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>How To Ask Questions The Smart Way</title>
        <published>2023-11-11T09:01:58+05:30</published>
        <updated>2023-11-11T09:01:58+05:30</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/how-to-ask-questions-the-smart-way/"/>
        <id>https://scp.net.cn/blog/how-to-ask-questions-the-smart-way/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/how-to-ask-questions-the-smart-way/">&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/tvvocold/How-To-Ask-Questions-The-Smart-Way&quot;&gt;原文链接&lt;/a&gt; &lt;img src=&quot;https://scp-net-cn.oss-cn-beijing.aliyuncs.com/blog-images/how-to-ask.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;h1 id=&quot;ti-wen-de-zhi-hui&quot;&gt;提问的智慧&lt;/h1&gt;
&lt;h4 id=&quot;ai-rui-ke-shi-di-wen-lei-meng-de-eric-steven-raymond&quot;&gt;艾瑞克.史蒂文.雷蒙德（Eric Steven Raymond）&lt;/h4&gt;
&lt;p&gt;Thyrsus Enterprises&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;mailto:esr@thyrsus.com&quot;&gt;esr@thyrsus.com&lt;/a&gt;&lt;/p&gt;
&lt;h4 id=&quot;rui-ke-mo-en-rick-moen&quot;&gt;瑞克.莫恩（Rick Moen）&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;mailto:respond-auto@linuxmafia.com&quot;&gt;respond-auto@linuxmafia.com&lt;/a&gt;
版权©2001, 2006 Eric S. Raymond, Rick Moen&lt;/p&gt;
&lt;h3 id=&quot;修订历史&quot;&gt;修订历史&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;修订版 3.9    2013年4月23日    esr&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;修正链接&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;修订版 3.8    2012年6月19日    esr&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;修正链接&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;修订版 3.7    2010年12月6日    esr&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;对于英语为第二语言人士的有益建议&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;修订版 3.7    2010年11月2日    esr&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;几种翻译不见了&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;修订版 3.6    2008年3月19日    esr&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;小更新及新链接&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;修订版 3.5    2008年1月2日    esr&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;勘误及一些翻译链接&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;修订版 3.4    2007年3月24日    esr&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;新章节：“关于代码的问题”&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;修订版 3.3    2006年9月29日    esr&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;增加凯.尼格曼（Kai Niggemann）的一个好建议&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;修订版 3.2    2006年1月10日    esr&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;加入瑞克.莫恩（Rick Moen）编写的内容&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;修订版 3.1    2004年10月28日    esr&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;文档“谷歌是你的朋友！”&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;修订版 3.0    2004年2月2日    esr&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;主要新增在网页论坛应有的礼节&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;yuan-wen-how-to-ask-questions-the-smart-way&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;http://www.catb.org/~esr/faqs/smart-questions.html&quot;&gt;原文：How To Ask Questions The Smart Way&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;翻译：王刚 &amp;lt;yafrank at 126 dot com &amp;gt;&lt;br /&gt;
时间：2013年10月26日
内容&lt;/p&gt;
&lt;h3 id=&quot;mu-lu&quot;&gt;目录&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/how-to-ask-questions-the-smart-way/#%E5%BC%83%E6%9D%83%E7%94%B3%E6%98%8E&quot;&gt;弃权申明&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/how-to-ask-questions-the-smart-way/#%E5%BC%95%E8%A8%80&quot;&gt;引言&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/how-to-ask-questions-the-smart-way/#%E6%8F%90%E9%97%AE%E5%89%8D&quot;&gt;提问前&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/how-to-ask-questions-the-smart-way/#%E6%8F%90%E9%97%AE%E6%97%B6&quot;&gt;提问时&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/how-to-ask-questions-the-smart-way/#%E4%BB%94%E7%BB%86%E6%8C%91%E9%80%89%E8%AE%BA%E5%9D%9B&quot;&gt;仔细挑选论坛&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/how-to-ask-questions-the-smart-way/#%E9%9D%A2%E5%90%91%E6%96%B0%E6%89%8B%E7%9A%84%E8%AE%BA%E5%9D%9B%E5%92%8C%E4%BA%92%E8%81%94%E7%BD%91%E4%B8%AD%E7%BB%A7%E8%81%8A%E5%A4%A9irc%E9%80%9A%E5%B8%B8%E5%93%8D%E5%BA%94%E6%9C%80%E5%BF%AB&quot;&gt;面向新手的论坛和互联网中继聊天（IRC）通常响应最快&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/how-to-ask-questions-the-smart-way/#%E7%AC%AC%E4%BA%8C%E6%AD%A5%E4%BD%BF%E7%94%A8%E9%A1%B9%E7%9B%AE%E7%9A%84%E9%82%AE%E4%BB%B6%E5%88%97%E8%A1%A8&quot;&gt;第二步，使用项目的邮件列表&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/how-to-ask-questions-the-smart-way/#%E4%BD%BF%E7%94%A8%E6%9C%89%E6%84%8F%E4%B9%89%E4%B8%94%E6%98%8E%E7%A1%AE%E7%9A%84%E4%B8%BB%E9%A2%98&quot;&gt;使用有意义且明确的主题&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/how-to-ask-questions-the-smart-way/#%E4%BD%BF%E9%97%AE%E9%A2%98%E5%AE%B9%E6%98%93%E5%9B%9E%E5%A4%8D&quot;&gt;使问题容易回复&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/how-to-ask-questions-the-smart-way/#%E7%94%A8%E6%B8%85%E6%99%B0%E8%AF%AD%E6%B3%95%E6%8B%BC%E5%86%99%E6%AD%A3%E7%A1%AE%E7%9A%84%E8%AF%AD%E5%8F%A5%E4%B9%A6%E5%86%99&quot;&gt;用清晰、语法、拼写正确的语句书写&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/how-to-ask-questions-the-smart-way/#%E4%BD%BF%E7%94%A8%E6%98%93%E4%BA%8E%E8%AF%BB%E5%8F%96%E4%B8%94%E6%A0%87%E5%87%86%E7%9A%84%E6%96%87%E4%BB%B6%E6%A0%BC%E5%BC%8F%E5%8F%91%E9%80%81%E9%97%AE%E9%A2%98&quot;&gt;使用易于读取且标准的文件格式发送问题&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/how-to-ask-questions-the-smart-way/#%E6%8F%8F%E8%BF%B0%E9%97%AE%E9%A2%98%E5%BA%94%E5%87%86%E7%A1%AE%E4%B8%94%E6%9C%89%E5%86%85%E5%AE%B9&quot;&gt;描述问题应准确且有内容&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/how-to-ask-questions-the-smart-way/#%E9%87%8F%E4%B8%8D%E5%9C%A8%E5%A4%9A%E7%B2%BE%E7%82%BC%E5%88%99%E7%81%B5&quot;&gt;量不在多，精炼则灵&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/how-to-ask-questions-the-smart-way/#%E5%88%AB%E6%80%A5%E4%BA%8E%E5%AE%A3%E7%A7%B0%E6%89%BE%E5%88%B0Bug&quot;&gt;别急于宣称找到Bug&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/how-to-ask-questions-the-smart-way/#%E4%BD%8E%E5%A3%B0%E4%B8%8B%E6%B0%94%E4%BB%A3%E6%9B%BF%E4%B8%8D%E4%BA%86%E5%81%9A%E8%87%AA%E5%B7%B1%E7%9A%84%E5%AE%B6%E5%BA%AD%E4%BD%9C%E4%B8%9A&quot;&gt;低声下气代替不了做自己的家庭作业&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/how-to-ask-questions-the-smart-way/#%E6%8F%8F%E8%BF%B0%E9%97%AE%E9%A2%98%E7%97%87%E7%8A%B6%E8%80%8C%E4%B8%8D%E6%98%AF%E7%8C%9C%E6%B5%8B&quot;&gt;描述问题症状而不是猜测&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/how-to-ask-questions-the-smart-way/#%E6%8C%89%E6%97%B6%E9%97%B4%E5%85%88%E5%90%8E%E7%BD%97%E5%88%97%E9%97%AE%E9%A2%98%E7%97%87%E7%8A%B6&quot;&gt;按时间先后罗列问题症状&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/how-to-ask-questions-the-smart-way/#%E6%8F%8F%E8%BF%B0%E7%9B%AE%E6%A0%87%E8%80%8C%E4%B8%8D%E6%98%AF%E8%BF%87%E7%A8%8B&quot;&gt;描述目标而不是过程&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/how-to-ask-questions-the-smart-way/#%E5%88%AB%E8%A6%81%E6%B1%82%E7%A7%81%E4%B8%8B%E5%9B%9E%E5%A4%8D%E7%94%B5%E9%82%AE&quot;&gt;别要求私下回复电邮&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/how-to-ask-questions-the-smart-way/#%E6%8F%90%E9%97%AE%E5%BA%94%E6%98%8E%E7%A1%AE&quot;&gt;提问应明确&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/how-to-ask-questions-the-smart-way/#%E5%85%B3%E4%BA%8E%E4%BB%A3%E7%A0%81%E7%9A%84%E9%97%AE%E9%A2%98&quot;&gt;关于代码的问题&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/how-to-ask-questions-the-smart-way/#%E5%88%AB%E5%BC%A0%E8%B4%B4%E5%AE%B6%E5%BA%AD%E4%BD%9C%E4%B8%9A%E5%BC%8F%E9%97%AE%E9%A2%98&quot;&gt;别张贴家庭作业式问题&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/how-to-ask-questions-the-smart-way/#%E5%88%A0%E9%99%A4%E6%97%A0%E6%84%8F%E4%B9%89%E7%9A%84%E8%A6%81%E6%B1%82&quot;&gt;删除无意义的要求&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/how-to-ask-questions-the-smart-way/#%E4%B8%8D%E8%A6%81%E6%8A%8A%E9%97%AE%E9%A2%98%E6%A0%87%E8%AE%B0%E4%B8%BA%E7%B4%A7%E6%80%A5%E5%8D%B3%E4%BD%BF%E5%AF%B9%E4%BD%A0%E8%80%8C%E8%A8%80%E7%9A%84%E7%A1%AE%E5%A6%82%E6%AD%A4&quot;&gt;不要把问题标记为“紧急”，即使对你而言的确如此&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/how-to-ask-questions-the-smart-way/#%E7%A4%BC%E8%B2%8C%E6%80%BB%E6%98%AF%E6%9C%89%E7%9B%8A%E7%9A%84&quot;&gt;礼貌总是有益的&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/how-to-ask-questions-the-smart-way/#%E9%97%AE%E9%A2%98%E8%A7%A3%E5%86%B3%E5%90%8E%E8%BF%BD%E5%8A%A0%E4%B8%80%E6%9D%A1%E7%AE%80%E8%A6%81%E8%AF%B4%E6%98%8E&quot;&gt;问题解决后追加一条简要说明&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/how-to-ask-questions-the-smart-way/#%E5%A6%82%E4%BD%95%E8%A7%A3%E8%AF%BB%E5%9B%9E%E7%AD%94&quot;&gt;如何解读回答&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/how-to-ask-questions-the-smart-way/#%E8%AF%BB%E8%AF%BB%E8%AF%A5%E6%AD%BB%E7%9A%84%E6%89%8B%E5%86%8Crtfm%E5%92%8C%E6%90%9C%E6%90%9C%E8%AF%A5%E6%AD%BB%E7%9A%84%E7%BD%91%E7%BB%9Cstfw%E5%A6%82%E4%BD%95%E6%98%8E%E7%99%BD%E4%BD%A0%E5%B7%B2%E5%AE%8C%E5%85%A8%E6%90%9E%E7%A0%B8&quot;&gt;“读读该死的手册”（RTFM）和“搜搜该死的网络”（STFW）：如何明白你已完全搞砸&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/how-to-ask-questions-the-smart-way/#%E5%A6%82%E6%9E%9C%E8%BF%98%E4%B8%8D%E6%98%8E%E7%99%BD&quot;&gt;如果还不明白……&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/how-to-ask-questions-the-smart-way/#%E5%AF%B9%E5%BE%85%E6%97%A0%E7%A4%BC&quot;&gt;对待无礼&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/how-to-ask-questions-the-smart-way/#%E5%88%AB%E8%B1%A1%E5%A4%B1%E8%B4%A5%E8%80%85%E9%82%A3%E6%A0%B7%E5%8F%8D%E5%BA%94&quot;&gt;别象失败者那样反应&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/how-to-ask-questions-the-smart-way/#%E6%8F%90%E9%97%AE%E7%A6%81%E5%BF%8C&quot;&gt;提问禁忌&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/how-to-ask-questions-the-smart-way/#%E5%A5%BD%E9%97%AE%E9%A2%98%E4%B8%8E%E5%9D%8F%E9%97%AE%E9%A2%98&quot;&gt;好问题与坏问题&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/how-to-ask-questions-the-smart-way/#%E5%A6%82%E6%9E%9C%E5%BE%97%E4%B8%8D%E5%88%B0%E5%9B%9E%E7%AD%94&quot;&gt;如果得不到回答&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/how-to-ask-questions-the-smart-way/#%E5%A6%82%E4%BD%95%E6%9B%B4%E5%A5%BD%E5%9C%B0%E5%9B%9E%E7%AD%94&quot;&gt;如何更好地回答&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/how-to-ask-questions-the-smart-way/#%E7%9B%B8%E5%85%B3%E8%B5%84%E6%BA%90&quot;&gt;相关资源&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/how-to-ask-questions-the-smart-way/#%E9%B8%A3%E8%B0%A2&quot;&gt;鸣谢&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;译文： 印尼语 白俄罗斯语 巴西葡萄牙语 简体中文 荷兰语 法语 乔治亚语 德语 希腊语 希伯来语 日语 波兰语 葡萄牙语 罗马尼亚语 俄语 西班牙语 泰语 如果你想复制、镜像、翻译或引用本文，请参阅我的 复制协议。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;弃权申明&quot;&gt;弃权申明&lt;/h3&gt;
&lt;p&gt;许多项目的网站在如何取得帮助的部分链接了本文，这没有关系，也正是我们想要的。但如果你是该项目生成此链接的网管，请在链接附近显著位置注明：我们不提供该项目的服务支持！&lt;/p&gt;
&lt;p&gt;我们已经领教了没有此说明带来的痛苦，我们将不停地被一些白痴纠缠，他们认为既然我们发布了本文，那么我们就有责任解决世上所有的技术问题。&lt;/p&gt;
&lt;p&gt;如果你是因为需要帮助正在阅读本文，然后就带着可以直接从作者那取得帮助的印象离开，那么 你 就不幸成了我们所说的白痴之一。 别向 我们 提问，我们不会理睬的。 我们只是在这教你如何从那些真正懂得你软硬件问题的人那里取得帮助，但 99.9％ 的时间我们不会是那些人。除非你非常地 确定 本文的作者是你遇到问题方面的专家，请不要打搅，这样大家都更开心一点。&lt;/p&gt;
&lt;h3 id=&quot;引言&quot;&gt;引言&lt;/h3&gt;
&lt;p&gt;在 黑客 的世界里，你所提技术问题的解答很大程度上取决于你提问的方式与解决此问题的难度，本文将教你如何提问才更有可能得到满意的答复。&lt;/p&gt;
&lt;p&gt;开源程序的应用已经很广，你通常可以从其他更有经验的用户而不是黑客那里得到解答。这是好事，他们一般对新手常有的毛病更容忍一点。然尔，使用我们推荐的方法，象对待黑客那样对待这些有经验的用户，通常能最有效地得到问题的解答。&lt;/p&gt;
&lt;p&gt;第一件需要明白的事是黑客喜欢难题和激发思考的好问题。假如不是这样，我们也不会写本文了。如果你能提出一个有趣的问题让我们咀嚼玩味，我们会感激你。好问题是种激励与礼物，帮助我们发展认知，揭示没有注意或想到的问题。在黑客中，“好问题！” 是非常热烈而认真的赞许。&lt;/p&gt;
&lt;p&gt;此外，黑客还有遇到简单问题就表现出敌视或傲慢的名声。有时，我们看起来还对新手和愚蠢的家伙有条件反射式的无礼，但事情并不真是这样。&lt;/p&gt;
&lt;p&gt;我们只是毫无歉意地敌视那些提问前不愿思考、不做自己家庭作业的人。这种人就象时间无底洞──他们只知道索取，不愿意付出，他们浪费了时间，这些时间本可用于其它更有趣的问题或更值得回答的人。我们将这种人叫做 “失败者（loser）” （由于历史原因，我们有时将“loser”拼写为“lusers” 。）&lt;/p&gt;
&lt;p&gt;我们意识到许多人只是想使用我们写的软件，他们对学习技术细节没有兴趣。对大多数人而言，计算机只是种工具，是种达到目的的手段而已。他们有自己的生活并且有更重要的事要做，我们承认这点，也从不指望每个人都对这些让我们着迷的技术问题感兴趣。不过，我们回答问题的风格是为了适应那些真正对此有兴趣并愿意主动参与解决问题的用户，这一点不会变，也不该变。如果连这都变了，我们就会在自己能做得最好的事情上不再那么犀利。&lt;/p&gt;
&lt;p&gt;我们（大多数）是自愿者， 从自己繁忙的生活中抽时间来回答问题，有时会力不从心。因此，我们会毫不留情地滤除问题，特别是那些看起来象是失败者提的，以便更有效地把回答问题的时间留给那些胜利者。&lt;/p&gt;
&lt;p&gt;如果你认为这种态度令人反感、以施惠者自居或傲慢自大，请检查你的假设，我们并未要求你屈服──事实上，假如你做了该做的努力，我们中的大多数将非常乐意平等地与你交流，并欢迎你接纳我们的文化。试图去帮助那些不愿自救的人对我们简直没有效率。不懂没有关系，但愚蠢地做事不行。&lt;/p&gt;
&lt;p&gt;所以，你不必在技术上很在行才能吸引我们的注意，但你 必须 表现出能引导你在行的姿态──机 敏、有想法、善于观察、乐于主动参与问题的解决。如果你做不到这些使你与众不同的事情，我们建议你付钱跟别人签商业服务合同，而不是要求黑客无偿帮助。&lt;/p&gt;
&lt;p&gt;如果你决定向我们求助，你不会想成为一名失败者，你也不想被看成一个失败者。得到快速有效回答的最好方法是使提问者看起来象个聪明、自信和有想法的人，并且暗示只是碰巧在某一特别问题上需要帮助。&lt;/p&gt;
&lt;p&gt;（欢迎对本文指正，可以将建议发至 esr@thyrsus.com 或 respond-auto@linuxmafia.com。 请注意，本文不想成为一般性的 网络礼仪 指南，我一般会拒绝那些与引出技术论坛中有用的回答不特别相关的建议。）&lt;/p&gt;
&lt;h3 id=&quot;提问前&quot;&gt;提问前&lt;/h3&gt;
&lt;p&gt;在通过电邮、新闻组或论坛提技术问题以前，做以下事情：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;尝试在你准备提问论坛的历史文档中搜索答案&lt;/li&gt;
&lt;li&gt;尝试搜索互联网以找到答案&lt;/li&gt;
&lt;li&gt;尝试阅读手册以找到答案&lt;/li&gt;
&lt;li&gt;尝试阅读“常见问题文档”（FAQ）以找到答案&lt;/li&gt;
&lt;li&gt;尝试自己检查或试验以找到答案&lt;/li&gt;
&lt;li&gt;尝试请教懂行的朋友以找到答案&lt;/li&gt;
&lt;li&gt;如果你是程序员，尝试阅读源代码以找到答案&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;提问时，请先表明你已做了上述事情，这将有助于建立你不是寄生虫与浪费别人时间的印象。最好再表述你从中 学到的东西 ，我们喜欢回答那些表现出能从答案中学习的人。&lt;/p&gt;
&lt;p&gt;运用某些策略，比如用谷歌（Google）搜索你遇到的各种错误提示（既搜索 谷歌论坛，也搜索网页）， 这样很可能直接就找到了解决问题的文档或邮件列表线索。 即使没有结果，在邮件列表或新闻组寻求帮助时提一句“我在谷歌中搜过下列句子但没有找到什么有用的东西” 也是件好事，至少它表明了搜索引擎不能提供哪些帮助。将搜索关键词与你的问题及可能的解决方案联系起来，还有助于引导其他有类似问题的人。&lt;/p&gt;
&lt;p&gt;别着急，不要指望几秒钟的谷歌搜索就能解决一个复杂的问题。读一下常见问题文档。在向专家提问之前，先向后靠靠放松一下，再思考一下问题。相信我们，他们能从你的提问看出你做了多少阅读与思考，如果你是有备而来，将更有可能得到解答。不要将所有问题一股脑抛出，只因你的第一次搜索没有结果（或者结果太多）。&lt;/p&gt;
&lt;p&gt;认真地思考，准备好你的问题。轻率的提问只能得到轻率的回答，或者压根没有。在提问时，你越是表现出在此前做过思考与努力去解决自己的问题，你越有可能得到真正的帮助。&lt;/p&gt;
&lt;p&gt;注意别提错问题。如果提问基于错误的假设，某黑客多半会一边想 “愚蠢的问题……”，一边按将错就错的答案回复你，并且希望这种只是得到你自己“问的问题”而非真正所需的解答，给你一个教训。&lt;/p&gt;
&lt;p&gt;永远不要假设你 有资格 得到解答。你没有这种资格，毕竟你没有为此服务付费。如果你能够提出有内容、有趣和激励思考的问题──那种毫无疑问能够向社区贡献经验，而不仅仅是消极地要求从别人那获取知识的问题，你将“挣到”答案。&lt;/p&gt;
&lt;p&gt;另一方面，表明你有能力也乐意参与问题的解决是个很好的开端。“有没有人能指个方向？”，我这还差点什么？”，“我应该查哪个网站？”，通常要比 “请给出我可以用的完整步骤”更容易得到回复，因为你表明了只要有人能指个方向，你就很乐意完成剩下的过程。&lt;/p&gt;
&lt;h3 id=&quot;提问时&quot;&gt;提问时&lt;/h3&gt;
&lt;h4 id=&quot;仔细挑选论坛&quot;&gt;仔细挑选论坛&lt;/h4&gt;
&lt;p&gt;要对在哪提问留心，如果你做了下述事情，多半会被一笔勾销或被看成“失败者”：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;张贴与论坛主题无关的问题&lt;/li&gt;
&lt;li&gt;在面向高级技术问题的论坛上张贴肤浅的问题，或者反之。&lt;/li&gt;
&lt;li&gt;在太多不同的新闻组同时张贴&lt;/li&gt;
&lt;li&gt;给既非熟人也没有义务解决你问题的人发送你私人的电邮&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;为保护通信的渠道不被无关的东西淹没，黑客会除掉那些没有找对地方的问题，你不会想让这种事落到自己头上的。&lt;/p&gt;
&lt;p&gt;因此，第一步是找对论坛。谷歌和其它搜索引擎还是你的朋友，可以用它们搜索你遇到困难的软硬件问题最相关的项目网站。那里通常都有项目的常见问题（FAQ）、邮件列表及文档的链接。如果你的努力（包括 阅读 FAQ）都没有结果，这些邮件列表就是最后能取得帮助的地方。项目的网站也许还有报告Bug的流程或链接，如果是这样，去看看。&lt;/p&gt;
&lt;p&gt;向陌生的人或论坛发送邮件极有可能是在冒险。譬如，不要假设一个内容丰富的网页的作者想充当你的免费顾问，不要对你的问题是否会受到欢迎做太乐观的估计──如果你不确定，向别处发或者压根别发。&lt;/p&gt;
&lt;p&gt;在选择论坛、新闻组或邮件列表时，别太相信名字，先看看 FAQ 或者许可书以明确你的问题是否切题。发贴前先翻翻已有的帖子，这样可以让你感受一下那里行事的方式。事实上，张贴前在新闻组或邮件列表的历史文档中搜索与你问题相关的关键词是个极好的主意，也许就找到答案了。即使没有，也能帮助你归纳出更好的问题。&lt;/p&gt;
&lt;p&gt;别象机关枪似的一次性“扫射”所有的帮助渠道，这就象大喊大叫一样会令人不快，温柔地一个一个来。&lt;/p&gt;
&lt;p&gt;弄懂主题！最典型的错误之一是在某种致立于跨平台可移植的语言、库或工具的论坛中提关于 Unix 或 Windows 操作系统程序接口的问题。如果你不明白为什么这是大错，最好在搞清楚概念前什么也别问。&lt;/p&gt;
&lt;p&gt;一般来说，在仔细挑选的公共论坛中提问比在私有论坛中提同样的问题更容易得到有用的回答。有几个道理支持这点，一是看潜在的回复者有多少，二是看论坛的参与者有多少，黑客更愿回答能启发多数人的问题。&lt;/p&gt;
&lt;p&gt;可以理解，老练的黑客和一些流行软件的作者正在承受过多的不当消息。就象那根最后压垮骆驼背的稻草一样，你的加入也有可能使情况走向极端──已经好几次了，一些流行软件的作者退出了对自己软件的支持，因为伴随而来的涌入其私人邮箱的垃圾邮件变得无法忍受。&lt;/p&gt;
&lt;h4 id=&quot;面向新手的论坛和互联网中继聊天irc通常响应最快&quot;&gt;面向新手的论坛和互联网中继聊天（IRC）通常响应最快&lt;/h4&gt;
&lt;p&gt;本地的用户组织或者你所用的 Linux 发行版也许正在宣传新手取得帮助的论坛或 IRC 通道（在一些非英语国家，新手论坛很可能还是邮件列表），这些地方是开始提问的好去处，特别是当你觉得遇到的也许只是相对简单或者很普通的问题时。经过宣传的 IRC 通道是公开邀请提问的地方，通常可以得到实时的回复。&lt;/p&gt;
&lt;p&gt;事实上，如果出问题的程序来自某发行版（这很常见），最好先去该发行版的论坛或邮件列表中提问，再到程序本身的项目论坛或邮件列表，（否则）该项目的黑客可能仅仅回复“用 我们的 代码”。&lt;/p&gt;
&lt;p&gt;在任何论坛发贴以前，先看看有没有搜索功能。如果有，就试着用问题的几个关键词搜索一下，也许就有帮助。如果在此之前你已做过全面的网页搜索（你应该这样去做），还是再搜索一下论坛，搜索引擎有可能没来得及索引此论坛的全部内容。&lt;/p&gt;
&lt;p&gt;通过论坛或 IRC 通道提供项目的用户支持有增长的趋势，电子邮件交流则更多地为项目开发者保留。所以先在论坛或 IRC 中寻求与该项目相关的帮助。&lt;/p&gt;
&lt;h4 id=&quot;第二步使用项目的邮件列表&quot;&gt;第二步，使用项目的邮件列表&lt;/h4&gt;
&lt;p&gt;当某个项目存在开发者邮件列表时，要向列表而不是其中的个别成员提问，即使你确信能有最好地回答你的问题。查一查项目的文档和主页，找到项目的邮件列表并使用它。采用这种办法有几个很好的理由：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;向个别开发者提的问题（如果）足够好，也将对整个项目组有益。相反，如果你认为自己的问题对整个项目组来说太愚蠢，这也不能成为骚扰个别开发者的理由。&lt;/li&gt;
&lt;li&gt;向列表提问可以分散开发者的负担，个别开发者（尤其是项目领导）也许太忙以至于没法回答你的问题。&lt;/li&gt;
&lt;li&gt;大多数邮件列表都要存档，那些存档将被搜索引擎索引，如果你向列表提问并得到解答，将来其它人可以通过网页搜索找到你的问题和答案，也就不用再次发问了。&lt;/li&gt;
&lt;li&gt;如果某些问题经常被问到，开发者可以利用此信息改进文档或软件本身，以使其更清楚。如果只是私下提问，就没有人能看到最常见问题的完整场景。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果一个项目既有 “用户” 也有“开发者”（或 “黑客”）邮件列表或论坛，而你又不摆弄那些代码，向“用户”列表或论坛提问。不要假设自己会在开发者列表中受到欢迎，那些人多半会遭受你的噪音干扰。&lt;/p&gt;
&lt;p&gt;然尔，如果你 确信 你的问题不一般，而且在“用户” 列表或论坛中几天都没有回复，可以试试“开发者”列表或论坛。建议你在张贴前最好先暗暗地观察几天,至少看看最近几天保存的帖子,以了解那的行事方式（事实上这是参与任何私有或半私有列表的好主意）&lt;/p&gt;
&lt;p&gt;如果你找不到一个项目的邮件列表，而只能查到项目维护者的地址，只管向其发信。即便在这种情况下，也别假设（项目）邮件列表不存在。在你的电子邮件中陈述你已经试过但没有找到合适的邮件列表，也提及你不反对将自己的邮件转发给他人（许多人认为，即使没什么秘密，私人电子邮件也不应该被公开。通过允许将你的电子邮件转发他人，你给了相应人员处置你邮件的选择）。&lt;/p&gt;
&lt;h4 id=&quot;使用有意义且明确的主题&quot;&gt;使用有意义且明确的主题&lt;/h4&gt;
&lt;p&gt;在邮件列表、新闻组或论坛中，主题是你在五十个或更少的字以内吸引有资格专家注意的黄金机会，不要用诸如 “请帮我” （更别提大写的 “请帮我！！！！”，这种主题的消息会被条件反射式地删掉）之类的唠叨浪费机会。不要用你痛苦深度来感动我们，相反，要在这点空间中使用超级简明扼要的问题描述。&lt;/p&gt;
&lt;p&gt;使用主题的好惯例是“对象──偏差”（式的描述），许多技术支持组织就是这样做的。在“对象”部分指明是哪一个或哪一组东西有问题，在“偏差”部分则描述与期望的行为不一致的地方。&lt;/p&gt;
&lt;p&gt;愚蠢：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;救命啊！我的笔记本视频工作不正常！&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;明智：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;X.org 6.8.1 扭曲鼠标光标，MV1005 型号的某显卡芯片组&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;更明智：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;使用 MV1005 型号的某显卡芯片组在 X.org 6.8.1 的鼠标光标被扭曲&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;编写 “对象──偏差”式描述的过程有助于你组织对问题的细致思考。是什么被影响了？仅仅是鼠标光标或者还有其它图形？只在 X.org 中出现？或只是在其 6.8.1 版中？是针对某显卡芯片组？或者只是其中的 MV1005 型号？一个黑客只需描一眼就能够立即明白什么是你遇到的问题，什么是你自己的问题。&lt;/p&gt;
&lt;p&gt;更一般地，想象一下在一个只显示主题的文档索引中查找。让你的主题更好地反映问题，可以使下一个搜索类似问题的人能够在文档中直接就找到答案的线索，而不用再次发贴提问。&lt;/p&gt;
&lt;p&gt;如果你想在回复中提问，确保改变主题以表明你是在问一个问题，一个主题象 &lt;code&gt;Re: 测试&lt;/code&gt; 或者 &lt;code&gt;Re: 新Bug&lt;/code&gt; 的消息不太可能引起足够的注意。同时，将回复中与新主题不甚相关的引用内容尽量删除。&lt;/p&gt;
&lt;p&gt;对于列表消息，不要直接点击回复（按钮）来开始一个全新的线索，这将限制你的观众。有些邮件阅读程序，比如 mutt，允许用户按线索排序并通过折叠线索来隐藏消息，这样做的人永远看不到你发的消息。&lt;/p&gt;
&lt;p&gt;仅仅改变主题还不够。mutt 和其它一些邮件阅读程序还要检查邮件头主题以外的其它信息，以便为其指定线索，所以宁可发一个全新的邮件。&lt;/p&gt;
&lt;p&gt;在论坛，因为消息与特定的线索紧密结合，并且通常在线索之外不可见，好的提问方式略有不同，通过回复提问并不要紧。不是所有论坛都允许在回复中出现分离的主题，而且这样做了基本上没有人会去看。不过，通过回复提问本身就是令人怀疑的做法，因为它们只会被正在查看该线索的人读到。所以，除非你 只想 在该线索当前活跃的人群中提问，还是另起炉灶比较好。&lt;/p&gt;
&lt;h4 id=&quot;使问题容易回复&quot;&gt;使问题容易回复&lt;/h4&gt;
&lt;p&gt;以&lt;code&gt;请向……回复&lt;/code&gt;来结束问题多半会使你得不到回答。如果你觉得花几秒钟在邮件客户端设置一下回复地址都麻烦，我们也觉得花几秒钟考虑你的问题更麻烦。如果你的邮件客户端程序不支持这样做，换个好点的；如果是操作系统不支持所有这种邮件客户端程序，也换个好点的。&lt;/p&gt;
&lt;p&gt;在论坛，要求通过电子邮件回复是完全无礼的，除非你确信回复的信息也许是敏感的（而且有人会为了某些未知的原因，只让你而不是整个论坛知道答案）。如果你只是想在有人回复线索时得到电子邮件提醒，可以要求论坛发送。几乎所有论坛都支持诸如&lt;code&gt;留意本线索&lt;/code&gt;、&lt;code&gt;有回复发送邮件&lt;/code&gt;等功能。&lt;/p&gt;
&lt;h4 id=&quot;用清晰语法拼写正确的语句书写&quot;&gt;用清晰、语法、拼写正确的语句书写&lt;/h4&gt;
&lt;p&gt;经验告诉我们，粗心与草率的作者通常也粗心与草率地思考和编程（我敢打赌）。为这些粗心与草率的思考者回答问题没有好处，我们宁可将时间花在其它地方。&lt;/p&gt;
&lt;p&gt;清楚、良好地表达你的问题非常重要。如果你觉得这样做麻烦，我们也觉得注意（你的问题）麻烦。花点额外的精力斟酌一下字句，用不着太僵硬与正式──事实上，黑客文化很看重能准确地使用非正式、俚语和幽默的语句。但它 必须 很准确，而且有迹象表明你是在思考和关注问题。&lt;/p&gt;
&lt;p&gt;正确地拼写、使用标点和大小写，不要将 &lt;code&gt;its&lt;/code&gt; 混淆为 &lt;code&gt;it&#39;s&lt;/code&gt;，&lt;code&gt;loose&lt;/code&gt; 搞成 &lt;code&gt;lose&lt;/code&gt; 或者将 “discrete” 弄成 “discreet”。不要全部用大写，这会被视为无礼的大声嚷嚷嚷 （全部小写也好不到哪去，因为不易阅读。Alan Cox [注：著名黑客，Linux 内核的重要参与者] 也许可以这样做，但你不行。）&lt;/p&gt;
&lt;p&gt;一般而言，如果你写得象个半文盲似的傻子，多半得不到理睬。也不要使用即时通讯中的简写，如将 &lt;code&gt;you&lt;/code&gt; 简化为 &lt;code&gt;u&lt;/code&gt; 会使你看起来象一个为了节约二次击键的半文盲式的傻子。更糟的是，如果象个小孩似地鬼画桃符那绝对是在找死，可以肯定没人会理你（或者最多是给你一大堆指责与挖苦）。&lt;/p&gt;
&lt;p&gt;如果在非母语论坛提问，你的拼写与语法错误会得到有限的宽容，但懒惰完全不会被容忍（是的，我们通常看得出其中的差别）。同时，除非你知道回复者使用的语言，请使用英语书写。繁忙的黑客一般会直接删除用他们看不懂语言写的消息。在互联网上英语是工作语言，用英语书写可以将你的问题不被阅读就被直接删除的可能性降到最低。&lt;/p&gt;
&lt;p&gt;如果你用英语书写但它是你的第二语言，最好提醒潜在的回复者语言上可能的困难以便绕过这个问题，比如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;英语不是我的母语，请谅解拼写错误。&lt;/li&gt;
&lt;li&gt;如果您使用某某语言，请电邮/私聊我，也许我需要您的协助翻译我的问题。&lt;/li&gt;
&lt;li&gt;对于这个技术术语本身我很熟悉，但对于它的一些俚语或习惯表达方式就不太明白了。&lt;/li&gt;
&lt;li&gt;我已经同时用某某语及英语提问，如果您使用两者之一回复，我很乐意翻译。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;使用易于读取且标准的文件格式发送问题&quot;&gt;使用易于读取且标准的文件格式发送问题&lt;/h4&gt;
&lt;p&gt;如果你人为地将问题搞得难以阅读，它多半会被忽略，人们更愿读易懂的问题，所以：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;使用纯文本而不是 HTML（超文本标注语言）（ 关闭HTML 并不难）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;使用 MIME（多用途互联网邮件扩展）附件通常没有问题，前提是真正有内容（譬如附带的源文件或补丁），而不仅仅是邮件客户端程序生成的模板（譬如只是消息内容的拷贝）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;不要发送整段只是单行句子但多次折回的邮件（这使得回复部分内容非常困难）。设想你的读者是在80个字符宽的文本终端阅读邮件，设置你的行折回点小于 80 列。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;但是，也 不要 用任何固定列折回数据（譬如日志文件拷贝或会话记录）。数据应该原样包含，使回复者确信他们看到的是与你看到的一样的东西。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在英语论坛中，不要使用’Quoted-Printable’ MIME 编码发送消息。这种编码对于张贴非 ASCII 语言可能是必须的，但很多邮件程序并不支持。当它们分断时，那些文本中四处散布的 “=20”符号既难看也分散注意力， even 有可能破坏内容的语意。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;永远不要 指望黑客们阅读使用封闭的专用格式编写的文档，诸如微软公司的 Word 或 Excel 文件等。大多数黑客对此的反应就象有人将还在冒热气的猪粪倒在你门口时你的反应一样。即使他们能够处理，也很厌恶这么做。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果你从使用视窗的电脑发送电子邮件，关闭问题颇多的微软“聪明引用”功能（在“工具” -&amp;gt; “自动纠正选项”的“输入时自动格式化”下去掉聪明引用的选框），以免在你的邮件中到处散布垃圾字符。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在论坛，勿滥用“表情符号”和“HTML”功能(当它们提供时)。一两个表情符号通常没有问题，但花哨的彩色文本倾向于使人认为你是个无能之辈。过滥地使用表情符号、色彩和字体会使你看来象个傻笑的小姑娘。这通常不是个好主意，除非你只是对性而不是有用的回复更有兴趣。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果你使用图形用户界面的邮件客户端程序(如网景公司的 Messenger、微软公司的 Outlook 或者其它类似的)，注意它们的缺省配置不一定满足这些要求。大多数这类程序有基于菜单的&lt;code&gt;查看源码&lt;/code&gt;命令，用它来检查发送文件夹中的消息，以确保发送的是没有多余杂质的纯文本文件。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;描述问题应准确且有内容&quot;&gt;描述问题应准确且有内容&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;仔细、清楚地描述问题的症状&lt;/li&gt;
&lt;li&gt;描述问题发生的环境(主机、操作系统、应用程序，任何相关的)，提供销售商的发行版和版本号（如：“Fedora Core 7”、“Slackware 9.1”等）&lt;/li&gt;
&lt;li&gt;描述提问前做过的研究及其理解。&lt;/li&gt;
&lt;li&gt;描述提问前为确定问题而采取的诊断步骤。&lt;/li&gt;
&lt;li&gt;描述最近对计算机或软件配置的任何相关改变。&lt;/li&gt;
&lt;li&gt;如果可能，提供在可控环境下重现问题的方法。&lt;/li&gt;
&lt;li&gt;尽最大努力预测黑客会提到的问题，并提前备好答案。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果你认为是代码有问题，向黑客提供在可控环境下重现问题的方法尤其重要。当你这么做时，得到有用且及时回复的可能性将大大增加。&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http://www.chiark.greenend.org.uk/%7Esgtatham/&quot;&gt;西蒙.泰瑟姆（Simon Tatham）&lt;/a&gt;写过一篇《&lt;a rel=&quot;external&quot; href=&quot;http://www.chiark.greenend.org.uk/%7Esgtatham/bugs-tw.html&quot;&gt;如何有效报告Bug》&lt;/a&gt;的文章，我强烈推荐各位阅读。&lt;/p&gt;
&lt;h4 id=&quot;量不在多精炼则灵&quot;&gt;量不在多，精炼则灵&lt;/h4&gt;
&lt;p&gt;你应该（写得）精炼且有内容，简单地将一大堆代码或数据罗列在求助消息中达不到目的。如果你有一个很大且复杂的测试样例让程序崩溃，尝试将其裁剪得越小越好。&lt;/p&gt;
&lt;p&gt;至少有三个理由支持这点。第一，让别人看到你在努力简化问题使你更有可能得到回复。第二，简化问题使你更有可能得到 &lt;code&gt;有用的&lt;/code&gt; 回复。第三，在提纯Bug报告的过程中，你可能自己就找到了解决办法或权宜之计。&lt;/p&gt;
&lt;h4 id=&quot;别急于宣称找到Bug&quot;&gt;别急于宣称找到Bug&lt;/h4&gt;
&lt;p&gt;当你在一个软件中遇到问题，除非你 非常、非常 的有根据，不要动辄声称找到了Bug。提示：除非我能提供解决问题的源代码补丁，或者对前一版本的回归测试表现出不正确的行为，否则你都多半不够完全确信。对于网页和文档也如此，如果你（声称）发现了文档的“Bug”，你应该能提供相应位置的替代文本。&lt;/p&gt;
&lt;p&gt;记住，还有许多其它用户并未经历你遇到的问题，否则你在阅读文档或搜索网页时就应该发现了（&lt;a href=&quot;https://scp.net.cn/blog/how-to-ask-questions-the-smart-way/#%E6%8F%90%E9%97%AE%E5%89%8D&quot;&gt;你在报怨前已经做了这些，是吧 ？&lt;/a&gt;）。这也意味着很有可能是你弄错了而不是软件本身有问题。&lt;/p&gt;
&lt;p&gt;编写软件的人总是非常辛苦地使它尽可能完美。如果你声称找到了Bug，也就置疑了他们的能力，即使你是对的，也有可能会使其中的部分人感到不快。（此外，）在主题中嚷嚷“Bug”也是特别不老练的。&lt;/p&gt;
&lt;p&gt;提问时，即使你私下非常确信已经发现一个真正的Bug，最好写得象是 你 做错了什么。如果真的有Bug，你会在回复中看到这点。这样做的话，如果真有虫子，维护者就会向你道歉，这总比你弄砸了然后欠别人一个道歉要强。&lt;/p&gt;
&lt;h4 id=&quot;低声下气代替不了做自己的家庭作业&quot;&gt;低声下气代替不了做自己的家庭作业&lt;/h4&gt;
&lt;p&gt;有些人明白他们不应该粗鲁或傲慢地行事并要求得到答复，但他们退到相反的低声下气的极端：“我知道我只是个可怜的新丁，一个失败者，但……”。这既使人困扰，也没有用，当伴随着对实际问题含糊的描述时还特别令人反感。&lt;/p&gt;
&lt;p&gt;别用低级灵长类动物的办法浪费你我的时间，相反，尽可能清楚地描述背景情况和你的问题，这比低声下气更好地摆正了你的位置。&lt;/p&gt;
&lt;p&gt;有时，论坛设有单独的初学者提问版面，如果你真的认为遇到了肤浅的问题，到那去就是了，但一样别低声下气。&lt;/p&gt;
&lt;h4 id=&quot;描述问题症状而不是猜测&quot;&gt;描述问题症状而不是猜测&lt;/h4&gt;
&lt;p&gt;告诉黑客是什么导致了问题是没用的（如果你的诊断理论是了不起的东西，你还会向别人咨询求助吗？）。所以，确保只是告诉他们问题的原始症状，而不是你的解释和理论，让他们来解释和诊断。如果你认为陈述自己的猜测很重要，应清楚地说明这只是你的猜测并描述为什么它们不起作用。&lt;/p&gt;
&lt;p&gt;愚蠢：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我在编译内核时接连遇到 SIG11 错误，怀疑主板上的某根电路丝断了，找到它们的最好办法是什么？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;明智：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我组装的电脑（K6/233 CPU、FIC-PA2007 主板[威盛 Apollo VP2 芯片组]、Corsair PC133 SDRAM 256Mb 内存）最近在开机 20 分钟左右、做内核编译时频繁地报 SIG11 错，但在头 20 分钟内从不出问题。重启动不会复位时钟，但整夜关机会。更换所有内存未解决问题，相关的典型编译会话日志附后。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;由于以上这点许多人似乎难以掌握，这里有句话可以提醒你：“所有的诊断专家都来自密苏里州”。美国国务院的官方座右铭则是“让我看看”（出自国会议员威勒德.D.范迪弗［Willard D. Vandiver］在1899年时的讲话：“我来自一个出产玉米、棉花、牛蒡和民主党人的国家，滔滔雄辩既不能说服我，也不会让我满意。我来自密苏里州，你必须让我看看。”）针对诊断者而言，这并不是怀疑，而只是一种真实而有用的需求，以便让学生看到与你看到的原始证据尽可能一致的东西，而不是你的猜测与总结。（所以，）让我们看看。&lt;/p&gt;
&lt;h4 id=&quot;按时间先后罗列问题症状&quot;&gt;按时间先后罗列问题症状&lt;/h4&gt;
&lt;p&gt;刚出问题之前发生的事情通常包含有解决问题最有效的线索。所以，记录中应准确地描述你、电脑和软件在崩溃前都做了什么。在命令行处理的情况下，有会话日志（如运行脚本工具生成的）并引用相关的若干（如20）行记录会非常有帮助。&lt;/p&gt;
&lt;p&gt;如果崩溃的程序有诊断选项（如-v详述开关），试着选择这些能在记录中增加排错信息的选项。记住，“多”不等于“好”。试着选取适当的排错级别以便提供有用的信息而不是将阅读者淹没在垃圾中。&lt;/p&gt;
&lt;p&gt;如果你的记录很长（如超过四段），在开头简述问题随后按时间先后罗列详细过程也许更有用。这样，黑客在读你的记录时就知道该注意哪些内容了。&lt;/p&gt;
&lt;h4 id=&quot;描述目标而不是过程&quot;&gt;描述目标而不是过程&lt;/h4&gt;
&lt;p&gt;如果你想弄清楚如何做某事（而不是报告一个Bug），在开头就描述你的目标，然后才陈述遇到问题的特定步骤。&lt;/p&gt;
&lt;p&gt;经常出现这种情况，寻求技术帮助的人在脑袋里有个更高层次的目标，他们在自以为能达到目标的特定道路上被卡住了，然后跑来问该怎么走，但没有意识到这条路本身有问题，结果要费很大的劲才能通过。&lt;/p&gt;
&lt;p&gt;愚蠢：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我怎样才能让某图形程序的颜色拾取器取得十六进制的 RGB 值？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;明智：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我正试着用自己选定数值的颜色替换一幅图片的色表，我现在知道的唯一方法是编辑每个表槽，但却无法让某图形程序的颜色拾取器取得十六进制的 RGB 值。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;第二种提法是明智的，它使得建议采用更合适的工具以完成任务的回复成为可能。&lt;/p&gt;
&lt;h4 id=&quot;别要求私下回复电邮&quot;&gt;别要求私下回复电邮&lt;/h4&gt;
&lt;p&gt;黑客们认为问题的解决过程应该公开、透明，此过程中如果更有才能的人注意到不完整或者不当之处，最初的回复才能够、也应该被纠正。同时，作为回复者也因为能力和学识被其它同行看到而得到某种回报。&lt;/p&gt;
&lt;p&gt;当你要求私下回复时，此过程和回报都被中止。别这样做，让 回复者 来决定是否私下回答──如果他真这么做了，通常是因为他认为问题编写太差或者太肤浅，以至于对其它人毫无意义。&lt;/p&gt;
&lt;p&gt;对这条规则存在一条有限的例外，如果你确信提问可能会引来大量雷同的回复时，那么“向我发电邮，我将为论坛归纳这些回复”将是神奇的句子。试着将邮件列表或新闻组从洪水般雷同的回复中解救出来是非常有礼貌的──但你必须信守诺言。&lt;/p&gt;
&lt;h4 id=&quot;提问应明确&quot;&gt;提问应明确&lt;/h4&gt;
&lt;p&gt;漫无边际的问题通常也被视为没有明确限制的时间无底洞。最有可能给你有用答案的人通常也是最忙的人（假如只是因为他们承担了太多工作的话），这些人对于没有止境的时间无底洞极其敏感，所以他们也倾向于讨厌那些漫无边际的问题。&lt;/p&gt;
&lt;p&gt;如果你明确了想让回复者做的事（如指点方向、发送代码、检查补丁或其它），你更有可能得到有用的回复。（因为）这样可以让学生集中精力并间接地设定了他们为帮助你需要花费的时间和精力上限，这很好。&lt;/p&gt;
&lt;p&gt;要想理解专家生活的世界，可以这样设想：那里有丰富的专长资源但稀缺的响应时间。你暗中要求他们奉献的时间越少，你越有可能从这些真正懂行也真正很忙的专家那里得到解答。&lt;/p&gt;
&lt;p&gt;所以限定你的问题以使专家回答时需要付出的时间最少──这通常与简化问题还不太一样。举个例，“请问可否指点一下哪有好一点的 X 解释？”通常要比“请解释一下 X”明智。如果你的代码不运行了，通常请别人看看哪有问题比叫他们帮你改正更明智。&lt;/p&gt;
&lt;h4 id=&quot;关于代码的问题&quot;&gt;关于代码的问题&lt;/h4&gt;
&lt;p&gt;别要求他人给你出问题的代码排错而不提及应该从何入手。张贴几百行的代码，然后说一声“它不能运行”会让你得不到理睬。只贴几十行代码，然后说一句“在第七行以后，本应该显示&lt;x&gt;，但实际出现的是&lt;y&gt;”非常有可能让你得到回复。&lt;/p&gt;
&lt;p&gt;最精确描述代码问题的方法是提供一个能展示问题的最小测试样例。什么是最小测试样例？它是对问题的展现，只需要刚好能够重现非预期行为的代码即可。如何生成一个最小测试样例？如果你知道哪一行或哪一段代码会产生问题，将其复制并提供刚好够用的外围支撑代码以构成一个完整的样例（够用是指源码刚好能被编译器、解释器或任何处理它的程序所接受）。如果你不能将问题缩小到特定的段落，复制源码并去除那些与问题无关的代码段。你能提供的最小测试样例越小越好（参见 量不在多，精炼则灵 ）。&lt;/p&gt;
&lt;p&gt;生成一个非常小的最小测试样例并不总是可能，但尽力去做是很好的锻练，这有可能帮助你找到需要自己解决的问题。即使你找不到，黑客们喜欢看到你努力过，这将使他们更合作。&lt;/p&gt;
&lt;p&gt;如果你只是想让别人帮忙审一下代码，在最开头就要说出来，并且一定要提到你认为哪一部分特别需要关注以及为什么。&lt;/p&gt;
&lt;h4 id=&quot;别张贴家庭作业式问题&quot;&gt;别张贴家庭作业式问题&lt;/h4&gt;
&lt;p&gt;黑客们善于发现“家庭作业”式的问题。我们中的大多数人已经做了自己的家庭作业，那是该 你 做的，以便从中学到东西。问一下提示没有关系，但不是要求完整的解决方案。&lt;/p&gt;
&lt;p&gt;如果你怀疑自己碰到了一个家庭作业式的问题，但仍然无法解决，试试在用户组、论坛或（作为最后一招）在项目的“用户”邮件列表或论坛中提问。尽管黑客们会看出来，一些老用户也许仍会给你提示。&lt;/p&gt;
&lt;h4 id=&quot;删除无意义的要求&quot;&gt;删除无意义的要求&lt;/h4&gt;
&lt;p&gt;抵制这种诱惑，即在求助消息末尾加上诸如“有人能帮我吗？”或“有没有答案？”之类在语义上毫无意义的东西。第一，如果问题描述还不完整，这些附加的东西最多也只能是多余的。第二，因为它们是多余的，黑客们会认为这些东西烦人──就很有可能用逻辑上无误但打发人的回复，诸如“是的，你可以得到帮助”和“不，没有给你的帮助”。&lt;/p&gt;
&lt;p&gt;一般来说，避免提“是或否”类型的问题，除非你想得到 “是或否”类型的回答。&lt;/p&gt;
&lt;h4 id=&quot;不要把问题标记为紧急即使对你而言的确如此&quot;&gt;不要把问题标记为“紧急”，即使对你而言的确如此&lt;/h4&gt;
&lt;p&gt;这是你的问题，不要我们的。宣称“紧急”极有可能事与愿违：大多数黑客会直接删除这种消息，他们认为这是无礼和自私地企图得到即时与特殊的关照。而且“紧急”或其它有类似含义的主题有可能触发垃圾过滤规则，潜在的回复者可能永远看不到你的问题！&lt;/p&gt;
&lt;p&gt;有一点点局部的例外，如果你是在一些知名度很高、会使黑客们激动的地方使用程序，也许值得这样去做。在这种情况下，如果你有期限压力，也很有礼貌地提到这点，人们也许会有足够的兴趣快一点回答。&lt;/p&gt;
&lt;p&gt;当然，这是非常冒险的，因为黑客们对什么是令人激动的标准多半与你的不同。譬如从国际空间站这样张贴没有问题，但代表感觉良好的慈善或政治原因这样做几乎肯定不行。事实上，张贴诸如“紧急：帮我救救这个毛绒绒的小海豹！”肯定会被黑客回避或光火，即使他们认为毛绒绒的小海豹很重要。&lt;/p&gt;
&lt;p&gt;如果你觉得这不可思议，再把剩下的内容多读几遍，直到弄懂了再发贴也不迟。&lt;/p&gt;
&lt;h4 id=&quot;礼貌总是有益的&quot;&gt;礼貌总是有益的&lt;/h4&gt;
&lt;p&gt;礼貌一点，使用 &lt;code&gt;请&lt;/code&gt; 和 &lt;code&gt;谢谢你的关注&lt;/code&gt; 或者 &lt;code&gt;谢谢你的关照&lt;/code&gt;，让别人明白你感谢他们无偿花时间帮助你。&lt;/p&gt;
&lt;p&gt;坦率地讲，这一点没有语法正确、文字清晰、准确、有内容和避免使用专用格式重要（同时也不能替代它们）。黑客们一般宁可读有点唐突但技术鲜明的Bug报告，而不是那种有礼但含糊的报告。（如果这点让你不解，记住我们是按问题能教我们什么来评价它的）&lt;/p&gt;
&lt;p&gt;然尔，如果你已经谈清楚了技术问题，客气一点肯定会增加你得到有用回复的机会。&lt;/p&gt;
&lt;p&gt;（我们必须指出，本文唯一受到一些老黑客认真反对的地方是以前曾经推荐过的“提前谢了”，一些黑客认为这隐含着事后不用再感谢任何人的暗示。我们的建议是要么先说 &lt;code&gt;提前谢了&lt;/code&gt;，事后再 对回复者表示感谢，要么换种方式表达，譬如用 &lt;code&gt;谢谢你的关注&lt;/code&gt; 或 &lt;code&gt;谢谢你的关照&lt;/code&gt;）。&lt;/p&gt;
&lt;h4 id=&quot;问题解决后追加一条简要说明&quot;&gt;问题解决后追加一条简要说明&lt;/h4&gt;
&lt;p&gt;问题解决后向所有帮助过的人追加一条消息，让他们知道问题是如何解决的并再次感谢。如果问题在邮件列表或新闻组中受到广泛关注，在那里追加此消息比较恰当。&lt;/p&gt;
&lt;p&gt;最理想的方式是向最初提问的线索回复此消息，并在主题中包含 &lt;code&gt;已解决&lt;/code&gt;、&lt;code&gt;已搞定&lt;/code&gt; 或其它同等含义的明显标记。人在人往的邮件列表里，一个看见线索 &lt;code&gt;问题 X&lt;/code&gt; 和 &lt;code&gt;问题 X-已解决&lt;/code&gt; 的潜在回复者就明白不用再浪费时间了（除非他个人觉得“问题 X”有趣），因此可以利用此时间去解决其它问题。&lt;/p&gt;
&lt;p&gt;追加的消息用不着太长或太复杂，一句简单的“你好──是网线坏了！谢谢大家──比尔”就比什么都没有要强。事实上，除非解决问题的技术真正高深，一条简短而亲切的总结比长篇大论要好。说明是什么行动解决了问题，用不着重演整个排错的故事。&lt;/p&gt;
&lt;p&gt;对于有深度的问题，张贴排错历史的摘要是恰当的。描述问题的最终状态，说明是什么解决了问题，在此之后 才指明可以避免的弯路。应避免的弯路部分应放在正确的解决方案和其它总结材料之后，而不要将此消息搞成侦探推理小说。列出那些帮助过你的名字，那样你会交到朋友的。&lt;/p&gt;
&lt;p&gt;除了有礼貌、有内容以外，这种类型的追帖将帮助其他人在邮件列表、新闻组或论坛文档中搜索到真正解决你问题的方案，从而也让他们受益。&lt;/p&gt;
&lt;p&gt;最后，此类追帖还让每位参与协助的人因问题的解决而产生一种满足感。如果你自己不是技术专家或黑客，相信我们，这种感觉对于你寻求帮助的老手和专家是非常重要的。问题叙述到最后不知所终总是令人沮丧的，黑客们痒痒地渴望它们被解决。&lt;code&gt;挠痒痒&lt;/code&gt; 为你挣到的信誉将对你下次再次张贴提问非常非常的有帮助。&lt;/p&gt;
&lt;p&gt;考虑一下怎样才能避免他人将来也遇到类似的问题，问问自己编一份文档或 FAQ 补丁会不会有帮助，如果是的话就将补丁发给维护者。&lt;/p&gt;
&lt;p&gt;在黑客中，这种良好的后继行动实际上比传统的礼貌更重要，也是你善待他人而赢得声誉的方式，这是非常有价值的财富。&lt;/p&gt;
&lt;h3 id=&quot;如何解读回答&quot;&gt;如何解读回答&lt;/h3&gt;
&lt;h4 id=&quot;读读该死的手册rtfm和搜搜该死的网络stfw如何明白你已完全搞砸&quot;&gt;“读读该死的手册”（RTFM）和“搜搜该死的网络”（STFW）：如何明白你已完全搞砸&lt;/h4&gt;
&lt;p&gt;有一个古老而神圣的传统：如果你收到 &lt;code&gt;读读该死的手册&lt;/code&gt;（RTFM） 的回复，发信人认为你应该去“读读该死的手册”。他或她多半是对的，去读一下吧。&lt;/p&gt;
&lt;p&gt;“读读该死的手册”（RTFM）有个年轻一点的亲戚，如果你收到“搜搜该死的网络”（STFW）的回复，发信人认为你应该“搜搜该死的网络”。那人多半也是对的，去搜一下吧。(更温和一点的说法是“&lt;a rel=&quot;external&quot; href=&quot;http://lmgtfy.com/&quot;&gt;谷歌是你的朋友！&lt;/a&gt;”)&lt;/p&gt;
&lt;p&gt;在论坛，你也可能被要求去搜索论坛的文档。事实上，有人甚至可能热心地为你提供以前解决此问题的线索。但不要依赖这种关照，提问前应该先搜索一下文档。&lt;/p&gt;
&lt;p&gt;通常，叫你搜索的人已经打开了能解决你问题的手册或网页，正在一边看一边敲键盘。这些回复意味着他认为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;第一，你要的信息很容易找到。&lt;/li&gt;
&lt;li&gt;第二，自已找要比别人喂到嘴里能学得更多。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;你不应该觉得这样就被冒犯了，按黑客的标准，回复者没有不理你就是在向你表示某种尊敬，你反而应该感谢他热切地想帮助你。&lt;/p&gt;
&lt;h4 id=&quot;如果还不明白&quot;&gt;如果还不明白……&lt;/h4&gt;
&lt;p&gt;如果你看不懂回答，不要马上回复一个要求说明的消息，先试试那些最初提问时用过的相同工具（如手册、FAQ、网页、懂行的朋友等）试着搞懂回答。如果还是需要说明，展现你已经明白的。&lt;/p&gt;
&lt;p&gt;譬如，假如我告诉你：“看起来象是某输入项有问题，你需要清除它”，接着是个 不好 的回帖：“什么是某输入项？”。而这是一个 很好 的跟帖：“是的，我读了手册，某某输入项只在 -z 和 -p 开关中被提到，但都没有涉及到如何清除它们，你指的是哪一个还是我弄错了什么？”&lt;/p&gt;
&lt;h4 id=&quot;对待无礼&quot;&gt;对待无礼&lt;/h4&gt;
&lt;p&gt;很多黑客圈子中看似无礼的行为并不是存心冒犯。相反，它是直接了当、一针见血式的交流风格，这种风格对于更关注解决问题而不是使别人感觉舒服而混乱的人是很自然的。&lt;/p&gt;
&lt;p&gt;如果你觉得被冒犯了，试着平静地反应。如果有人真的做了过格的事，邮件列表、新闻组或论坛中的前辈多半会招呼他。如果这 没有 发生而你却光火了，那么你发火对象的言语可能在黑客社区中看起来是正常的，而 你 将被视为有错的一方，这将伤害到你获取信息或帮助的机会。&lt;/p&gt;
&lt;p&gt;另一方面，你会偶而真的碰到无礼和无聊的言行。与上述相反，对真正的冒犯者狠狠地打击、用犀利的语言将其驳得体无完肤都是可以接受的。然尔，在行事之前一定要非常非常的有根据。纠正无礼的言论与开始一场毫无意义的口水战仅一线之隔，黑客们自己莽撞地越线的情况并不鲜见。如果你是新手或外来者，避开这种莽撞的机会并不高。如果你想得到的是信息而不是消磨时光，这时最好不要把手放在键盘上以免冒险。&lt;/p&gt;
&lt;p&gt;（有些人断言很多黑客都有轻度的自闭症或阿斯伯格综合症，缺少用于润滑人类社会“正常”交往所需的脑电路。这既可能是真也可能是假。如果你自己不是黑客，兴许你认为我们脑袋有问题还能帮助你应付我们的古怪行为。只管这么干好了，我们不在乎。我们 喜欢 现在这个样子，并且一般都对病号标记有站得住脚的怀疑。）&lt;/p&gt;
&lt;p&gt;在下一节，我们会谈到另一个问题，当 你 行为不当时会受到的“冒犯”。&lt;/p&gt;
&lt;h3 id=&quot;别象失败者那样反应&quot;&gt;别象失败者那样反应&lt;/h3&gt;
&lt;p&gt;在黑客社区的论坛中有那么几次你可能会搞砸──以本文描述或类似的方式。你会被示众是如何搞砸的，也许言语中还会带点颜色。&lt;/p&gt;
&lt;p&gt;这种事发生以后，我们能做的最糟糕的事莫过于哀嚎你的遭遇、宣称被口头攻击、要求道歉、高声尖叫、憋闷气、威胁诉诸法律、向其雇主报怨、忘了关马桶盖等等。相反，你该这样去做：&lt;/p&gt;
&lt;p&gt;熬过去，这很正常。事实上，它是有益健康与恰当的。&lt;/p&gt;
&lt;p&gt;社区的标准不会自己维持，它们是通过参与者积极而 公开 地执行来维持的。不要哭嚎所有的批评都应该通过私下的邮件传送，这不是事情运作的方式。当有人评论你的一个说法有误或者提出不同看法时，坚持声称受到个人攻击也毫无益处，这些都是失败者的态度。&lt;/p&gt;
&lt;p&gt;也有其它的黑客论坛，受过高礼节要求的误导，禁止参与者张贴任何对别人帖子挑毛病的消息，并声称“如果你不想帮助用户就闭嘴”。有思路的参与者纷纷离开的结果只会使它们变成了毫无意义的唠叨与无用的技术论坛。&lt;/p&gt;
&lt;p&gt;是夸张的“友谊”（以上述方式）还是有用？挑一个。&lt;/p&gt;
&lt;p&gt;记着：当黑客说你搞砸了，并且(无论多么刺耳地)告诉你别再这样做时，他正在为关心你和他的社区而行动。对他而言，不理你并将你从他的生活中滤除要容易得多。如果你无法做到感谢，至少要有点尊严，别大声哀嚎，也别因为自己是个有戏剧性超级敏感的灵魂和自以为有资格的新来者，就指望别人象对待脆弱的洋娃娃那样对你。&lt;/p&gt;
&lt;p&gt;有时候，即使你没有搞砸（或者只是别人想象你搞砸了）， 有些人也会无缘无故地攻击你本人。在这种情况下，报怨倒是 真的 会把问题搞砸。&lt;/p&gt;
&lt;p&gt;这些找茬者要么是毫无办法但自以为是专家的不中用家伙，要么就是测试你是否真会搞砸的心理专家。其它读者要么不理睬，要么用自己的方式对付他们。这些找茬者在给自己找麻烦，这点你不用操心。&lt;/p&gt;
&lt;p&gt;也别让自己卷入口水战，大多数口水战最好不要理睬──当然，是在你核实它们只是口水战、没有指出你搞砸的地方，而且没有巧妙地将问题真正的答案藏于其中之后（这也是可能的）。&lt;/p&gt;
&lt;h3 id=&quot;提问禁忌&quot;&gt;提问禁忌&lt;/h3&gt;
&lt;p&gt;下面是些典型的愚蠢问题和黑客不回答它们时的想法。&lt;/p&gt;
&lt;p&gt;问：我到哪可以找到某程序或 X 资源？&lt;/p&gt;
&lt;p&gt;问：我怎样用 X 做 Y？&lt;/p&gt;
&lt;p&gt;问：如何配置我的 shell 提示？&lt;/p&gt;
&lt;p&gt;问：我可以用 Bass-o-matic 文件转换工具将 AcmeCorp 文档转为 TeX 格式吗？&lt;/p&gt;
&lt;p&gt;问：我的{程序、配置、SQL 语句}不运行了&lt;/p&gt;
&lt;p&gt;问：我的视窗电脑出问题了，你能帮忙吗？&lt;/p&gt;
&lt;p&gt;问：我的程序不运行了，我认为系统工具X有问题&lt;/p&gt;
&lt;p&gt;问：我安装 Linux 或 X 遇到困难，我能帮忙吗？&lt;/p&gt;
&lt;p&gt;问：我如何才能破解超级用户口令/盗取通道操作员的特权/查看某人的电子邮件？&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;问：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我到哪可以找到某程序或 X 资源？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;答：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;在我找到它的同样地方，笨旦──在网页搜索引擎上。上帝啊，难道还有人不知道如何使用 谷歌 吗？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;问：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我怎样用 X 做 Y？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;答：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;如果你想解决的是 Y，提问时别给出可能并不恰当的方法。这种问题说明提问者不但对 X 完全无知，也对要解决的 Y 问题糊涂，还被特定形势禁锢了思维。等他们把问题弄好再说。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;问：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;如何配置我的 shell 提示？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;答：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;如果你有足够的智慧提这个问题，你也该有足够的智慧去 “读读该死的手册”（RTFM），然后自己去找出来。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;问：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我可以用 Bass-o-matic 文件转换工具将 AcmeCorp 文档转为 TeX 格式吗？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;答：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;试试就知道了。如果你试过，你既知道了答案，又不用浪费我的时间了。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;问：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我的{程序、配置、SQL 语句}不运行了&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;答：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这不是一个问题，我也没有兴趣去猜你有什么问题──我有更要紧的事要做。看到这种东西，我的反应一般如下：&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;你还有什么补充吗？&lt;/li&gt;
&lt;li&gt;噢，太糟了，希望你能搞定。&lt;/li&gt;
&lt;li&gt;这跟我究竟有什么关系？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;问：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我的视窗电脑出问题了，我能帮忙吗？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;答：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;是的，把视窗垃圾删了，装个象 Linux 或 BSD 的开源操作系统吧。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;注意：如果程序有官方的视窗版或者与视窗有交互(如 Samba)，你 可以 问与视窗相关的问题，只是别对问题是由视窗操作系统而不是程序本身造成的回复感到惊讶，因为视窗一般来说太差，这种说法一般都成立。&lt;/p&gt;
&lt;p&gt;问：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我的程序不运行了，我认为系统工具 X 有问题&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;答：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;你完全有可能是第一个注意到被成千上万用户反复使用的系统调用与库文件有明显缺陷的人，更有可能的是你完全没有根据。不同凡响的说法需要不同凡响的证据，当你这样声称时，你必须有清楚而详尽的缺陷说明文档作后盾。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;问：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我安装 Linux 或 X 遇到困难，我能帮忙吗？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;答：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;不行，我需要亲手操作你的电脑才能帮你排错，去向当地的 Linux 用户组寻求方便的帮助（你可以在 这里 找到用户组列表）&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;注意：如果安装问题与某 Linux 发行版有关，在针对 它 的邮件列表、论坛或本地用户组织中提问也许是恰当的。此时，应描述问题的准确细节。在此之前，先用 “linux”和 所有 被怀疑的硬件 [作关键词] 仔细搜索。&lt;/p&gt;
&lt;p&gt;问：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我如何才能破解超级用户口令/盗取通道操作员的特权/查看某人的电子邮件？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;答：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;想做这种事情说明你是个卑劣的家伙，想让黑客教你做这种事情说明你是个白痴。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id=&quot;好问题与坏问题&quot;&gt;好问题与坏问题&lt;/h4&gt;
&lt;p&gt;最后，我将通过举例来演示提问的智慧。同样的问题两种提法，一种愚蠢，另一种明智。&lt;/p&gt;
&lt;p&gt;愚蠢：我在哪能找到关于 Foonly Flurbamatic 设备的东西？&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这个问题在乞求得到 “搜搜该死的网络”（STFW） 式的回复。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;明智： 我用谷歌搜索过“Foonly Flurbamatic 2600”，但没有找到什么有用的，有谁知道在哪能找到这种设备的编程信息？&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这个人已经搜索过网络了，而且听起来他可能真的遇到了问题。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;愚蠢： 我不能编译某项目的源代码，它为什么这么破？&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;提问者假设是别人搞砸了，太自大了。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;明智： 某项目的源代码不能在某 Linux 6.2 版下编译。我读了常见问题文档，但其中没有与某 Linux 相关的内容。这是编译时的记录，我做错了什么吗？&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;提问者已经指明了运行环境，读了常见问题文档（FAQ），列出了错误，也没有假设问题是别人的过错，这家伙值得注意。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;愚蠢： 我的主板有问题，谁能帮我？&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;某黑客对此的反应可能是：“是的，还需要帮你拍背和换尿布吗？”，然后是敲下删除键。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;明智： 我在 S2464 主板上试过 X、Y 和 Z，当它们都失败后，又试了 A、B 和 C。注意我试 C 时的奇怪症状，显然某某东西正在做某某事情，这不是期望的行为。通常在 Athlon MP 主板上导致某某事情的原因是什么？有谁知道我还能再试点什么以确定问题？&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;相反地，这个人看来值得回答。他或她展现了解决问题的能力而不是坐等天上掉馅饼。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在最后那个问题中，注意“给我一个回答”与“请帮我看看我还能再做点什么测试以得到启发”之间细微但重要的差别。&lt;/p&gt;
&lt;p&gt;事实上，最后那个问题基本上源于 2001 年 8 月 Linux 内核邮件列表（lkml）上的真实事件，是我（Eric）当时提了那个问题，我发现 Tyan S2462 主板有神秘的死机现象，邮件列表成员给我提供了解决此问题的关键信息。&lt;/p&gt;
&lt;p&gt;通过这种提问方式，我给了别人可以咀嚼玩味的东西。我设法使之对参与者既轻松又有吸引力，也表明了对同行能力的尊敬并邀请他们与我一起协商。通过告诉他们我已经走过的弯路，我还表明了对他们宝贵时间的尊重。&lt;/p&gt;
&lt;p&gt;事后，当我感谢大家并评论这次良好的经历时，一个 Linux 内核邮件列表的成员谈到，他认为我得到答案并不是因为我的名字挂在列表上，而只是因为我正确的提问方式。&lt;/p&gt;
&lt;p&gt;黑客们在某种方面是非常不留情面的精英分子。我想在这事上他是对的，如果我 表现得 象个不劳而获的寄生虫，不管我是谁都会被忽略或斥责。他建议将整个事件作为对其它人提问的指导，这直接导致了本文的编写。&lt;/p&gt;
&lt;h3 id=&quot;如果得不到回答&quot;&gt;如果得不到回答&lt;/h3&gt;
&lt;p&gt;如果得不到回答，请不要认为我们不想帮你，有时只是因为被问到的小组成员的确不知道答案。没有回复不等于不被理睬，当然必须承认从外面很难看出两者的差别。&lt;/p&gt;
&lt;p&gt;一般而言，直接将问题再张贴一次不好，这会被视为毫无意义的骚扰。耐心一点，知道你问题答案的人可能生活在不同的时区，有可能正在睡觉，也有可能你的问题一开始就没有组织好。&lt;/p&gt;
&lt;p&gt;还有其它资源可以寻求帮助，通常是在一些面向新手的资源中。&lt;/p&gt;
&lt;p&gt;有许多在线与本地的用户组织，虽然它们自己不编写任何软件，但是对软件很热心。这些用户组通常因互助和帮助新手而形成。&lt;/p&gt;
&lt;p&gt;还有众多大小商业公司提供签约支持服务，别因为要付点钱才有支持就感到沮丧！毕竟，如果你车子的汽缸垫烧了，你多半还得花钱找个修理店把它弄好。即使软件没花你一分钱，你总不能指望服务支持都是免费的。&lt;/p&gt;
&lt;p&gt;象 Linux 这样流行的软件，每个开发者至少有一万个以上的用户，一个人不可能应付这么多用户的服务要求。记住，即使你必须付费才能得到支持，也比你还得额外花钱买软件要少得多（而且对封闭源代码软件的服务支持与开源软件相比通常还要贵一点，也要差一点）。&lt;/p&gt;
&lt;h3 id=&quot;如何更好地回答&quot;&gt;如何更好地回答&lt;/h3&gt;
&lt;p&gt;态度和善一点。问题带来的压力常使人显得无礼或愚蠢，其实并不是这样。&lt;/p&gt;
&lt;p&gt;对初犯者私下回复。 对那些坦诚犯错之人没有必要当众羞辱，一个真正的新手也许连怎么搜索或在哪找 FAQ 都不知道。&lt;/p&gt;
&lt;p&gt;如果你不确定，一定要说出来！ 一个听起来权威的错误回复比没有还要糟，别因为听起来象个专家好玩就给别人乱指路。要谦虚和诚实，给提问者与同行都树个好榜样。&lt;/p&gt;
&lt;p&gt;如果帮不了忙，别妨碍。 不要在具体步骤上开玩笑，那样也许会毁了用户的安装──有些可怜的呆瓜会把它当成真的指令。&lt;/p&gt;
&lt;p&gt;探索性的反问以引出更多的细节。 如果你做得好，提问者可以学到点东西──你也可以。试试将很差的问题转变成好问题，别忘了我们都曾是新手。&lt;/p&gt;
&lt;p&gt;尽管对那些懒虫报怨一声“读读该死的手册”（RTFM）是正当的，指出文档的位置（即使只是建议做个谷歌关键词搜索）会更好&lt;/p&gt;
&lt;p&gt;如果你决意回答，给出好的答案。 当别人正在用错误的工具或方法时别建议笨拙的权宜之计，应推荐更好的工具，重新组织问题。&lt;/p&gt;
&lt;p&gt;请回答真正的问题！如果提问者已经做了自己该做的研究，并且说明尝试过&lt;code&gt; X，Y，Z，A，B 与 C&lt;/code&gt; 都没有得到想要的結果，那么回复 &lt;code&gt;试试 A 或 B&lt;/code&gt; 或者给出一个内容为 &lt;code&gt;试一下 X，Y，Z，A，B 或 C&lt;/code&gt; 的链接将极其无益！&lt;/p&gt;
&lt;p&gt;帮助你的社区从中学习。当回复一个好问题时，问问自己 &lt;code&gt;如何修改相关文件或 FAQ 文档以免再次解答同样的问题？&lt;/code&gt;，接着再向文档维护者发一份补丁。&lt;/p&gt;
&lt;p&gt;如果你是在研究一番后才做出的回答，展现你的技巧而不是直接端出结果。毕竟“授人以鱼，不如授人以渔”。&lt;/p&gt;
&lt;h3 id=&quot;相关资源&quot;&gt;相关资源&lt;/h3&gt;
&lt;p&gt;如果需要个人电脑、Unix 和互联网如何工作的基础知识，参阅 &lt;a rel=&quot;external&quot; href=&quot;http://en.tldp.org/HOWTO/Unix-and-Internet-Fundamentals-HOWTO/&quot;&gt;Unix 和互联网工作的基本原理&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;当你发布软件或补丁时，试着按 &lt;a rel=&quot;external&quot; href=&quot;http://en.tldp.org/HOWTO/Software-Release-Practice-HOWTO/index.html&quot;&gt;软件发布实践&lt;/a&gt; 操作。&lt;/p&gt;
&lt;h3 id=&quot;鸣谢&quot;&gt;鸣谢&lt;/h3&gt;
&lt;p&gt;伊夫林.米切尔（Evelyn Mitchell）贡献了一些愚蠢问题例子并启发了编写&lt;code&gt;如何更好地回答问题&lt;/code&gt;这一节，米哈伊尔.罗门迪克（Mikhail Ramendik）贡献了一些特别有价值的建议和改进。&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>深入解析时间轮（Timing Wheel）：从 Kafka Purgatory 看高效定时任务调度</title>
        <published>2023-10-27T00:00:00+00:00</published>
        <updated>2023-10-27T00:00:00+00:00</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/hierarchical-timing-wheels-analysis/"/>
        <id>https://scp.net.cn/blog/hierarchical-timing-wheels-analysis/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/hierarchical-timing-wheels-analysis/">&lt;p&gt;在构建高性能分布式系统时，定时任务调度是一个极其常见但又充满挑战的需求。Apache Kafka 作为一个高吞吐量的消息系统，在其内部有一个被称为 “Purgatory”（炼狱）的组件，专门用于管理那些无法立即完成、需要等待特定条件满足或超时的异步请求。&lt;/p&gt;
&lt;p&gt;早期的 Kafka 使用 Java 的 &lt;code&gt;DelayQueue&lt;/code&gt; 来管理这些请求，但随着集群规模和负载的增加，这种设计逐渐成为了性能瓶颈。本文将基于 Kafka Purgatory 的重构历程，深入剖析 &lt;strong&gt;分层时间轮（Hierarchical Timing Wheel）&lt;/strong&gt; 的设计思想，并探讨它是如何解决 O(log n) 复杂度问题并实现 O(1) 高效调度的。&lt;/p&gt;
&lt;h2 id=&quot;1-wen-ti-de-qi-yuan-kafka-purgatory-yu-delayqueue&quot;&gt;1. 问题的起源：Kafka Purgatory 与 DelayQueue&lt;/h2&gt;
&lt;p&gt;Kafka 中有大量请求是无法立即返回的，例如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;acks=all&lt;/code&gt; 的 Produce 请求：需要等待所有 ISR（In-Sync Replicas）确认。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;min.bytes=1&lt;/code&gt; 的 Fetch 请求：需要等待至少有新数据产生（Long Polling）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些请求会被放入 Purgatory 中，直到满足条件（完成）或超时（强制完成）。&lt;/p&gt;
&lt;h3 id=&quot;jiu-she-ji-de-tong-dian&quot;&gt;旧设计的痛点&lt;/h3&gt;
&lt;p&gt;在 Kafka 0.8.x 版本中，Purgatory 使用 Java 的 &lt;code&gt;java.util.concurrent.DelayQueue&lt;/code&gt; 来管理超时。这是一个基于优先队列（PriorityQueue）的实现，底层通常是二叉堆（Min-Heap）。&lt;/p&gt;
&lt;p&gt;这种设计面临两个核心问题：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;时间复杂度 O(log n)&lt;/strong&gt;：&lt;code&gt;DelayQueue&lt;/code&gt; 的插入（offer）和删除（poll）操作复杂度都是 O(log n)。当 Purgatory 中积压了数万甚至数十万个请求时，频繁的插入和删除操作会消耗大量 CPU。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;删除效率低与 OOM 风险&lt;/strong&gt;：在 Purgatory 中，很多请求在超时之前就已经因为条件满足而完成了。但是，&lt;code&gt;DelayQueue&lt;/code&gt; 不支持高效的随机删除（Random Delete）。为了移除一个已完成的请求，通常需要遍历队列（O(n)），这在性能上是不可接受的。
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Workaround&lt;/strong&gt;：旧实现采用“标记删除”策略，即请求完成后不立即从队列移除，而是等到它自然“超时”弹出时再检查状态。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;后果&lt;/strong&gt;：这导致队列中堆积了大量已经完成的“僵尸请求”，占用了大量内存，极端情况下会导致 JVM &lt;code&gt;OutOfMemoryError&lt;/code&gt;。虽然引入了单独的 Reaper 线程来定期清理，但这又引入了额外的锁竞争和 CPU 开销。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;2-jiu-xing-deng-chang-shi-jian-lun-timing-wheel&quot;&gt;2. 救星登场：时间轮（Timing Wheel）&lt;/h2&gt;
&lt;p&gt;为了解决上述问题，Kafka 引入了基于 &lt;strong&gt;时间轮（Timing Wheel）&lt;/strong&gt; 的新设计。&lt;/p&gt;
&lt;h3 id=&quot;ji-chu-shi-jian-lun&quot;&gt;基础时间轮&lt;/h3&gt;
&lt;p&gt;想象一个老式的挂钟。表盘被分成 60 个格（Bucket），秒针每秒走一格。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;插入任务&lt;/strong&gt;：如果要在 5 秒后执行任务，就将任务放入当前指针位置 + 5 的格子里。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;推进时间&lt;/strong&gt;：秒针每走一格（Tick），就取出该格子里所有的任务执行。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;数据结构&lt;/strong&gt;：一个固定大小的环形数组（Circular Array），数组的每个元素是一个桶（Bucket），桶通常是一个双向链表（Doubly Linked List）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;优势&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;O(1) 插入&lt;/strong&gt;：通过 &lt;code&gt;(CurrentTime + Delay) % WheelSize&lt;/code&gt; 直接定位桶索引。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;O(1) 删除&lt;/strong&gt;：如果使用双向链表存储任务，只要持有任务节点的引用，即可在 O(1) 时间内将其从链表中移除。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;jin-jie-fen-ceng-shi-jian-lun-hierarchical-timing-wheel&quot;&gt;进阶：分层时间轮（Hierarchical Timing Wheel）&lt;/h3&gt;
&lt;p&gt;基础时间轮有一个缺陷：&lt;strong&gt;只能覆盖有限的时间范围&lt;/strong&gt;。
如果表盘只有 60 格，每格 1 秒，那它最多只能管理 60 秒内的任务。如果我想定一个 1 小时后的闹钟怎么办？&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;扩大数组&lt;/strong&gt;：造一个 3600 格的轮子？太浪费内存，且大部分格子是空的。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;分层设计&lt;/strong&gt;：这就是 &lt;strong&gt;分层时间轮&lt;/strong&gt; 的核心。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;类比现实世界的时钟，我们有秒针轮、分针轮、时针轮：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Level 1（秒轮）&lt;/strong&gt;：20 格，每格 1ms。覆盖范围 0-20ms。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Level 2（分轮）&lt;/strong&gt;：20 格，每格 20ms。覆盖范围 0-400ms。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Level 3（时轮）&lt;/strong&gt;：20 格，每格 400ms。覆盖范围 0-8000ms。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;工作机制（降级/Re-insert）&lt;/strong&gt;：
当插入一个 200ms 后执行的任务时，它超过了 Level 1 的范围，于是被放入 Level 2 的对应桶中。
随着时间推移，Level 1 的轮子转了很多圈。当时间推进到 Level 2 的那个桶过期时，任务&lt;strong&gt;并不会立即执行&lt;/strong&gt;，而是被&lt;strong&gt;降级&lt;/strong&gt;（Re-insert）到 Level 1 的轮子中。
这就好比：时针走到了 12 点，但任务其实是 12:30 执行的，所以此时把任务移交给分针轮去管理。&lt;/p&gt;
&lt;p&gt;这种设计使得我们可以用很少的内存（几个小数组）管理跨度极大的定时任务。&lt;/p&gt;
&lt;h2 id=&quot;3-kafka-de-du-te-you-hua-delayqueue-qu-dong-shi-jian-lun&quot;&gt;3. Kafka 的独特优化：DelayQueue 驱动时间轮&lt;/h2&gt;
&lt;p&gt;标准的简单时间轮通常有一个线程死循环，每隔固定时间（比如 1ms）醒来一次“拨动”指针。这被称为 &lt;strong&gt;Busy Waiting&lt;/strong&gt;。
如果任务非常稀疏（例如大部分时候桶都是空的），这种空转非常浪费 CPU。&lt;/p&gt;
&lt;p&gt;Kafka 做了一个极其聪明的优化：&lt;strong&gt;使用 DelayQueue 来管理时间轮的“桶”，而不是“任务”。&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;每个非空的 Bucket（注意是 Bucket，不是 Task）被作为一个 Item 放入 &lt;code&gt;DelayQueue&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DelayQueue&lt;/code&gt; 的过期时间设置为 Bucket 的过期时间。&lt;/li&gt;
&lt;li&gt;线程只需要 &lt;code&gt;DelayQueue.poll()&lt;/code&gt;。如果最近的桶是 100ms 后过期，线程就会挂起 100ms，而不是每 1ms 醒来一次。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;为什么这样更快？&lt;/strong&gt;
虽然又用回了 &lt;code&gt;DelayQueue&lt;/code&gt;，但现在的元素数量不再是&lt;strong&gt;任务数&lt;/strong&gt;（Millions），而是&lt;strong&gt;非空桶的数量&lt;/strong&gt;（通常只有几十个）。在元素极少的情况下，&lt;code&gt;DelayQueue&lt;/code&gt; 的 O(log n) 开销几乎可以忽略不计。&lt;/p&gt;
&lt;h2 id=&quot;4-shen-du-dui-bi-delayqueue-vs-hierarchical-timing-wheel&quot;&gt;4. 深度对比：DelayQueue vs Hierarchical Timing Wheel&lt;/h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;特性&lt;/th&gt;&lt;th style=&quot;text-align: left&quot;&gt;Java DelayQueue (Old)&lt;/th&gt;&lt;th style=&quot;text-align: left&quot;&gt;Hierarchical Timing Wheel (New)&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;插入复杂度&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;O(log N)&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;O(1)&lt;/strong&gt; (O(m)，m为层数，极小)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;删除复杂度&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;O(log N)&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;O(1)&lt;/strong&gt; (双向链表移除)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;随机删除支持&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;困难 (通常需 O(n) 扫描)&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;完美支持&lt;/strong&gt; (持有引用即可删除)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;内存开销&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;高 (包含大量已完成但未移除的僵尸任务)&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;低 (及时移除，仅存活任务占用内存)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;CPU 开销&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;高 (频繁重排堆，Reaper 线程扫描)&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;低 (仅处理过期桶，无空转)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;适用场景&lt;/strong&gt;&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;任务量小，对精确度要求极高&lt;/td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;海量任务&lt;/strong&gt;，高吞吐，允许极微小误差&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;5-zong-jie&quot;&gt;5. 总结&lt;/h2&gt;
&lt;p&gt;Kafka Purgatory 的重构是数据结构优化的经典案例。它告诉我们：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;特定场景特定分析&lt;/strong&gt;：通用数据结构（如 JDK 的 &lt;code&gt;DelayQueue&lt;/code&gt;）能解决问题，但在极端规模下可能不是最优解。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;组合优于单一&lt;/strong&gt;：Kafka 并没有完全抛弃 &lt;code&gt;DelayQueue&lt;/code&gt;，而是将其用于驱动时间轮的推进，结合了 &lt;code&gt;DelayQueue&lt;/code&gt; 的阻塞特性和时间轮的 O(1) 读写特性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;空间换时间与分层思想&lt;/strong&gt;：通过分层数组索引（哈希）来代替堆排序，大大降低了 CPU 消耗。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;对于构建类似的高性能定时任务系统（如 RPC 超时管理、心跳检测、游戏服务器 Buff 计时），分层时间轮无疑是首选方案。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;参考资料&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://cwiki.apache.org/confluence/display/KAFKA/Purgatory+Redesign+Proposal&quot;&gt;Apache Kafka Purgatory Redesign Proposal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;http://www.cs.columbia.edu/~nahum/w6998/papers/ton97-timing-wheels.pdf&quot;&gt;Hierarchical Timing Wheels Paper&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Paxos 协议</title>
        <published>2023-08-04T15:00:00+20:30</published>
        <updated>2023-08-04T15:00:00+20:30</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/paxos-in-action/"/>
        <id>https://scp.net.cn/blog/paxos-in-action/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/paxos-in-action/">&lt;p&gt;Paxos 协议是一种分布式一致性算法，用于在多个节点上达成一致性，确保分布式系统的可靠性和高可用性。Paxos 协议的核心思想是将分布式系统中的节点划分为 Proposer、Acceptor 和 Learner 三类节点，Proposer 节点提出提案，Acceptor 节点接受或拒绝提案，Learner 节点学习已经达成一致的提案结果。&lt;/p&gt;
&lt;h2 id=&quot;paxos-xie-yi-de-ji-ben-liu-cheng-ru-xia&quot;&gt;Paxos 协议的基本流程如下：&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Proposer 节点向 Acceptor 节点发送编号为 n 的提案，Acceptor 节点接收提案并判断编号是否大于已经接受的提案编号，如果大于则将该提案编号保存并发送一个 promise 消息给 Proposer 节点，否则拒绝提案。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果 Proposer 节点收到大多数 Acceptor 节点发送的 promise 消息，则进入第 2a 步，否则进入第 2b 步。&lt;/p&gt;
&lt;p&gt;2a. Proposer 节点向 Acceptor 节点发送一个编号为 n 的 accept 请求，Acceptor 节点接收请求并判断编号是否大于已经接受的提案编号，如果大于则将该提案编号保存并发送一个 accepted 消息给 Proposer 节点，否则拒绝提案。&lt;/p&gt;
&lt;p&gt;2b. Proposer 节点重新提出一个新的提案，重复步骤 1 和 2。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Proposer 节点收到大多数 Acceptor 节点发送的 accepted 消息后，向所有 Learner 节点广播提案结果。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Learner 节点学习提案结果并应用到本地状态。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;paxos-xie-yi-de-shi-xian-xu-yao-zhu-yi-yi-xia-ji-dian&quot;&gt;Paxos 协议的实现需要注意以下几点：&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;避免脑裂：如果多个 Acceptor 节点同时接受编号不同的提案，会导致脑裂现象，因此需要确保 Acceptor 节点接受提案的顺序是按照提案编号递增的顺序。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;避免网络分区：如果网络分区导致 Proposer 节点和一部分 Acceptor 节点无法通信，会导致无法达成一致性。因此需要确保网络分区时，Proposer 节点能够检测到网络分区并重新选定 Acceptor 节点。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;避免 Acceptor 节点崩溃：如果 Acceptor 节点崩溃，则它无法接受新的提案，导致无法达成一致性。因此需要确保 Acceptor 节点的高可用性，例如使用备份 Acceptor 节点。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;提案编号的管理：为了避免重复的提案编号，需要对提案编号进行管理，例如使用递增的序列号或者使用数据库存储已经使用的提案编号。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>cosid 项目学习</title>
        <published>2023-03-18T12:13:38+05:30</published>
        <updated>2023-03-18T12:13:38+05:30</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/cosid-intro/"/>
        <id>https://scp.net.cn/blog/cosid-intro/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/cosid-intro/">&lt;h2 id=&quot;xiang-mu-gai-shu&quot;&gt;项目概述&lt;/h2&gt;
&lt;p&gt;me.ahoo.cosid 是一个分布式 ID 生成器框架，提供了多种 ID 生成策略，支持雪花算法（Snowflake）、号段模式（Segment）等多种分布式 ID 生成方案。该项目旨在解决分布式系统中唯一 ID 生成的问题，具有高性能、可扩展、易用等特点。&lt;/p&gt;
&lt;h2 id=&quot;zhu-yao-te-xing&quot;&gt;主要特性&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;多种 ID 生成策略&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;雪花算法（Snowflake）&lt;/li&gt;
&lt;li&gt;号段模式（Segment）&lt;/li&gt;
&lt;li&gt;基于时间的 ID 生成&lt;/li&gt;
&lt;li&gt;自定义 ID 生成器&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;丰富的存储支持&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Redis&lt;/li&gt;
&lt;li&gt;Zookeeper&lt;/li&gt;
&lt;li&gt;JDBC&lt;/li&gt;
&lt;li&gt;MongoDB&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;高性能&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;本地缓存&lt;/li&gt;
&lt;li&gt;批量获取&lt;/li&gt;
&lt;li&gt;异步预分配&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;易于集成&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Spring Boot Starter&lt;/li&gt;
&lt;li&gt;支持多种框架集成&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;可观测性&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;提供监控指标&lt;/li&gt;
&lt;li&gt;支持 Micrometer&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;he-xin-gai-nian&quot;&gt;核心概念&lt;/h2&gt;
&lt;h3 id=&quot;1-fen-bu-shi-id-sheng-cheng-ce-lue&quot;&gt;1. 分布式 ID 生成策略&lt;/h3&gt;
&lt;h4 id=&quot;1-1-xue-hua-suan-fa-snowflake&quot;&gt;1.1 雪花算法（Snowflake）&lt;/h4&gt;
&lt;p&gt;雪花算法是一种基于时间的分布式 ID 生成算法，生成的 ID 是一个 64 位的长整型数字，由以下部分组成：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;符号位（1 位）：始终为 0&lt;/li&gt;
&lt;li&gt;时间戳（41 位）：毫秒级时间戳&lt;/li&gt;
&lt;li&gt;工作机器 ID（10 位）：包括 5 位数据中心 ID 和 5 位机器 ID&lt;/li&gt;
&lt;li&gt;序列号（12 位）：毫秒内的计数器&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;CosId 对雪花算法进行了优化和扩展，提供了更灵活的位分配方案和机器号分配策略。&lt;/p&gt;
&lt;h4 id=&quot;1-2-hao-duan-mo-shi-segment&quot;&gt;1.2 号段模式（Segment）&lt;/h4&gt;
&lt;p&gt;号段模式是一种基于数据库的 ID 生成策略，通过预先分配一段 ID 范围（号段）给应用实例，应用实例在内存中生成 ID，当号段用完时再去数据库获取新的号段。这种方式减少了数据库访问频率，提高了性能。&lt;/p&gt;
&lt;p&gt;CosId 的号段模式支持多种存储介质，如 Redis、Zookeeper、JDBC、MongoDB 等。&lt;/p&gt;
&lt;h3 id=&quot;2-ji-qi-hao-fen-pei&quot;&gt;2. 机器号分配&lt;/h3&gt;
&lt;p&gt;在分布式环境中，为每个节点分配唯一的机器号是雪花算法的关键。CosId 提供了多种机器号分配策略：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;静态分配：通过配置文件指定&lt;/li&gt;
&lt;li&gt;基于 Redis 的分配&lt;/li&gt;
&lt;li&gt;基于 Zookeeper 的分配&lt;/li&gt;
&lt;li&gt;基于数据库的分配&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;3-shi-zhong-hui-bo-chu-li&quot;&gt;3. 时钟回拨处理&lt;/h3&gt;
&lt;p&gt;时钟回拨是分布式系统中的常见问题，可能导致 ID 重复。CosId 提供了多种时钟回拨处理策略：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;抛出异常&lt;/li&gt;
&lt;li&gt;等待时钟追赶&lt;/li&gt;
&lt;li&gt;使用备用时钟源&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;shi-yong-shi-li&quot;&gt;使用示例&lt;/h2&gt;
&lt;h3 id=&quot;maven-yi-lai&quot;&gt;Maven 依赖&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;xml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    &amp;lt;groupId&amp;gt;&lt;/span&gt;&lt;span&gt;me.ahoo.cosid&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    &amp;lt;artifactId&amp;gt;&lt;/span&gt;&lt;span&gt;cosid-core&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    &amp;lt;version&amp;gt;&lt;/span&gt;&lt;span&gt;${cosid.version}&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;spring-boot-ji-cheng&quot;&gt;Spring Boot 集成&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;xml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    &amp;lt;groupId&amp;gt;&lt;/span&gt;&lt;span&gt;me.ahoo.cosid&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    &amp;lt;artifactId&amp;gt;&lt;/span&gt;&lt;span&gt;cosid-spring-boot-starter&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    &amp;lt;version&amp;gt;&lt;/span&gt;&lt;span&gt;${cosid.version}&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;pei-zhi-shi-li&quot;&gt;配置示例&lt;/h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;cosid&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;  namespace&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; ${spring.application.name}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;  snowflake&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    enabled&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    epoch&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1577203200000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    machine&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;      enabled&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;      distributor&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; redis&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;  segment&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    enabled&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    mode&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; chain&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;    distributor&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;      type&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; redis&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;dai-ma-shi-li&quot;&gt;代码示例&lt;/h3&gt;
&lt;h4 id=&quot;xue-hua-suan-fa&quot;&gt;雪花算法&lt;/h4&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 获取雪花算法 ID 生成器&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;IdGenerator&lt;/span&gt;&lt;span&gt; idGenerator&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; cosIdContainer&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getIdGenerator&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;snowflake&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 生成 ID&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;long&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; idGenerator&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;generate&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;hao-duan-mo-shi&quot;&gt;号段模式&lt;/h4&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 获取号段模式 ID 生成器&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;IdGenerator&lt;/span&gt;&lt;span&gt; idGenerator&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; cosIdContainer&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getIdGenerator&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;segment&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// 生成 ID&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;long&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; idGenerator&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;generate&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;xing-neng-you-hua&quot;&gt;性能优化&lt;/h2&gt;
&lt;p&gt;CosId 在性能方面做了多种优化：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;本地缓存&lt;/strong&gt;：减少远程调用&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;批量获取&lt;/strong&gt;：一次获取多个 ID&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;异步预分配&lt;/strong&gt;：在后台异步获取下一个号段&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;无锁设计&lt;/strong&gt;：使用 CAS 操作减少锁竞争&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;zui-jia-shi-jian&quot;&gt;最佳实践&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;选择合适的 ID 生成策略&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对于高并发场景，推荐使用雪花算法&lt;/li&gt;
&lt;li&gt;对于需要连续 ID 的场景，推荐使用号段模式&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;机器号分配&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在生产环境中，推荐使用分布式机器号分配策略&lt;/li&gt;
&lt;li&gt;在开发环境中，可以使用静态分配&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;监控&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;启用 Micrometer 监控，及时发现性能问题&lt;/li&gt;
&lt;li&gt;关注时钟回拨事件&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;容灾&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;配置多个 ID 生成器，互为备份&lt;/li&gt;
&lt;li&gt;使用 Redis 集群或主从架构提高可用性&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;kuo-zhan-yue-du&quot;&gt;扩展阅读&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://tech.meituan.com/2017/04/21/mt-leaf.html&quot;&gt;分布式 ID 生成算法的比较&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://juejin.cn/post/6844903562007314440&quot;&gt;雪花算法的优化&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https://www.cnblogs.com/haoxinyue/p/5208136.html&quot;&gt;号段模式的实现原理&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;chang-jian-wen-ti&quot;&gt;常见问题&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ID 重复问题&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;检查时钟是否回拨&lt;/li&gt;
&lt;li&gt;确保机器号唯一&lt;/li&gt;
&lt;li&gt;验证序列号生成逻辑&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;性能问题&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用本地缓存&lt;/li&gt;
&lt;li&gt;批量获取 ID&lt;/li&gt;
&lt;li&gt;调整号段大小&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;集成问题&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;检查依赖版本兼容性&lt;/li&gt;
&lt;li&gt;确认配置正确&lt;/li&gt;
&lt;li&gt;查看日志排查问题&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;zong-jie&quot;&gt;总结&lt;/h2&gt;
&lt;p&gt;me.ahoo.cosid 是一个功能丰富、性能优秀的分布式 ID 生成框架，提供了多种 ID 生成策略和存储支持，适用于各种分布式系统场景。通过合理配置和使用，可以解决分布式系统中唯一 ID 生成的问题，提高系统的可扩展性和性能。&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>How to Write a Javaagent</title>
        <published>2021-03-18T12:13:38+05:30</published>
        <updated>2021-03-18T12:13:38+05:30</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/java-simple-agent-impl/"/>
        <id>https://scp.net.cn/blog/java-simple-agent-impl/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/java-simple-agent-impl/">&lt;h2 id=&quot;shen-me-shi-java-agentji-shu&quot;&gt;什么是Java Agent技术&lt;/h2&gt;
&lt;p&gt;Java Agent本质上可以理解为一个插件，该插件就是一个精心提供的Jar包，这个Jar包通过JVMTI（JVM Tool Interface）完成加载，最终借助&lt;a rel=&quot;external&quot; href=&quot;https://github.com/openjdk/jdk/blob/master/src/java.instrument/share/native/libinstrument/JPLISAgent.c&quot;&gt;JPLISAgent&lt;/a&gt;（Java Programming Language Instrumentation Services Agent）完成对目标代码的修改。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Java agent的功能&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;可以在加载Java文件之前做拦截把字节码做修改&lt;/li&gt;
&lt;li&gt;可以在运行期将已经加载的类的字节码做变更&lt;/li&gt;
&lt;li&gt;………..&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;使用场景&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;APM 工具：如 Pinpoint、SkyWalking 等&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;动态调试和诊断：比较流行的 btrace、arthas 等&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;热部署：jrebel&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;混沌工程：jvm-sandbox 等&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://scp-net-cn.oss-cn-beijing.aliyuncs.com/blog-images/java-agent-overview-min.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;h4 id=&quot;shi-xian-agentqi-dong-fang-fa&quot;&gt;实现Agent启动方法&lt;/h4&gt;
&lt;p&gt;Java Agent支持目标JVM启动时加载，也支持在目标JVM运行时加载，这两种不同的加载模式会使用不同的入口函数，如果需要在目标JVM启动的同时加载Agent，那么可以选择实现下面的方法：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[1] public static void premain(String agentArgs, Instrumentation inst);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[2] public static void premain(String agentArgs);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;JVM将首先寻找[1]，如果没有发现[1]，再寻找[2]。如果希望在目标JVM运行时加载Agent，则需要实现下面的方法：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[1] public static void agentmain(String agentArgs, Instrumentation inst);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[2] public static void agentmain(String agentArgs);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这两组方法的第一个参数AgentArgs是随同 &lt;code&gt;–javaagent&lt;/code&gt; 一起传入的程序参数，如果这个字符串代表了多个参数，就需要自己解析这些参数。inst是&lt;code&gt;Instrumentation&lt;/code&gt;类型的对象，是JVM自动传入的，我们可以拿这个参数进行类增强等操作。&lt;/p&gt;
&lt;h4 id=&quot;zhi-ding-main-class&quot;&gt;指定Main-Class&lt;/h4&gt;
&lt;p&gt;Agent需要打包成一个jar包，在ManiFest属性中指定&lt;code&gt;Premain-Class&lt;/code&gt;或者&lt;code&gt;Agent-Class&lt;/code&gt;：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Premain-Class: class&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Agent-Class: class&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;gua-zai-dao-mu-biao-jvm&quot;&gt;挂载到目标JVM&lt;/h4&gt;
&lt;p&gt;将编写的Agent打成jar包后，就可以挂载到目标JVM上去了。如果选择在目标JVM启动时加载Agent，则可以使用&lt;code&gt;-javaagent:[=]&lt;/code&gt;，具体的使用方法可以使用&lt;code&gt;Java -Help&lt;/code&gt;来查看。&lt;/p&gt;
&lt;p&gt;如果想要在运行时挂载Agent到目标JVM，就需要做一些额外的开发了。&lt;/p&gt;
&lt;p&gt;``com.sun.tools.attach.VirtualMachine 这个类代表一个JVM抽象，可以通过这个类找到目标JVM，并且将Agent挂载到目标JVM上。&lt;/p&gt;
&lt;p&gt;下面是使用&lt;code&gt;com.sun.tools.attach.VirtualMachine&lt;/code&gt;进行动态挂载Agent的一般实现：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    private void&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; attachAgentToTargetJVM&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span&gt; throws Exception &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        List&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;VirtualMachineDescriptor&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; virtualMachineDescriptors&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; VirtualMachine&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;list&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        VirtualMachineDescriptor&lt;/span&gt;&lt;span&gt; targetVM&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = null;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        for&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;VirtualMachineDescriptor&lt;/span&gt;&lt;span&gt; descriptor&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; :&lt;/span&gt;&lt;span&gt; virtualMachineDescriptors&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;descriptor&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;equals&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;configure&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getPid&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;())) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                targetVM &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt; descriptor&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;                break;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;targetVM &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;== null&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            throw new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; IllegalArgumentException&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;could not find the target jvm by process id:&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span&gt; configure&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getPid&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;())&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        VirtualMachine&lt;/span&gt;&lt;span&gt; virtualMachine&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = null;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        try&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            virtualMachine &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt; VirtualMachine&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;attach&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;targetVM&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            virtualMachine&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;loadAgent&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;{agent}&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;{params}&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; catch&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Exception&lt;/span&gt;&lt;span&gt; e&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;virtualMachine &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;!= null&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                virtualMachine&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;detach&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;首先通过指定的进程ID找到目标JVM，然后通过Attach挂载到目标JVM上，执行加载Agent操作。VirtualMachine的Attach方法就是用来将Agent挂载到目标JVM上去的，而Detach则是将Agent从目标JVM卸载。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https://docs.oracle.com/javase/8/docs/api/java/lang/instrument/Instrumentation.html&quot;&gt;Instrumentation (Java Platform SE 8 )&lt;/a&gt;&lt;/strong&gt; 类提供检测 Java 编程语言代码所需的服务。Instrumentation 是在方法中添加字节码，以收集工具使用的数据。由于更改纯粹是附加的，因此这些工具不会修改应用程序状态或行为。这种良性工具的示例包括监控代理、分析器、覆盖分析器和事件记录器。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;addTransformer&lt;/code&gt;: 添加一个类转换器&lt;/li&gt;
&lt;li&gt;&lt;code&gt;removeTransformer&lt;/code&gt;: 删除一个类转换器&lt;/li&gt;
&lt;li&gt;&lt;code&gt;isRetransformClassesSupported&lt;/code&gt;: 判断是否支持类的重新转换&lt;/li&gt;
&lt;li&gt;&lt;code&gt;retransformClasses&lt;/code&gt;: 在类加载后，重新定义该类&lt;/li&gt;
&lt;li&gt;&lt;code&gt;isRedefineClassesSupported&lt;/code&gt;: 判断是否支持重新定义类&lt;/li&gt;
&lt;li&gt;&lt;code&gt;redefineClasses&lt;/code&gt;: 重新进行类的定义&lt;/li&gt;
&lt;li&gt;&lt;code&gt;isModifiableClass&lt;/code&gt;: 确定一个类是否可以通过重新转换或重新定义来修改&lt;/li&gt;
&lt;li&gt;&lt;code&gt;getAllLoadedClasses&lt;/code&gt;: 返回 JVM 当前加载的所有类的数组&lt;/li&gt;
&lt;li&gt;&lt;code&gt;getInitiatedClasses&lt;/code&gt;: 返回 loader 为其初始加载器的所有类的数组。如果提供的加载器为空，则返回由引导类加载器启动的类&lt;/li&gt;
&lt;li&gt;……&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;premain-jing-tai-fang-shi&quot;&gt;premain 静态方式&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;大多数中间件/工具的使用方式&lt;/p&gt;
&lt;p&gt;使用方法：java -javaagent:xxx.jar MyApp&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;代码地址：&lt;a rel=&quot;external&quot; href=&quot;https://gitee.com/dllen/dllen-demos/tree/master/application-premain&quot;&gt;application-premain&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;编译和测试：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 编译打包&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;mvn&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; clean package&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 执行&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;java&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -javaagent:target/application-premain-jar-with-dependencies.jar  -cp target/application-premain-jar-with-dependencies.jar com.ks.test.app.MyApp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 执行结果（方法执行前后添加代码）&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=====start=====&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Hello&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; World!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=====end=====&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=====start=====&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Hello&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; World!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=====end=====&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;he-xin-dai-ma&quot;&gt;核心代码&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;MyTransformer.java&lt;/code&gt; 类是具体实现字节码植入的实现类&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; java&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;lang&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;instrument&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;ClassFileTransformer&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; java&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;lang&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;instrument&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;IllegalClassFormatException&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; java&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;security&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;ProtectionDomain&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; java&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;util&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Objects&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; javassist&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;ClassPool&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; javassist&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;CtClass&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; javassist&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;CtMethod&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;public class&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; MyTransformer&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; implements&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;font-weight: bold;&quot;&gt; ClassFileTransformer&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public byte&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[]&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; transform&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;ClassLoader&lt;/span&gt;&lt;span&gt; loader&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; String&lt;/span&gt;&lt;span&gt; className&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; classBeingRedefined&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; ProtectionDomain&lt;/span&gt;&lt;span&gt; protectionDomain&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; byte&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[]&lt;/span&gt;&lt;span&gt; classfileBuffer&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; throws&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; IllegalClassFormatException&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        //跳过java自带方法&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;className&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;startsWith&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;java&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ||&lt;/span&gt;&lt;span&gt; className&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;startsWith&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;sun&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            return&lt;/span&gt;&lt;span&gt; classfileBuffer&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        //好像使用premain这个className是没问题的，但使用attach时className的.变成了/，所以如果是attach，那么这里需要替换&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        className &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt; className&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;replace&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        //只处理MyApp类&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;!&lt;/span&gt;&lt;span&gt;className&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;endsWith&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;MyApp&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            return&lt;/span&gt;&lt;span&gt; classfileBuffer&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        //使用javassist类库对字节码修改&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        try&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;            ClassPool&lt;/span&gt;&lt;span&gt; classPool&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; ClassPool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getDefault&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;            CtClass&lt;/span&gt;&lt;span&gt; ctClass&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; classPool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;className&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;            CtMethod&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[]&lt;/span&gt;&lt;span&gt; declaredMethods&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; ctClass&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getDeclaredMethods&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            for&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;CtMethod&lt;/span&gt;&lt;span&gt; declaredMethod&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; :&lt;/span&gt;&lt;span&gt; declaredMethods&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;                //只处理printSth方法&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;                if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;Objects&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;equals&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;printHello&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span&gt; declaredMethod&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getName&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;())) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;                    //在方法执行前插入打印语句&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    declaredMethod&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;insertBefore&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;System.out.println(&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=====start=====&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;);&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;                    //在方法执行后插入打印语句&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    declaredMethod&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;insertAfter&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;System.out.println(&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=====end=====&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;);&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;                    break;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            return&lt;/span&gt;&lt;span&gt; ctClass&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;toBytecode&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; catch&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Exception&lt;/span&gt;&lt;span&gt; e&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            e&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;printStackTrace&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return&lt;/span&gt;&lt;span&gt; classfileBuffer&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;PremainMain.java&lt;/code&gt; Java Agent内部约定的 &lt;code&gt;premain&lt;/code&gt; 实现：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; java&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;lang&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;instrument&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Instrumentation&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;public class&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; PremainMain&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    /*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     * 注意，这个premain方法签名是Java Agent约定的，不要随意修改&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     * @param agentArgs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     * @param instrumentation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public static void&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; premain&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;String&lt;/span&gt;&lt;span&gt; agentArgs&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Instrumentation&lt;/span&gt;&lt;span&gt; instrumentation&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        instrumentation&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;addTransformer&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; MyTransformer&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;())&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    //PremainMain#premain的方法签名是Java Agent内部约定的，不能随意修改。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;resouces/META-INF/MANIFEST.MF&lt;/code&gt;通过 &lt;code&gt;MANIFEST.MF&lt;/code&gt; 文件找到 &lt;code&gt;premain&lt;/code&gt; 的实现类&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Manifest&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&lt;/span&gt;&lt;span&gt;Version&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Created&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&lt;/span&gt;&lt;span&gt;By&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span&gt; dllen&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Premain&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;-&lt;/span&gt;&lt;span&gt;Class&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span&gt; com&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;ks&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;test&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;app&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;PremainMain&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;注意：最后一行需要留一个空行&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;MyApp.java&lt;/code&gt; 测试应用&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; java&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;util&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;concurrent&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;TimeUnit&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;public class&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; MyApp&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public static void&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; main&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[]&lt;/span&gt;&lt;span&gt; args&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        while&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;            printHello&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    private static void&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; printHello&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        System&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;out&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Hello World!&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        try&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            TimeUnit&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;SECONDS&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sleep&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; catch&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;InterruptedException&lt;/span&gt;&lt;span&gt; e&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            e&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;printStackTrace&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;attach-dong-tai-fang-shi&quot;&gt;attach 动态方式&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;混沌工程-故障注入，应用调试和诊断的实现方式&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;代码地址：&lt;a rel=&quot;external&quot; href=&quot;https://gitee.com/dllen/dllen-demos/tree/master/application-attach&quot;&gt;application-attach&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;编译和测试：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 编译打包&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;mvn&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; clean package&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 终端 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;java&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -cp target/application-premain-jar-with-dependencies.jar com.ks.test.app.MyApp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 终端 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 使用 ps 找到 进程id&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;java&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -cp ./target/application-premain-jar-with-dependencies.jar com.ks.test.app.AttachMain&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ${&lt;/span&gt;&lt;span&gt;pid&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; ./target/application-premain-jar-with-dependencies.jar&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# attach success!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;# 终端 1 结果&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Hello&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; World!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Hello&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; World!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Hello&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; World!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Hello&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; World!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Hello&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; World!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;come&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; in agentmain&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;clazz&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; = com.ks.test.app.AttachAgent&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;clazz&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; = com.ks.test.app.MyApp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=====start=====&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Hello&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; World!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=====end=====&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=====start=====&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Hello&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; World!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=====end=====&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;he-xin-dai-ma-1&quot;&gt;核心代码&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;MyAttachTransformer.java&lt;/code&gt; 代码植入类&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; java&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;lang&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;instrument&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;ClassFileTransformer&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; java&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;lang&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;instrument&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;IllegalClassFormatException&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; java&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;security&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;ProtectionDomain&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; java&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;util&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Objects&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; javassist&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;ClassPool&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; javassist&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;CtClass&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; javassist&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;CtMethod&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;public class&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; MyAttachTransformer&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; implements&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;font-weight: bold;&quot;&gt; ClassFileTransformer&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public byte&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[]&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; transform&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;ClassLoader&lt;/span&gt;&lt;span&gt; loader&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; String&lt;/span&gt;&lt;span&gt; className&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; classBeingRedefined&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; ProtectionDomain&lt;/span&gt;&lt;span&gt; protectionDomain&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; byte&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[]&lt;/span&gt;&lt;span&gt; classfileBuffer&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; throws&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; IllegalClassFormatException&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        //跳过java自带方法&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;className&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;startsWith&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;java&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; ||&lt;/span&gt;&lt;span&gt; className&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;startsWith&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;sun&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            return&lt;/span&gt;&lt;span&gt; classfileBuffer&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        //好像使用premain这个className是没问题的，但使用attach时className的.变成了/，所以如果是attach，那么这里需要替换&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        className &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span&gt; className&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;replace&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        //只处理MyApp类&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;!&lt;/span&gt;&lt;span&gt;className&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;endsWith&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;MyApp&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            return&lt;/span&gt;&lt;span&gt; classfileBuffer&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        try&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;            ClassPool&lt;/span&gt;&lt;span&gt; classPool&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; ClassPool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getDefault&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;            CtClass&lt;/span&gt;&lt;span&gt; ctClass&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; classPool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;className&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;            CtMethod&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[]&lt;/span&gt;&lt;span&gt; declaredMethods&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; ctClass&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getDeclaredMethods&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            for&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;CtMethod&lt;/span&gt;&lt;span&gt; declaredMethod&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; :&lt;/span&gt;&lt;span&gt; declaredMethods&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;                //只处理printSth方法&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;                if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;Objects&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;equals&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;printHello&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span&gt; declaredMethod&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getName&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;())) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;                    //在方法执行前插入打印语句&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    declaredMethod&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;insertBefore&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;System.out.println(&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=====start=====&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;);&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;                    //在方法执行后插入打印语句&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    declaredMethod&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;insertAfter&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;System.out.println(&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;=====end=====&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;);&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;                    break;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            return&lt;/span&gt;&lt;span&gt; ctClass&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;toBytecode&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; catch&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Exception&lt;/span&gt;&lt;span&gt; e&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            e&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;printStackTrace&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return&lt;/span&gt;&lt;span&gt; classfileBuffer&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;AttachAgent.java&lt;/code&gt;实现 &lt;code&gt;agentmain&lt;/code&gt; 方法&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; java&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;lang&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;instrument&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Instrumentation&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; java&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;lang&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;instrument&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;UnmodifiableClassException&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;public class&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; AttachAgent&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    /*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     * 注意：agentmain的方法签名也是约定好的，不能随意修改&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     * 其实如果要支持premain和attach两种方式的话，可以把premain和agentmain两个方法写在一个类里，这里为了方便演示，写成了两个&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     * @param agentArgs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     * @param instrumentation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public static void&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; agentmain&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;String&lt;/span&gt;&lt;span&gt; agentArgs&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Instrumentation&lt;/span&gt;&lt;span&gt; instrumentation&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        String&lt;/span&gt;&lt;span&gt; targetClassPath&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;com.ks.test.app.MyApp&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        System&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;out&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;come in agentmain&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        for&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; clazz&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; :&lt;/span&gt;&lt;span&gt; instrumentation&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getAllLoadedClasses&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;            // 过滤掉不能修改的类&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;!&lt;/span&gt;&lt;span&gt;instrumentation&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;isModifiableClass&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;clazz&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;                continue;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            System&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;out&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;clazz = &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span&gt; clazz&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getName&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;())&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;            // 只修改我们关心的类&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;clazz&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getName&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;equals&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;targetClassPath&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;                // 最根本的目的还是把MyTransformer添加到instrumentation中&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                instrumentation&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;addTransformer&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; MyAttachTransformer&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(),&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;                try&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    instrumentation&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;retransformClasses&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;clazz&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; catch&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;UnmodifiableClassException&lt;/span&gt;&lt;span&gt; e&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    e&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;printStackTrace&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;                return;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;resouces/META-INF/MANIFEST.MF&lt;/code&gt;通过 &lt;code&gt;MANIFEST.MF&lt;/code&gt; 文件找到 &lt;code&gt;agentmain&lt;/code&gt; 的实现类&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Manifest-Version: 1.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Created-By: dllen&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Agent-Class: com.ks.test.app.AttachAgent&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Can-Redefine-Classes: true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Can-Retransform-Classes: true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;AttachMain.java&lt;/code&gt; 在运行时挂载Agent到目标JVM&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; com&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;sun&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;tools&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;attach&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;VirtualMachine&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; java&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;io&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;File&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; java&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;lang&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;reflect&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;InvocationTargetException&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; java&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;lang&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;reflect&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Method&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; java&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;net&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;MalformedURLException&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; java&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;net&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;URL&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; java&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;net&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;URLClassLoader&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;public class&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; AttachMain&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    /*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     * 加载 tools.jar&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     * @throws NoSuchMethodException&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     * @throws MalformedURLException&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     * @throws InvocationTargetException&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     * @throws IllegalAccessException&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    private static void&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; prepareAttach&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; throws&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; NoSuchMethodException&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; MalformedURLException&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; InvocationTargetException&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; IllegalAccessException&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        String&lt;/span&gt;&lt;span&gt; binPath&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; System&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getProperty&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;sun.boot.library.path&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // remove jre/bin, replace with lib&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        String&lt;/span&gt;&lt;span&gt; libPath&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; binPath&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;substring&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; binPath&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;length&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 7&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;lib&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        URLClassLoader&lt;/span&gt;&lt;span&gt; loader&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;URLClassLoader&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span&gt; AttachMain&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getClassLoader&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        Method&lt;/span&gt;&lt;span&gt; addURLMethod&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; URLClassLoader&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getDeclaredMethod&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;addURL&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span&gt; URL&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        addURLMethod&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;setAccessible&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        File&lt;/span&gt;&lt;span&gt; toolsJar&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; File&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;libPath &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;/tools.jar&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;!&lt;/span&gt;&lt;span&gt;toolsJar&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;exists&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            throw new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; RuntimeException&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;toolsJar&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getAbsolutePath&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; does not exist&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        addURLMethod&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;invoke&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;loader&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; File&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;libPath &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;/tools.jar&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;).&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;toURI&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;toURL&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;())&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public static void&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; main&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[]&lt;/span&gt;&lt;span&gt; args&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        String&lt;/span&gt;&lt;span&gt; pid&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; args&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        String&lt;/span&gt;&lt;span&gt; agentPath&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; args&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        File&lt;/span&gt;&lt;span&gt; agentFile&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; File&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;agentPath&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;!&lt;/span&gt;&lt;span&gt;agentFile&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;exists&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            System&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;out&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Agent not exist!&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            return;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        try&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;            prepareAttach&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;            VirtualMachine&lt;/span&gt;&lt;span&gt; virtualMachine&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; VirtualMachine&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;attach&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;pid&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            virtualMachine&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;loadAgent&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;agentFile&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getAbsolutePath&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;())&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            virtualMachine&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;detach&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            System&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;out&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;attach success!&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; catch&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Exception&lt;/span&gt;&lt;span&gt; e&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            e&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;printStackTrace&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // attach ok&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;需要传递2个参数&lt;/p&gt;
&lt;p&gt;    目标Java进程ID&lt;/p&gt;
&lt;p&gt;    Agent的路径&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;can-kao-zi-liao&quot;&gt;参考资料&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http://www.taoxuefeng.com/JAVA/jdk/agent.html&quot;&gt;java agent · GitBook&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://zhengw-tech.com/2023/05/27/java-agent/&quot;&gt;JavaAgent使用及原理 | 个人网页&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://tech.meituan.com/2019/11/07/java-dynamic-debugging-technology.html&quot;&gt;Java 动态调试技术原理及实践 - 美团技术团队&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://www.cnblogs.com/rickiyang/p/11368932.html&quot;&gt;javaagent使用指南 - rickiyang - 博客园&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://www.kancloud.cn/alex_wsc/javajvm/1844993&quot;&gt;第21讲：深入剖析：如何使用 Java Agent 技术对字节码进行修改 · 深入浅出Java虚拟机 · 看云&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://cloud.tencent.com/developer/article/2161810&quot;&gt;谈谈Java Agent技术的实现-腾讯云开发者社区-腾讯云&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;https://segmentfault.com/a/1190000039731381&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://veryjj.github.io/2021/01/01/%E6%89%8B%E6%8A%8A%E6%89%8B%E6%95%99%E4%BD%A0Java%E5%AD%97%E8%8A%82%E7%A0%81Demo/&quot;&gt;手把手教你Java字节码Demo&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://www.hollischuang.com/archives/592&quot;&gt;深入探索 Java 热部署&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;zi-jie-ma-cao-zuo-ku&quot;&gt;字节码操作库&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;https://asm.ow2.io/&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/cglib/cglib&quot;&gt;GitHub - cglib/cglib&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;https://www.javassist.org/&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://bytebuddy.net/#/&quot;&gt;Byte Buddy - runtime code generation for the Java virtual machine&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;kai-yuan-xiang-mu&quot;&gt;开源项目&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/alibaba/jvm-sandbox&quot;&gt;GitHub - alibaba/jvm-sandbox: Real - time non-invasive AOP framework container based on JVM&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace&quot;&gt;GitHub - btraceio/btrace: BTrace - a safe, dynamic tracing tool for the Java platform&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/alibaba/arthas&quot;&gt;GitHub - alibaba/arthas: Alibaba Java Diagnostic Tool Arthas/Alibaba Java诊断利器Arthas&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/pinpoint-apm/pinpoint&quot;&gt;GitHub - pinpoint-apm/pinpoint: APM, (Application Performance Management) tool for large-scale distributed systems.&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/apache/skywalking&quot;&gt;GitHub - apache/skywalking: APM, Application Performance Monitoring System&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/pandening/Java-debug-tool&quot;&gt;GitHub - pandening/Java-debug-tool: Java dynamic debug tool&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>PacificA：微软设计的分布式存储框架分析</title>
        <published>2020-10-18T12:13:32+05:30</published>
        <updated>2020-10-18T12:13:32+05:30</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/pacifica/"/>
        <id>https://scp.net.cn/blog/pacifica/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/pacifica/">&lt;p&gt;本文主要阅读下面2篇文章整理完成 (有歧义以原文为主)：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://zhuanlan.zhihu.com/p/27582424&quot;&gt;PacificA：微软设计的分布式存储框架&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://cloud.tencent.com/developer/article/1530515&quot;&gt;PacificA算法分析-腾讯云开发者社区-腾讯云&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;xi-tong-kuang-jia&quot;&gt;系统框架&lt;/h2&gt;
&lt;p&gt;整个系统框架主要有两部分组成：&lt;strong&gt;存储集群&lt;/strong&gt;和&lt;strong&gt;配置管理集群&lt;/strong&gt;。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;存储集群&lt;/strong&gt;：负责系统数据的读取和更新，通过使用多副本方式保证数据可靠性和可用性；&lt;br /&gt;
&lt;strong&gt;配置管理集群&lt;/strong&gt;：维护副本信息，包括副本的参与节点，主副本节点，当前副本的版本等。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;数据被存储在数据分片上，数据分片实际上是数据集合，每个数据分片的大小基本固定，在存储节点上，数据分片表现为磁盘上的一个大文件。而数据分片也是多副本的基本单位。&lt;/p&gt;
&lt;p&gt;配置管理集群维护的其实是分片的副本信息（分片位于哪些节点）。数据分片的副本称之为复制组（Replication Group）。因为每个存储节点上会存在众多的数据分片，因此，每个存储节点会位于多个复制组中。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://scp-net-cn.oss-cn-beijing.aliyuncs.com/blog-images/20240221181850.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; /&gt;&lt;/p&gt;
&lt;p&gt;配置管理集群维护所有分片的位置信息，配置管理集群使用Paxos协议维护该数据的一致性。存储集群以配置管理集群维护的分片位置信息为准。&lt;/p&gt;
&lt;h2 id=&quot;she-ji-mu-biao&quot;&gt;设计目标&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;High scalability, availability and throughput&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Flexibility and configurable&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Necessary features, extensibility&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Correct, simple and clean designs&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Good user experiences&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;    PacificA是一个读写都满足强一致的算法，它通过三个不变式保证了读写的primary的唯一性，读写的强一致性，故障恢复的可靠性。&lt;/p&gt;
&lt;p&gt;    它把数据的一致性和配置的一致性分开，使用额外的一致性组件（Configuration Manager）维护配置的一致性，结合lease机制保证了Primary Invariant，使得在同一时刻有且仅有一个primary。
    update操作时，要求所有的secondary均prepare当前update，primary commit当前update，保证了Committed Invariant, 使得读操作可以获取到最新数据，primary故障时，secondary也有全量的数据。&lt;/p&gt;
&lt;p&gt;    故障恢复机制保证了当secondary被选为primary时，其commit包含之前primary或secondary的commit，保证了Reconfiguration Invariant，使得在故障恢复后数据不会有丢失。&lt;/p&gt;
&lt;h2 id=&quot;shu-ju-fen-pian&quot;&gt;数据分片&lt;/h2&gt;
&lt;p&gt;本地存储设计要点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sequential IO&lt;/li&gt;
&lt;li&gt;Immutable files(append)&lt;/li&gt;
&lt;li&gt;Easy to take a snapshot&lt;/li&gt;
&lt;li&gt;Easy to handle failures&lt;/li&gt;
&lt;li&gt;Continue to update the data when we do query&lt;/li&gt;
&lt;/ul&gt;
&lt;img title=&quot;&quot; src=&quot;https://scp-net-cn.oss-cn-beijing.aliyuncs.com/blog-images/20240221153757.png&quot; alt=&quot;&quot; width=&quot;477&quot;&gt;
&lt;h2 id=&quot;xi-tong-mo-xing-he-qian-ti-tiao-jian&quot;&gt;系统模型和前提条件&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;No Byzantine Failure.&lt;/li&gt;
&lt;li&gt;Fail-stop and messages, when delivered, are delivered correctly.&lt;/li&gt;
&lt;li&gt;Network is unreliable (may  lose, reorder, duplicate messages, may partition)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;yi-zhi-xing-bao-zheng&quot;&gt;一致性保证&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Strong Consistency&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A total ordering of all requests yields the same responses that client received, reads must return the committed most up-to-date values&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Sequential Consistency&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;allows reads to return outdated values&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Weak Read Consistency&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Read can return results of even uncommitted operations&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;fu-zhi-xie-yi&quot;&gt;复制协议&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Primary/Backup protocol&lt;/li&gt;
&lt;li&gt;Two-phase protocol&lt;/li&gt;
&lt;li&gt;One-phase protocol&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;primary-backup-protocol&quot;&gt;Primary/Backup protocol&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Two-phase protocol&lt;/strong&gt;&lt;/p&gt;
&lt;img src=&quot;https://scp-net-cn.oss-cn-beijing.aliyuncs.com/blog-images/20240221155300.png&quot; title=&quot;&quot; alt=&quot;&quot; width=&quot;663&quot;&gt;
&lt;p&gt;&lt;strong&gt;Prepared and committed list&lt;/strong&gt;&lt;/p&gt;
&lt;img src=&quot;https://scp-net-cn.oss-cn-beijing.aliyuncs.com/blog-images/20240221155933.png&quot; title=&quot;&quot; alt=&quot;&quot; width=&quot;632&quot;&gt;
&lt;p&gt;pacificA副本数据使用主从式框架来保证数据一致性。分片的多个副本中存在一个主副本Primary和多个从副本Secondary。所有的数据更新和读取都进入主副本，当主副本出现故障无法访问时系统会从其他从副本中选择合适的节点作为新的主。&lt;/p&gt;
&lt;p&gt;在pacificA协议中，每个节点都维护&lt;/p&gt;
&lt;p&gt;数据更新的流程如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;更新记录进入主副本节点处理，为该记录分配Sn（Serial Number），然后将该记录插入prepare list，该list上的记录按照sn有序排列；&lt;/li&gt;
&lt;li&gt;主副本节点将携带sn的记录发往从节点，从节点同样将该记录插入到prepare list；&lt;/li&gt;
&lt;li&gt;一旦主节点收到所有从节点的响应，确定该记录已经被正确写入所有的从节点，那就将commit list向前移动，并将这些消息应用到主节点的状态机；&lt;/li&gt;
&lt;li&gt;主节点提交后即可给客户端返回响应，同时向所有从节点发送消息，告诉从节点可以提交刚刚写入的记录了。&lt;/li&gt;
&lt;/ol&gt;
&lt;img title=&quot;&quot; src=&quot;https://scp-net-cn.oss-cn-beijing.aliyuncs.com/blog-images/v2-299b37c6cfbfed4e2161313bc11a7ec6_r.jpg&quot; alt=&quot;&quot; width=&quot;629&quot;&gt;
&lt;p&gt;通过上面的分析可以知道，commit list和prepare list必然满足以下条件：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Commit Invariant: Let p be the primary and q be any replica
in the current configuration, committed &lt;em&gt;q&lt;/em&gt; ⊆ committed &lt;em&gt;p&lt;/em&gt; ⊆
prepared &lt;em&gt;q&lt;/em&gt; holds.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;所有的读需要全部发往主节点，这是因为客户端来读时，主节点有可能尚未将commit消息发送至从，因此，如果读从节点可能会无法获取最新数据。当然，如果应用能够忍受一定的窗口，那读从也无所谓。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;想到一个异常情况，当update执行过程中，primary挂掉了，导致更新失败，secondary已经被prepare了update，这时一个secondary被选为新的primary，将其所有的update commit，那之前失败的update操作数据不就出现在了数据中，导致与预期不符？&lt;/p&gt;
&lt;p&gt;pacificA算法中一个primary或secondary是一个数据实体，不应该是一个执行实体，所以当primary挂掉后，update任务不会执行失败，而是等待选出新的primary，并在其上commit这个update，保证不会出现数据不一致的情况&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;p-b-protocol-failure-scenarios&quot;&gt;P/B Protocol(Failure Scenarios)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Configuration&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Be consisted of primary and several backups&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Has a view number which increases by one each time the configurations changes.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Master(God) keeps the authoritative, most up-to-date configurations of all the groups.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;pacificA通过契约(lease)的方式来进行primary和secondary间的互相检测。primary会定期(lease period)向各节点请求契约，如果某个节点没有回复，则说明该节点已经故障，primary会向Configuration Manager请求移除该secondary。 如果过了(grace period), 一个secondary没有收到primary的请求，则认为primary故障，该secondary会向Configuration请求移除Primary，并将自己设置为primary。这里要注意&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;当多个secondary均发现primary故障，则按照first win原则，先请求的成为primary&lt;/li&gt;
&lt;li&gt;当出现网络分区时，primary会要求剔除secondary， secondary要求剔除primary，但由于lease period&amp;lt; grace period，可以保证primary先于secondary发现故障，并将secondary剔除&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;系统运行过程中难免出现节点宕机离线等诸多异常。如何保证在节点异常情况下协议的正常运行是分布式系统设计中的关键问题。pacificA是一种强一致协议，通过主节点来维护多副本数据一致性。因此，需要确保每个副本的唯一主，避免二主问题的发生就非常关键。&lt;/p&gt;
&lt;p&gt;pacificA使用了lease机制来保证不会产生二主问题。主节点与从节点维护心跳信息：主节点定期发送心跳，只要从节点响应该心跳，主节点就确定自己还是主。对于以下两种可能的异常：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果主节点在一定时间内（lease period）未收到从节点对心跳的回应，那主节点认为从节点异常，于是向配置管理服务汇报更新复制集拓扑，将该异常从节点从复制集中移除，同时，它也将自己降级不再作为主；&lt;/li&gt;
&lt;li&gt;如果从节点在一定时间内（grace period）未收到主节点的心跳信息，那么其认为主节点异常，于是向配置管理服务汇报回信复制集拓扑，将主节点从复制集中移除，同时将自己提升为新的主。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;分析可知，只要lease period &amp;lt;= grace peroid，就不会产生二主问题，因为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;假如主从之间出现网络分区。只要lease period &amp;lt;= grace peroid，主必然先检测到从没有回复的事件，于是他开始停止作为主服务，并且通知配置管理服务；&lt;/li&gt;
&lt;li&gt;由于lease period &amp;lt;= grace peroid，那么从节点检测到主节点异常则是在主节点停止作为主以后，此时该副本集是不存在主的，因此，必然不会产生二主现象。&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;为什么主在检测到从节点异常时需要停止自己作为主的身份?&lt;/p&gt;
&lt;p&gt;如果不这样有可能会出现多主情况。分析一下，主节点不停止自己作为主，继续对外提供更新服务，而直接向配置管理服务汇报从复制集中移除从节点的消息M1，而从节点经过一段时间后向配置管理服务汇报移除主节点并将自己提升为新主的消息M2，但是由于网络传输的不确定性，配置管理服务可能会先处理M2，于是问题来了，这时候就产生了两个主，破坏系统的强一致性。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;使用租约机制保证一致性是众多分布式系统的标准做法，例如GFS、Bigtable等。但是诸如GFS、Bigtable都是从一个集中式服务中申请lease，而pacificA则是一种去中心化式的租约机制。&lt;/p&gt;
&lt;p&gt;另外，主从之间的数据流动也天然发挥了心跳信息的功能，因此，只要主从之间有数据交换，就可以无需发送心跳。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;secondarygu-zhang&quot;&gt;secondary故障&lt;/h3&gt;
&lt;p&gt;    当一个scondary故障时，primary在向该secondary发送lease请求时会超时，primary向Configuration Manage发送Reconfiguration请求将该secondary从Configuration中移除&lt;/p&gt;
&lt;h3 id=&quot;primarygu-zhang&quot;&gt;primary故障&lt;/h3&gt;
&lt;p&gt;    当primary故障时， secondary在超过grace period没有收到primary的请求，就会向Configuration Manager发送Reconfiguraiont请求&lt;/p&gt;
&lt;p&gt;    要求将primary从configuration中移除并将自己选为primary。多个secondary竞争成为primary时，遵循first win原则。&lt;/p&gt;
&lt;p&gt;    当一个secondary被选为primary后 ,它会向所有的secondary发送prepare请求，要求所有的sencodary均以其pareparedList为准进行对齐，当收到所有secondary的ack后，primary将自己的commit point移动到最后，这个时候primary才能对外提供服务。&lt;/p&gt;
&lt;h3 id=&quot;wang-luo-fen-qu-de-chang-jing&quot;&gt;网络分区的场景&lt;/h3&gt;
&lt;p&gt;    网络分区场景下，primary认为secondary故障，secondary认为primary故障，但由于lease period小于grace period，所以primary会先与secondary发现故障，并向Congfiguration Manager发送请求移除secondary&lt;/p&gt;
&lt;h3 id=&quot;xin-jie-dian-jia-ru&quot;&gt;新节点加入&lt;/h3&gt;
&lt;p&gt;    新节点加入时，首先会先成为secondary candidate, 然后追平primary的preparedList,然后申请成为secondary。还有一种情况是之前故障的节点恢复加入，这个时候会复用之前的preparedlist并追平secondary的preparedlist, 然后申请成为secondary。&lt;/p&gt;
&lt;h3 id=&quot;primary-invariant&quot;&gt;Primary Invariant&lt;/h3&gt;
&lt;p&gt;在pacificA算法中，要保证primary不变式Primary Invariant，即&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;同一个时刻只有一个副本认为自己是primary&lt;/li&gt;
&lt;li&gt;configuration Manager也认为其是primary。
从前面的故障恢复可以看到pacificA算法通过lease（契约）机制保证了这个不变式&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;reconfiguration-invariant&quot;&gt;Reconfiguration Invariant&lt;/h3&gt;
&lt;p&gt;    重新配置不变式：当一个新的primary在T时刻完成reconfiguration,那么T时刻之前任意节点（包括原primary）的committedList都是新的primary当前committedList的前缀。&lt;/p&gt;
&lt;p&gt;    该不变式保证了reconfiguration过程中没有数据丢失，由于update机制保证了任意的sencondary都有所有的数据，而reconfiguration重新选primary要求新的primary commit其所有的prepareList,因此这个不变式可以得到保证。&lt;/p&gt;
&lt;h2 id=&quot;can-kao-zi-liao&quot;&gt;参考资料&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;https://www.zhihu.com/question/59320850/answer/1578135865&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://cloud.tencent.com/developer/article/1530515&quot;&gt;PacificA算法分析-腾讯云开发者社区-腾讯云&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;https://blog.51cto.com/u_15060462/2649440&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://www.cnblogs.com/holidays/p/pacificA.html&quot;&gt;PacificA协议 - holidays - 博客园&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;https://helloyoubeautifulthing.net/blog/2019/01/31/pacifica-notes/&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://juejin.cn/post/6844903504964747278&quot;&gt;小米开源分布式KV存储系统Pegasus - 掘金&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;https://zhuanlan.zhihu.com/p/260005664&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/apache/incubator-pegasus&quot;&gt;GitHub - apache/incubator-pegasus: Apache Pegasus - A horizontally scalable, strongly consistent and high-performance key-value store&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;https://www.microsoft.com/en-us/research/wp-content/uploads/2008/02/tr-2008-25.pdf&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;http://bos.itdks.com/2e8c552646f44c66b038cb76fd728167.pdf&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>BTrace User&#39;s Guide</title>
        <published>2020-03-18T12:13:32+05:30</published>
        <updated>2020-03-18T12:13:32+05:30</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/java-btrace-tour/"/>
        <id>https://scp.net.cn/blog/java-btrace-tour/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/java-btrace-tour/">&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://gist.github.com/yulewei/53339ccced8837686895e3c9f45557cc&quot;&gt;原文地址&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://gitee.com/dllen/dllen-demos/tree/master/btrace-demo&quot;&gt;实验Demo&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;注意：btrace 版本和包名已经更新，编写 btrace 脚本时使用以下依赖，但是整体使用方式基本没有变化；&lt;/p&gt;
&lt;p&gt;Q：Maven 无法下载 BTrace 的包。&lt;/p&gt;
&lt;p&gt;A：手动将 BTrace bin 文件夹下的 jar 安装到本地 Maven 仓库。&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;export&lt;/span&gt;&lt;span&gt; BTRACE_HOME&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;mvn&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; install:install-file -Dfile=&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;${&lt;/span&gt;&lt;span&gt;BTRACE_HOME&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;/libs/btrace-agent.jar -DgroupId=org.openjdk.btrace -DartifactId=btrace-agent -Dversion=2.1.1 -Dpackaging=jar&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;mvn&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; install:install-file -Dfile=&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;${&lt;/span&gt;&lt;span&gt;BTRACE_HOME&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;/libs/btrace-client.jar -DgroupId=org.openjdk.btrace -DartifactId=btrace-client -Dversion=2.0.1 -Dpackaging=jar&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;mvn&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; install:install-file -Dfile=&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;${&lt;/span&gt;&lt;span&gt;BTRACE_HOME&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;/libs/btrace-boot.jar -DgroupId=org.openjdk.btrace -DartifactId=btrace-boot -Dversion=2.0.1 -Dpackaging=jar&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;xml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    &amp;lt;groupId&amp;gt;&lt;/span&gt;&lt;span&gt;org.openjdk.btrace&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    &amp;lt;artifactId&amp;gt;&lt;/span&gt;&lt;span&gt;btrace-client&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    &amp;lt;version&amp;gt;&lt;/span&gt;&lt;span&gt;2.1.0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    &amp;lt;groupId&amp;gt;&lt;/span&gt;&lt;span&gt;org.openjdk.btrace&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    &amp;lt;artifactId&amp;gt;&lt;/span&gt;&lt;span&gt;btrace-boot&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    &amp;lt;version&amp;gt;&lt;/span&gt;&lt;span&gt;2.1.0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    &amp;lt;groupId&amp;gt;&lt;/span&gt;&lt;span&gt;org.openjdk.btrace&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    &amp;lt;artifactId&amp;gt;&lt;/span&gt;&lt;span&gt;btrace-agent&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    &amp;lt;version&amp;gt;&lt;/span&gt;&lt;span&gt;2.1.0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;
&lt;h1 id=&quot;btrace-user-s-guide&quot;&gt;BTrace User’s Guide&lt;/h1&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/blob/master/docs/usersguide.html&quot;&gt;https://github.com/btraceio/btrace/blob/master/docs/usersguide.html&lt;/a&gt;
&lt;a rel=&quot;external&quot; href=&quot;https://web.archive.org/web/20170410014122/https://kenai.com/projects/btrace/pages/UserGuide&quot;&gt;https://web.archive.org/web/20170410014122/https://kenai.com/projects/btrace/pages/UserGuide&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/java-btrace-tour/#btrace-terminology&quot;&gt;BTrace Terminology&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/java-btrace-tour/#btrace-program-structure&quot;&gt;BTrace Program Structure&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/java-btrace-tour/#btrace-restrictions&quot;&gt;BTrace Restrictions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/java-btrace-tour/#a-simple-btrace-program&quot;&gt;A simple BTrace program&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/java-btrace-tour/#steps-to-run-btrace&quot;&gt;Steps to run BTrace&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/java-btrace-tour/#btrace-command-line&quot;&gt;BTrace Command Line&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/java-btrace-tour/#optional&quot;&gt;optional&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/java-btrace-tour/#pre-compiling-btrace-scripts&quot;&gt;Pre-compiling BTrace scripts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/java-btrace-tour/#starting-an-application-with-btrace-agent&quot;&gt;Starting an application with BTrace agent&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/java-btrace-tour/#btrace-annotations&quot;&gt;BTrace Annotations&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/java-btrace-tour/#method-annotations&quot;&gt;Method Annotations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/java-btrace-tour/#argument-annotations&quot;&gt;Argument Annotations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/java-btrace-tour/#field-annotations&quot;&gt;Field Annotations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/java-btrace-tour/#class-annotations&quot;&gt;Class Annotations&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/java-btrace-tour/#dtrace-integration&quot;&gt;DTrace Integration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scp.net.cn/blog/java-btrace-tour/#btrace-samples&quot;&gt;BTrace Samples&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;BTrace&lt;/strong&gt; is a safe, dynamic tracing tool for Java. BTrace works by dynamically (bytecode) instrumenting classes of a running Java program. BTrace inserts tracing actions into the classes of a running Java program and hotswaps the traced program classes.&lt;/p&gt;
&lt;h2 id=&quot;btrace-terminology&quot;&gt;BTrace Terminology&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Probe Point&lt;/strong&gt;&lt;br/&gt;
“location” or “event” at which a set of tracing statements are executed. Probe point is “place” or “event” of interest where we want to execute some tracing statements.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Trace Actions or Actions&lt;/strong&gt;&lt;br/&gt;
Trace statements that are executed whenever a probe “fires”.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Action Methods&lt;/strong&gt;&lt;br/&gt;
BTrace trace statements that are executed when a probe fires are defined inside a static method a class. Such methods are called “action” methods.&lt;/p&gt;
&lt;h2 id=&quot;btrace-program-structure&quot;&gt;BTrace Program Structure&lt;/h2&gt;
&lt;p&gt;A BTrace program is a plain Java class that has one or more &lt;code&gt;public static void&lt;/code&gt; methods that are annotated with &lt;a href=&quot;https://scp.net.cn/blog/java-btrace-tour/#btrace-annotations&quot;&gt;BTrace annotations&lt;/a&gt;. The annotations are used to specify traced program “locations” (also known as “probe points”). The tracing actions are specified inside the static method bodies. These static methods are referred as “action” methods.&lt;/p&gt;
&lt;h2 id=&quot;btrace-restrictions&quot;&gt;BTrace Restrictions&lt;/h2&gt;
&lt;p&gt;To guarantee that the tracing actions are “read-only” (i.e., the trace actions don’t change the state of the program traced) and bounded (i.e., trace actions terminate in bounded time), a BTrace program is allowed to do only a restricted set of actions. In particular, a BTrace class&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;can &lt;strong&gt;not&lt;/strong&gt; create new objects.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;can &lt;strong&gt;not&lt;/strong&gt; create new arrays.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;can &lt;strong&gt;not&lt;/strong&gt; throw exceptions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;can &lt;strong&gt;not&lt;/strong&gt; catch exceptions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;can &lt;strong&gt;not&lt;/strong&gt; make arbitrary instance or static method calls - only the &lt;strong&gt;&lt;code&gt;public static&lt;/code&gt;&lt;/strong&gt; methods of &lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https://static.javadoc.io/com.sun.tools.btrace/btrace-client/1.2.3/com/sun/btrace/BTraceUtils.html&quot;&gt;com.sun.btrace.BTraceUtils&lt;/a&gt;&lt;/strong&gt; class may be called from a BTrace program.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;can &lt;strong&gt;not&lt;/strong&gt; assign to static or instance fields of target program’s classes and objects. But, BTrace class can assign to it’s own static fields (“trace state” can be mutated).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;can &lt;strong&gt;not&lt;/strong&gt; have instance fields and methods. Only &lt;strong&gt;&lt;code&gt;static public void&lt;/code&gt;&lt;/strong&gt; returning methods are allowed for a BTrace class. And all fields have to be static.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;can &lt;strong&gt;not&lt;/strong&gt; have outer, inner, nested or local classes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;can &lt;strong&gt;not&lt;/strong&gt; have synchronized blocks or synchronized methods.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;can &lt;strong&gt;not&lt;/strong&gt; have loops (&lt;strong&gt;&lt;code&gt;for, while, do..while&lt;/code&gt;&lt;/strong&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;can &lt;strong&gt;not&lt;/strong&gt; extend arbitrary class (super class has to be java.lang.Object)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;can &lt;strong&gt;not&lt;/strong&gt; implement interfaces.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;can &lt;strong&gt;not&lt;/strong&gt; contains assert statements.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;can &lt;strong&gt;not&lt;/strong&gt; use class literals.&lt;/p&gt;
&lt;h2 id=&quot;a-simple-btrace-program&quot;&gt;A simple BTrace program&lt;/h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// import all BTrace annotations&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; com&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;sun&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;btrace&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;annotations&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// import statics from BTraceUtils class&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import static&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; com&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;sun&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;btrace&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;BTraceUtils&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;*;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;// @BTrace annotation tells that this is a BTrace program&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color: #D08770;&quot;&gt;BTrace&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;public class&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; HelloWorld&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  // @OnMethod annotation tells where to probe.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  // In this example, we are interested in entry &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  // into the Thread.start() method. &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  @&lt;/span&gt;&lt;span style=&quot;color: #D08770;&quot;&gt;OnMethod&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      clazz&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;java.lang.Thread&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      method&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;start&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  public static void&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; func&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;      // println is defined in BTraceUtils&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;      // you can only call the static methods of BTraceUtils&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;      println&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;about to start a thread!&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above BTrace program can be run against a running Java process. This program will print “about to start a thread!” at the BTrace client whenever the target program is about to start a thread by &lt;code&gt;Thread.start()&lt;/code&gt; method. There are other interesting probe points possible. For example, we can insert trace action at return from a method, exception return from a method, a field get or set within method(s), object/array creation, line number(s), throwing an exception. Please refer to the &lt;a href=&quot;https://scp.net.cn/blog/java-btrace-tour/#btrace-annotations&quot;&gt;@OnMethod and other annotations&lt;/a&gt; for details.&lt;/p&gt;
&lt;h2 id=&quot;steps-to-run-btrace&quot;&gt;Steps to run BTrace&lt;/h2&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Find the process id of the target Java process that you want to trace. You can use &lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;http://java.sun.com/javase/6/docs/technotes/tools/share/jps.html&quot;&gt;jps&lt;/a&gt;&lt;/strong&gt; tool to find the pid.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Write a BTrace program - you may want to start modifying one of the &lt;strong&gt;&lt;a href=&quot;https://scp.net.cn/blog/java-btrace-tour/#btrace-samples&quot;&gt;samples&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run &lt;strong&gt;btrace&lt;/strong&gt; tool by the following command line:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;btrace &amp;lt;pid&amp;gt; &amp;lt;btrace-script&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;btrace-command-line&quot;&gt;BTrace Command Line&lt;/h2&gt;
&lt;p&gt;BTrace is run using the command line tool &lt;strong&gt;btrace&lt;/strong&gt; as shown below:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;btrace [-I &amp;lt;include-path&amp;gt;] [-p &amp;lt;port&amp;gt;] [-cp &amp;lt;classpath&amp;gt;] &amp;lt;pid&amp;gt; &amp;lt;btrace-script&amp;gt; [&amp;lt;args&amp;gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;where&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;include-path&lt;/code&gt; is a set of include directories that are searched for header files. BTrace includes a simple preprocess with support for #define, #include and conditional compilation. It is &lt;strong&gt;not&lt;/strong&gt; like a complete C/C++ preprocessor - but a useful subset. See the sample “ThreadBean.java”. If -I is not specified, BTrace skips the preprocessor invocation step.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;port&lt;/code&gt; is the port in which BTrace agent listens. This is optional argument.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;classpath&lt;/code&gt; is set of directories, jar files where BTrace searches for classes during compilation. Default is “.”.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;pid&lt;/code&gt; is the process id of the traced Java program&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;btrace-script&lt;/code&gt; is the trace program. If it is a “.java”, then it is compiled before submission. Or else, it is assumed to be pre-compiled [i.e., it has to be a .class] and submitted.&lt;/p&gt;
&lt;h3 id=&quot;optional&quot;&gt;optional&lt;/h3&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;port&lt;/code&gt; is the server socket port at which BTrace agent listens for clients. Default is 2020.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;path&lt;/code&gt; is the classpath used for compiling BTrace program. Default is “.”.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;args&lt;/code&gt; is command line arguments passed to BTrace program. BTrace program can access these using the built-in functions “$” and “$length”.&lt;/p&gt;
&lt;h2 id=&quot;pre-compiling-btrace-scripts&quot;&gt;Pre-compiling BTrace scripts&lt;/h2&gt;
&lt;p&gt;It is possible to precompile BTrace program using &lt;strong&gt;btracec&lt;/strong&gt; script. btracec is a javac-like program that takes a BTrace program and produces a .class file.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;btracec [-I &amp;lt;include-path&amp;gt;] [-cp &amp;lt;classpath&amp;gt;] [-d &amp;lt;directory&amp;gt;] &amp;lt;one-or-more-BTrace-.java-files&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;where&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;include-path&lt;/code&gt; is a set of include directories that are searched for header files. BTrace includes a simple preprocess with support for #define, #include and conditional compilation. It is &lt;strong&gt;not&lt;/strong&gt; like a complete C/C++ preprocessor - but a useful subset. See the sample “ThreadBean.java”. If -I is not specified, BTrace skips the preprocessor invocation step.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;classpath&lt;/code&gt; is the classpath used for compiling BTrace program(s). Default is “.”&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;directory&lt;/code&gt; is the output directory where compiled .class files are stored. Default is “.”.
This script uses BTrace compiler class - rather than regular javac and therefore will validate your BTrace program at compile time [so that you can avoid BTrace verify error at runtime].&lt;/p&gt;
&lt;h2 id=&quot;starting-an-application-with-btrace-agent&quot;&gt;Starting an application with BTrace agent&lt;/h2&gt;
&lt;p&gt;So far, we saw how to trace a running Java program. It is also possible to start an application with BTrace agent in it. If you want to start tracing the application from the very “beginning”, you may want to start the app with BTrace agent and specify a trace script along with it [i.e., BTrace agent is attach-on-demand loadable as well as pre-loadable agent] You can use the following command to start an app and specify BTrace script file. But, you need to &lt;a href=&quot;https://scp.net.cn/blog/java-btrace-tour/#pre-compiling-btrace-scripts&quot;&gt;precompile your BTrace script&lt;/a&gt; for this kind of usage.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;java -javaagent:btrace-agent.jar=script=&amp;lt;pre-compiled-btrace-script&amp;gt; &amp;lt;MainClass&amp;gt; &amp;lt;AppArguments&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When starting the application this way, the trace output goes to a file named &amp;lt;btrace-class-file-name&amp;gt;.btrace in the current directory. Also, you can avoid starting server for other remote BTrace clients by specifying &lt;code&gt;noServer=true&lt;/code&gt; as an argument to the BTrace agent.
There is a convenient script called &lt;strong&gt;btracer&lt;/strong&gt; to do the above:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;btracer &amp;lt;pre-compiled-btrace.class&amp;gt; &amp;lt;application-main-class&amp;gt; &amp;lt;application-args&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;btrace-annotations&quot;&gt;BTrace Annotations&lt;/h2&gt;
&lt;h3 id=&quot;method-annotations&quot;&gt;Method Annotations&lt;/h3&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https://static.javadoc.io/com.sun.tools.btrace/btrace-client/1.2.3/com/sun/btrace/annotations/OnMethod.html&quot;&gt;@com.sun.btrace.annotations.OnMethod&lt;/a&gt;&lt;/strong&gt; annotation can be used to specify target class(es), target method(s) and “location(s)” within the method(s). An action method annotated by this annotation is called when the matching method(s) reaches specified the location. In &lt;code&gt;OnMethod&lt;/code&gt; annotation, traced class name is specified by “clazz” property and traced method is specified by “method” property. “clazz” may be a fully qualified class name (like &lt;strong&gt;&lt;code&gt;java.awt.Component&lt;/code&gt;&lt;/strong&gt; or a regular expression specified within two forward slashes. Refer to the samples &lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/NewComponent.java&quot;&gt;NewComponent.java&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/Classload.java&quot;&gt; Classload.java&lt;/a&gt;&lt;/strong&gt;. The regular expression can match zero or more classes in which case all matching classes are instrumented. For example &lt;strong&gt;&lt;code&gt;/java\\.awt\\..+/&lt;/code&gt;&lt;/strong&gt; matches all classes in java.awt package. Also, method name can be a regular expression as well - matching zero or more methods. Refer to the sample &lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/MultiClass.java&quot;&gt;MultiClass.java&lt;/a&gt;&lt;/strong&gt;. There is another way to abstractly specify traced class(es) and method(s). Traced classes and methods may be specified by annotation. For example, if the “clazz” attribute is specified as &lt;strong&gt;&lt;code&gt;@javax.jws.WebService&lt;/code&gt;&lt;/strong&gt; BTrace will instrument all classes that are annotated by the WebService annotation. Similarly, method level annotations may be used to specify methods abstractly. Refer to the sample &lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/WebServiceTracker.java&quot;&gt;WebServiceTracker.java&lt;/a&gt;&lt;/strong&gt;. It is also possible to combine regular expressions with annotations - like &lt;strong&gt;&lt;code&gt;@/com\\.acme\\..+/&lt;/code&gt;&lt;/strong&gt; matches any class that is annotated by any annotation that matches the given regular expression. It is possible to match multiple classes by specifying super type. i.e., match all classes that are subtypes of a given super type. &lt;strong&gt;&lt;code&gt;+java.lang.Runnable&lt;/code&gt;&lt;/strong&gt; matches all classes implementing java.lang.Runnable interface. Refer to the sample &lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/SubtypeTracer.java&quot;&gt;SubtypeTracer.java&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https://static.javadoc.io/com.sun.tools.btrace/btrace-client/1.2.3/com/sun/btrace/annotations/OnTimer.html&quot;&gt;@com.sun.btrace.annotations.OnTimer&lt;/a&gt;&lt;/strong&gt; annotation can be used to specify tracing actions that have to run periodically once every N milliseconds. Time period is specified as long “value” property of this annotation. Refer to the sample &lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/Histogram.java&quot;&gt;Histogram.java&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https://static.javadoc.io/com.sun.tools.btrace/btrace-client/1.2.3/com/sun/btrace/annotations/OnError.html&quot;&gt;@com.sun.btrace.annotations.OnError&lt;/a&gt;&lt;/strong&gt; annotation can be used to specify actions that are run whenever any exception is thrown by tracing actions of some other probe. BTrace method annotated by this annotation is called when any exception is thrown by any of the other BTrace action methods in the same BTrace class.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https://static.javadoc.io/com.sun.tools.btrace/btrace-client/1.2.3/com/sun/btrace/annotations/OnExit.html&quot;&gt;@com.sun.btrace.annotations.OnExit&lt;/a&gt;&lt;/strong&gt; annotation can be used to specify actions that are run when BTrace code calls “exit(int)” built-in function to finish the tracing “session”. Refer to the sample &lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/ProbeExit.java&quot;&gt;ProbeExit.java&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https://static.javadoc.io/com.sun.tools.btrace/btrace-client/1.2.3/com/sun/btrace/annotations/OnEvent.html&quot;&gt;@com.sun.btrace.annotations.OnEvent&lt;/a&gt;&lt;/strong&gt; annotation is used to associate tracing methods with “external” events send by BTrace client. BTrace methods annotated by this annotation are called when BTrace client sends an “event”. Client may send an event based on some form of user request to send (like pressing Ctrl-C or a GUI menu). String value may used as the name of the event. This way certain tracing actions can be executed whenever an external event “fires”. As of now, the command line BTrace client sends “events” whenever use presses Ctrl-C (SIGINT). On SIGINT, a console menu is shown to send an event or exit the client [which is the default for SIGINT]. Refer to the sample &lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/HistoOnEvent.java&quot;&gt;HistoOnEvent.java&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https://static.javadoc.io/com.sun.tools.btrace/btrace-client/1.2.3/com/sun/btrace/annotations/OnLowMemory.html&quot;&gt;@com.sun.btrace.annotations.OnLowMemory&lt;/a&gt;&lt;/strong&gt; annotation can be used to trace memory threshold exceed event. See sample &lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/MemAlerter.java&quot;&gt;MemAlerter.java&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https://static.javadoc.io/com.sun.tools.btrace/btrace-client/1.2.3/com/sun/btrace/annotations/OnProbe.html&quot;&gt;@com.sun.btrace.annotations.OnProbe&lt;/a&gt;&lt;/strong&gt; annotation can be used to specify to avoid using implementation internal classes in BTrace scripts. &lt;code&gt;@OnProbe&lt;/code&gt; probe specifications are mapped to one or more &lt;code&gt;@OnMethod&lt;/code&gt; specifications by the BTrace VM agent. Currently, this mapping is done using a XML probe descriptor file [accessed by the BTrace agent]. Refer to the sample &lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/SocketTracker1.java&quot;&gt;SocketTracker1.java&lt;/a&gt;&lt;/strong&gt; and associated probe descriptor file &lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/java.net.socket.xml&quot;&gt;java.net.socket.xml&lt;/a&gt;&lt;/strong&gt;. When running this sample, this xml file needs to be copied in the directory where the target JVM runs (or fix probeDescPath option in btracer.bat to point to whereever the .xml file is).&lt;/p&gt;
&lt;h3 id=&quot;argument-annotations&quot;&gt;Argument Annotations&lt;/h3&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://static.javadoc.io/com.sun.tools.btrace/btrace-client/1.2.3/com/sun/btrace/annotations/Self.html&quot;&gt;@com.sun.btrace.annotations.Self&lt;/a&gt; annotation can be used to mark an argument to hold &lt;strong&gt;this&lt;/strong&gt; (or &lt;strong&gt;self&lt;/strong&gt;) value. Refer to the samples &lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/AWTEventTracer.java&quot;&gt;AWTEventTracer.java&lt;/a&gt; or &lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/AllCalls1.java&quot;&gt;AllCalls1.java&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://static.javadoc.io/com.sun.tools.btrace/btrace-client/1.2.3/com/sun/btrace/annotations/Return.html&quot;&gt;@com.sun.btrace.annotations.Return&lt;/a&gt; annotation can be used to mark an argument to hold the return value. Refer to the sample &lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/Classload.java&quot;&gt;Classload.java&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://static.javadoc.io/com.sun.tools.btrace/btrace-client/1.2.3/com/sun/btrace/annotations/ProbeClassName.html&quot;&gt;@com.sun.btrace.annotations.ProbeClassName (since 1.1)&lt;/a&gt; annotation can be used to mark an argument to hold the probed class name value. Refer to the sample &lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/AllMethods.java&quot;&gt;AllMethods.java&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://static.javadoc.io/com.sun.tools.btrace/btrace-client/1.2.3/com/sun/btrace/annotations/ProbeMethodName.html&quot;&gt;@com.sun.btrace.annotations.ProbeMethodName (since 1.1)&lt;/a&gt; annotation can be used to mark an argument to hold the probed method name. Refer to the sample &lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/WebServiceTracker.java&quot;&gt;WebServiceTracker.java&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;since 1.2 it accepts boolean parameter &lt;strong&gt;fqn&lt;/strong&gt; to get a fully qualified probed method name&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://static.javadoc.io/com.sun.tools.btrace/btrace-client/1.2.3/com/sun/btrace/annotations/Duration.html&quot;&gt;@com.sun.btrace.annotations.Duration&lt;/a&gt; annotation can be used to mark an argument to hold the duration of the method call in nanoseconds. The argument must be a long. Use with &lt;strong&gt;Kind.RETURN&lt;/strong&gt; or &lt;strong&gt;Kind.ERROR&lt;/strong&gt; locations.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://static.javadoc.io/com.sun.tools.btrace/btrace-client/1.2.3/com/sun/btrace/annotations/TargetInstance.htm&quot;&gt;@com.sun.btrace.annotations.TargetInstance (since 1.1)&lt;/a&gt; annotation can be used to mark an argument to hold the called instance value. Refer to the sample &lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/AllCalls2.java&quot;&gt;AllCalls2.java&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://static.javadoc.io/com.sun.tools.btrace/btrace-client/1.2.3/com/sun/btrace/annotations/TargetMethodOrField.html&quot;&gt;@com.sun.btrace.annotations.TargetMethodOrField (since 1.1)&lt;/a&gt; can be used to mark an argument to hold the called method name. Refer to the samples &lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/AllCalls1.java&quot;&gt;AllCalls1.java&lt;/a&gt; or &lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/AllCalls2.java&quot;&gt;AllCalls2.java&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;since 1.2 it accepts boolean parameter &lt;strong&gt;fqn&lt;/strong&gt; to get a fully qualified target method name&lt;/p&gt;
&lt;h4 id=&quot;unannotated-arguments&quot;&gt;Unannotated arguments&lt;/h4&gt;
&lt;p&gt;The unannotated BTrace probe method arguments are used for the signature matching and therefore they must appear in the order they are defined in the traced method. However, they can be interleaved with any number of annotated arguments. If an argument of type *AnyType[]* is used it will “eat” all the rest of the arguments in they order. The exact meaning of the unannotated arguments depends on the &lt;strong&gt;Location&lt;/strong&gt; used:&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Kind.ENTRY, Kind.RETURN&lt;/strong&gt;- the probed method arguments&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Kind.THROW&lt;/strong&gt; - the thrown exception&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Kind.ARRAY_SET, Kind.ARRAY_GET&lt;/strong&gt; - the array index&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Kind.CATCH&lt;/strong&gt; - the caught exception&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Kind.FIELD_SET&lt;/strong&gt; - the field value&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Kind.LINE&lt;/strong&gt; - the line number&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Kind.NEW&lt;/strong&gt; - the class name&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Kind.ERROR&lt;/strong&gt; - the thrown exception&lt;/p&gt;
&lt;h3 id=&quot;field-annotations&quot;&gt;Field Annotations&lt;/h3&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https://static.javadoc.io/com.sun.tools.btrace/btrace-client/1.2.3/com/sun/btrace/annotations/Export.html&quot;&gt;@com.sun.btrace.annotations.Export&lt;/a&gt;&lt;/strong&gt; annotation can be used with BTrace fields (static fields) to specify that the field has to be mapped to a jvmstat counter. Using this, a BTrace program can expose tracing counters to external jvmstat clients (such as jstat). Refer to the sample &lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/ThreadCounter.java&quot;&gt;ThreadCounter.java&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https://static.javadoc.io/com.sun.tools.btrace/btrace-client/1.2.3/com/sun/btrace/annotations/Property.html&quot;&gt;@com.sun.btrace.annotations.Property&lt;/a&gt;&lt;/strong&gt; annotation can be used to flag a specific (static) field as a MBean attribute. If a BTrace class has atleast one static field with &lt;code&gt;@Property&lt;/code&gt; attribute, then a MBean is created and registered with platform MBean server. JMX clients such as VisualVM, jconsole can be used to view such BTrace MBeans. After attaching BTrace to the target program, you can attach VisualVM or jconsole to the same program and view the newly created BTrace MBean. With VisualVM and jconsole, you can use MBeans tab to view the BTrace domain and check out it’s attributes. Refer to the samples &lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/ThreadCounterBean.java&quot;&gt;ThreadCounterBean&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/HistogramBean.java&quot;&gt;HistogramBean.java&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https://static.javadoc.io/com.sun.tools.btrace/btrace-client/1.2.3/com/sun/btrace/annotations/TLS.html&quot;&gt;@com.sun.btrace.annotations.TLS&lt;/a&gt;&lt;/strong&gt; annotation can be used with BTrace fields (static fields) to specify that the field is a thread local field. Each Java thread gets a separate “copy” of the field. These thread local fields may be used by BTrace programs to identify whether we reached multiple probe actions from the same thread or not. Refer to the samples &lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/OnThrow.java&quot;&gt;OnThrow.java&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/WebServiceTracker.java&quot;&gt;WebServiceTracker.java&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;class-annotations&quot;&gt;Class Annotations&lt;/h3&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https://static.javadoc.io/com.sun.tools.btrace/btrace-client/1.2.3/com/sun/btrace/annotations/DTrace.html&quot;&gt;@com.sun.btrace.annotations.DTrace&lt;/a&gt;&lt;/strong&gt; annotation can be used to associate a simple one-liner D-script (inlined in BTrace Java class) with the BTrace program. Refer to the sample &lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/DTraceInline.java&quot;&gt;DTraceInline.java&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https://static.javadoc.io/com.sun.tools.btrace/btrace-client/1.2.3/com/sun/btrace/annotations/DTraceRef.html&quot;&gt;@com.sun.btrace.annotations.DTraceRef&lt;/a&gt;&lt;/strong&gt; annotation can be used to associate a D-script (stored in a separate file) with the BTrace program. Refer to the sample &lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/DTraceRefDemo.java&quot;&gt;DTraceRefDemo.java&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https://static.javadoc.io/com.sun.tools.btrace/btrace-client/1.2.3/com/sun/btrace/annotations/BTrace.html&quot;&gt;@com.sun.btrace.annotations.BTrace&lt;/a&gt;&lt;/strong&gt; annotation must be used to designate a given Java class as a BTrace program. This annotation is enforced by the BTrace compiler as well as by the BTrace agent.&lt;/p&gt;
&lt;h2 id=&quot;dtrace-integration&quot;&gt;DTrace Integration&lt;/h2&gt;
&lt;p&gt;Solaris DTrace is a dynamic, safe tracing system for Solaris programs - both kernel and user land programs. Because of the obvious parallels b/w DTrace and BTrace, it is natural to expect integration b/w BTrace and DTrace. There are two ways in which BTrace is integrated with DTrace.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;BTrace program can raise a DTrace probe - by calling &lt;code&gt;dtraceProbe&lt;/code&gt; – see &lt;code&gt;BTraceUtils&lt;/code&gt; javadoc referred above. For this feature to work, you need to be running on &lt;strong&gt;Solaris 10 or beyond&lt;/strong&gt;. For other platforms (Solaris 9 or below or any other OS), &lt;code&gt;dtraceProbe()&lt;/code&gt; will be a no-op.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;BTrace program can associate a D-script with it– by &lt;code&gt;@DTrace&lt;/code&gt; annotation (if the D-script is a simple one liner) or by &lt;code&gt;@DTraceRef&lt;/code&gt; if the D-script is longer and hence stored outside of the BTrace program. See DTrace integration samples in the BTrace samples section below. This feature works using the &lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;http://www.opensolaris.org/os/project/dtrace-chime/java_dtrace_api/&quot;&gt;DTrace Java API&lt;/a&gt;&lt;/strong&gt;. For this DTrace feature to work (o.e., being able to run associated D-script), you need to be running on &lt;strong&gt;Solaris 11 build 35 or beyond&lt;/strong&gt;. You may want to check whether you have &lt;strong&gt;/usr/share/lib/java/dtrace.jar&lt;/strong&gt; on your machine or not. &lt;code&gt;@DTrace&lt;/code&gt; and &lt;code&gt;@DTraceRef&lt;/code&gt; annotations are ignored on other platforms (Solaris 10 or below or any other OS).&lt;/p&gt;
&lt;h2 id=&quot;btrace-samples&quot;&gt;BTrace Samples&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples&quot;&gt;BTrace samples&lt;/a&gt;&lt;/strong&gt;
One lines about samples:&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/AWTEventTracer.java&quot;&gt;AWTEventTracer.java&lt;/a&gt; - demonstates tracing of AWT events by instrumenting &lt;code&gt;EventQueue.dispatchEvent()&lt;/code&gt; method. Can filter events by instanceof check. This sample filters and prints only focus events.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/AllLines.java&quot;&gt;AllLines.java&lt;/a&gt; - demonstates line number based BTrace probes. It is possible to probe into any class (or classes) and line number(s). When the specified line number(s) of specified class(es) is reached, the BTrace probe fires and the corresponding action is executed.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/ArgArray.java&quot;&gt;ArgArray.java&lt;/a&gt; - prints all input arguments in every &lt;code&gt;readXXX&lt;/code&gt; method of every class in java.io package. Demonstrates argument array access and multiple class/method matching in probe specifications.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/Classload.java&quot;&gt;Classload.java&lt;/a&gt; - prints stack trace on every successful classload (&lt;code&gt;defineClass&lt;/code&gt; returns) by any userdefined class loader.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/CommandArg.java&quot;&gt;CommandArg.java&lt;/a&gt; - demonstrates BTrace command line argument access.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/Deadlock.java&quot;&gt;Deadlock.java&lt;/a&gt; - demonstrates &lt;code&gt;@OnTimer&lt;/code&gt; probe and &lt;code&gt;deadlock()&lt;/code&gt; built-in function.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/DTraceInline.java&quot;&gt;DTraceInline.java&lt;/a&gt; - demonstrates &lt;code&gt;@DTrace&lt;/code&gt; annotation to associate a simple one-line D-script with the BTrace program.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/DTraceRefDemo.java&quot;&gt;DTraceRefDemo.java&lt;/a&gt; - demonstrates &lt;code&gt;@DTraceRef&lt;/code&gt; annotation to associate a D-script file with the BTrace program. This sample associates &lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/classload.d&quot;&gt;classload.d&lt;/a&gt; with itself.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/FileTracker.java&quot;&gt;FileTracker.java&lt;/a&gt; - prints file open for read/write by probing into &lt;code&gt;File{Input/Output}Stream&lt;/code&gt; constructor entry points.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/FinalizeTracker.java&quot;&gt;FinalizeTracker.java&lt;/a&gt; - demonstrates that we can print all fields of an object and access (private) fields (read-only) as well. This is useful in debugging / troubleshooting scenarios. This sample prints info on &lt;code&gt;close() /finalize()&lt;/code&gt; methods of &lt;code&gt;java.io.FileInputStream&lt;/code&gt; class.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/Histogram.java&quot;&gt;Histogram.java&lt;/a&gt; - demonstates usage of BTrace maps for collecting histogram (of &lt;code&gt;javax.swing.JComponent&lt;/code&gt; objects created by an app - histogram by subclass name and count).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/HistogramBean.java&quot;&gt;HistogramBean.java&lt;/a&gt; - demonstates JMX integration. This sample exposes a Map as MBean attribute using &lt;code&gt;@Property&lt;/code&gt; annotation.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/HistoOnEvent.java&quot;&gt;HistoOnEvent.java&lt;/a&gt; - demonstrates getting trace output based on client side event. After starting the script by BTrace client, press Ctrl-C to get menu to send event or exit. On sending event, histogram is printed. This way client can “pull” trace output whenever needed rather than BTrace agent pushing the trace output always or based on timer.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/JdbcQueries.java&quot;&gt;JdbcQueries.java&lt;/a&gt; - demonstrates BTrace aggregation facility. This facility is similar to &lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;http://dlc.sun.com/osol/docs/content/DTRCUG/gcggh.html&quot;&gt; DTrace aggregation&lt;/a&gt;&lt;/strong&gt; facility.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/JInfo.java&quot;&gt;JInfo.java&lt;/a&gt; - demonstrates &lt;code&gt;printVmArguments()&lt;/code&gt;, &lt;code&gt;printProperties()&lt;/code&gt; and &lt;code&gt;printEnv()&lt;/code&gt; built-in functions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/JMap.java&quot;&gt;JMap.java&lt;/a&gt; - demonstrates &lt;code&gt;dumpHeap()&lt;/code&gt; built-in function to dump (hprof binary format) heap dump of the target application.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/JStack.java&quot;&gt;JStack.java&lt;/a&gt; - demonstrates &lt;code&gt;jstackAll()&lt;/code&gt; built-in function to print stack traces of all the threads.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/LogTracer.java&quot;&gt;LogTracer.java&lt;/a&gt; - demonstrates trapping into an instance method (Logger.log) and printing private field value (of LogRecord object) by &lt;code&gt;field()&lt;/code&gt; and &lt;code&gt;objectValue()&lt;/code&gt; built-in functions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/MemAlerter.java&quot;&gt;MemAlerter.java&lt;/a&gt; - demonstrates tracing low memory event by &lt;code&gt;@OnLowMememory&lt;/code&gt; annotation.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/Memory.java&quot;&gt;Memory.java&lt;/a&gt; - prints memory stat once every 4 seconds by a timer probe. Demonstrates memory stat built-in functions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/MultiClass.java&quot;&gt;MultiClass.java&lt;/a&gt; - demonstrates inserting trace code into multiple methods of multiple classes using regular expressions for &lt;code&gt;clazz&lt;/code&gt; and &lt;code&gt;method&lt;/code&gt; fields of &lt;code&gt;@OnMethod&lt;/code&gt; annotation.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/NewComponent.java&quot;&gt;NewComponent.java&lt;/a&gt; - tracks every &lt;code&gt;java.awt.Component&lt;/code&gt; creation and increments a counter and prints the counter based on a timer.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/OnThrow.java&quot;&gt;OnThrow.java&lt;/a&gt; - prints exception stack trace every time any exception instance is created. In most scenarios, exceptions are thrown immediately after creation. So, it we get stack trace of throw points.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/ProbeExit.java&quot;&gt;ProbeExit.java&lt;/a&gt; - demonstrates &lt;code&gt;@OnExit&lt;/code&gt; probe and &lt;code&gt;exit(int)&lt;/code&gt; built-in function.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/Sizeof.java&quot;&gt;Sizeof.java&lt;/a&gt; - demonstates “sizeof” built-in function that can be used to get (approx.) size of a given Java object. It is possible to get size-wise histogram etc. using this built-in.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/SocketTracker.java&quot;&gt;SocketTracker.java&lt;/a&gt; - prints every server socker creation/bind and client socket accepts.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/SocketTracker1.java&quot;&gt;SocketTracker1.java&lt;/a&gt; - similar to SocketTracker.java sample, except that this sample uses &lt;code&gt;@OnProbe&lt;/code&gt; probes to avoid using Sun specific socket channel implementation classes in BTrace program. Instead &lt;code&gt;@OnProbe&lt;/code&gt; probes are mapped to &lt;code&gt;@OnMethod&lt;/code&gt; probes by BTrace agent.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/SysProp.java&quot;&gt;SysProp.java&lt;/a&gt; - demonstrates that it is okay to probe into System classes (like &lt;code&gt;java.lang.System&lt;/code&gt;) and call BTrace built-in functions in the action method.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/SubtypeTracer.java&quot;&gt;SubtypeTracer.java&lt;/a&gt; - demonstrates that it is possible to match all subtypes of a given supertype.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/ThreadCounter.java&quot;&gt;ThreadCounter.java&lt;/a&gt; - demonstrates use of jvmstat counters from BTrace programs.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/ThreadCounterBean.java&quot;&gt;ThreadCounterBean.java&lt;/a&gt; - demonstrates exposing the BTrace program as a JMX bean with one attribute (using &lt;code&gt;@Property&lt;/code&gt; annotation).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/ThreadBean.java&quot;&gt;ThreadBean.java&lt;/a&gt; - demonstrates the use of preprocessor of BTrace [and JMX integratio].&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/ThreadStart.java&quot;&gt;ThreadStart.java&lt;/a&gt; - demonstrates raising DTrace probes from BTrace programs. See also &lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/jthread.d&quot;&gt;jthread.d&lt;/a&gt; - the associated D-script. This sample raises a DTrace USDT probe whenever the traced program enters &lt;code&gt;java.lang.Thread.start()&lt;/code&gt; method. The BTrace program passes JavaThread’s name to DTrace.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/Timers.java&quot;&gt;Timers.java&lt;/a&gt; - demonstrates multiple timer probes (&lt;code&gt;@OnTimer&lt;/code&gt;) in a BTrace program.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/URLTracker.java&quot;&gt;URLTracker.java&lt;/a&gt; - prints URL every time &lt;code&gt;URL.openConnection&lt;/code&gt; returns successfully. This program uses &lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/jurls.d&quot;&gt;jurls.d&lt;/a&gt; D-script as well (to show histogram of URLs opened via DTrace).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/btraceio/btrace/tree/master/samples/WebServiceTracker.java&quot;&gt;WebServiceTracker.java&lt;/a&gt; - demonstates tracing classes and methods by specifying class and method level annotations rather than class and method names.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Javassist tutorial</title>
        <published>2019-12-01T12:13:38+05:30</published>
        <updated>2019-12-01T12:13:38+05:30</updated>
        
        <author>
          <name>Unknown</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://scp.net.cn/blog/javassist-tour/"/>
        <id>https://scp.net.cn/blog/javassist-tour/</id>
        
        <content type="html" xml:base="https://scp.net.cn/blog/javassist-tour/">&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/jboss-javassist/javassist&quot;&gt;GitHub - jboss-javassist/javassist: Java bytecode engineering toolkit&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://www.javassist.org/tutorial/tutorial.html&quot;&gt;tutorial&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://www.javassist.org/tutorial/tutorial2.html&quot;&gt;tutorial2&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://www.javassist.org/tutorial/tutorial3.html&quot;&gt;tutorial3&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://gitee.com/dllen/dllen-demos/tree/master/javassist-tour&quot;&gt;示例代码地址&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;java-bytecode&quot;&gt;Java Bytecode&lt;/h3&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://en.wikipedia.org/wiki/Java_bytecode_instruction_listings&quot;&gt;Java字节码指令列表&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;示例：&lt;code&gt;Point.java&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;package&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; com&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;ks&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;test&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;app&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;public class&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Point&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    private int&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    private int&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; String&lt;/span&gt;&lt;span&gt; name&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Point&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;int&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; int&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public int&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; getX&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public void&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; setX&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;int&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public int&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; getY&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public void&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; setY&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;int&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public void&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; move&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;int&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; int&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;){&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        this&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;编译java文件并查看字节码&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;mvn&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; clean compile&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;javap&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; -c target.classes.com.ks.test.app.Point&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Java 字节码&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;public class&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; com&lt;/span&gt;&lt;span&gt;.ks.test.app.Point &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  public&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; java&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;lang&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;String&lt;/span&gt;&lt;span&gt; name&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  public&lt;/span&gt;&lt;span&gt; com.ks.test.app.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Point&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Code&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;       0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span&gt; aload_0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;       1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span&gt; invokespecial #&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;                  // Method java/lang/Object.&amp;quot;&amp;lt;init&amp;gt;&amp;quot;:()V&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;       4&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span&gt; aload_0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;       5&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span&gt; iload_1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;       6&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span&gt; putfield      #&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;                  // Field x:I&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;       9&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span&gt; aload_0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;      10&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span&gt; iload_2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;      11&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span&gt; putfield      #&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;                  // Field y:I&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;      14&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;: return&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  public int&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; getX&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Code&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;       0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span&gt; aload_0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;       1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span&gt; getfield      #&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;                  // Field x:I&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;       4&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span&gt; ireturn&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  public void&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; setX&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Code&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;       0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span&gt; aload_0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;       1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span&gt; iload_1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;       2&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span&gt; putfield      #&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;                  // Field x:I&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;       5&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;: return&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  public int&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; getY&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Code&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;       0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span&gt; aload_0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;       1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span&gt; getfield      #&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;                  // Field y:I&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;       4&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span&gt; ireturn&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  public void&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; setY&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Code&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;       0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span&gt; aload_0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;       1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span&gt; iload_1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;       2&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span&gt; putfield      #&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;                  // Field y:I&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;       5&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;: return&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;  public void&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; move&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Code&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;       0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span&gt; aload_0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;       1&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span&gt; iload_1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;       2&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span&gt; putfield      #&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;                  // Field x:I&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;       5&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span&gt; aload_0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;       6&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span&gt; iload_2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;       7&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;:&lt;/span&gt;&lt;span&gt; putfield      #&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;                  // Field y:I&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;      10&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;: return&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;分析一下&lt;code&gt;move()&lt;/code&gt;方法的字节码&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;aload_0: 从局部变量0加载一个引用到堆栈上&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;iload_1: 从局部变量1加载 int 值&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;putfield：给对象赋值&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;return：方法返回&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Java代码都会编译成字节码，使用 &lt;em&gt;&lt;a rel=&quot;external&quot; href=&quot;http://jboss-javassist.github.io/javassist/&quot;&gt;Javasisst&lt;/a&gt;&lt;/em&gt; 可以非常容易的修改字节码；&lt;/p&gt;
&lt;h3 id=&quot;generating-a-java-class&quot;&gt;Generating a Java Class&lt;/h3&gt;
&lt;p&gt;生产一个Java类&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; java&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;lang&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;reflect&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Field&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; javassist&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;ClassPool&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; javassist&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;bytecode&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;AccessFlag&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; javassist&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;bytecode&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;ClassFile&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; javassist&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;bytecode&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;FieldInfo&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;public class&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Demo1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public static void&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; main&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[]&lt;/span&gt;&lt;span&gt; args&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; throws&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Exception&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // 生产一个Demo类，并添加一个id字段&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        ClassFile&lt;/span&gt;&lt;span&gt; cf&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; ClassFile&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;com.ks.test.app.Demo&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        cf&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;setInterfaces&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; String&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[]{&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;java.io.Serializable&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;})&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        FieldInfo&lt;/span&gt;&lt;span&gt; fieldInfo&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; FieldInfo&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;cf&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getConstPool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(), &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;I&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        fieldInfo&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;setAccessFlags&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;AccessFlag&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;PUBLIC&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        cf&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;addField&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;fieldInfo&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        ClassPool&lt;/span&gt;&lt;span&gt; classPool&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; ClassPool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getDefault&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        Field&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[]&lt;/span&gt;&lt;span&gt; fields&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; classPool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;makeClass&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;cf&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;toClass&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getFields&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        //&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        System&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;out&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;fields&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;].&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getName&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;())&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;loading-bytecode-instructions-of-class&quot;&gt;Loading Bytecode instructions of Class&lt;/h3&gt;
&lt;p&gt;获取Java Class 的字节码&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; javassist&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;ClassPool&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; javassist&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;bytecode&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;ClassFile&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; javassist&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;bytecode&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;CodeAttribute&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; javassist&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;bytecode&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;CodeIterator&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; javassist&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;bytecode&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;MethodInfo&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; javassist&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;bytecode&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Mnemonic&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;public class&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Demo2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public static void&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; main&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[]&lt;/span&gt;&lt;span&gt; args&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; throws&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Exception&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        ClassPool&lt;/span&gt;&lt;span&gt; classPool&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; ClassPool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getDefault&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        ClassFile&lt;/span&gt;&lt;span&gt; classFile&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; classPool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;com.ks.test.app.Point&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;).&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getClassFile&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        MethodInfo&lt;/span&gt;&lt;span&gt; methodInfo&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; classFile&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getMethod&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;move&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        CodeAttribute&lt;/span&gt;&lt;span&gt; codeAttribute&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; methodInfo&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getCodeAttribute&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        CodeIterator&lt;/span&gt;&lt;span&gt; codeIterator&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; codeAttribute&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iterator&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // 打印 move 方法的字节码&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        System&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;out&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;start print move byte code....&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        System&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;out&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        while&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;codeIterator&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;hasNext&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            int&lt;/span&gt;&lt;span&gt; index&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; codeIterator&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            int&lt;/span&gt;&lt;span&gt; op&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; codeIterator&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;byteAt&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;index&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            System&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;out&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;Mnemonic&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;OPCODE&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;op&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;])&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        System&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;out&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        System&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;out&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;end print move byte code....&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;adding-fields-to-existing-class-bytecode&quot;&gt;Adding Fields to Existing Class Bytecode&lt;/h3&gt;
&lt;p&gt;给已有Java Class 添加字段&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; java&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;lang&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;reflect&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Field&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; javassist&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;ClassPool&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; javassist&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;bytecode&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;AccessFlag&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; javassist&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;bytecode&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;ClassFile&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; javassist&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;bytecode&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;FieldInfo&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;public class&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Demo3&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public static void&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; main&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[]&lt;/span&gt;&lt;span&gt; args&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; throws&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Exception&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        ClassPool&lt;/span&gt;&lt;span&gt; classPool&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; ClassPool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getDefault&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        ClassFile&lt;/span&gt;&lt;span&gt; classFile&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; classPool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;com.ks.test.app.Point&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;).&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getClassFile&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // 给 Point 类添加一个id字段&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        FieldInfo&lt;/span&gt;&lt;span&gt; fieldInfo&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; FieldInfo&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;classFile&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getConstPool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(), &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;I&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        fieldInfo&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;setAccessFlags&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;AccessFlag&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;PUBLIC&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        classFile&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;addField&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;fieldInfo&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // only get public fields&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        Field&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[]&lt;/span&gt;&lt;span&gt; fields&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; classPool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;makeClass&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;classFile&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;toClass&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getFields&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        for&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Field&lt;/span&gt;&lt;span&gt; field&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; :&lt;/span&gt;&lt;span&gt; fields&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            System&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;out&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;field&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getName&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;())&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;adding-constructor-to-class-bytecode&quot;&gt;Adding Constructor to Class Bytecode&lt;/h3&gt;
&lt;p&gt;添加构造方法&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; javassist&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;ClassPool&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; javassist&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;bytecode&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Bytecode&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; javassist&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;bytecode&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;ClassFile&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; javassist&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;bytecode&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;CodeIterator&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; javassist&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;bytecode&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;MethodInfo&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; javassist&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;bytecode&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Mnemonic&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;public class&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Demo4&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public static void&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; main&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[]&lt;/span&gt;&lt;span&gt; args&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; throws&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Exception&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        ClassPool&lt;/span&gt;&lt;span&gt; classPool&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; ClassPool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getDefault&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        ClassFile&lt;/span&gt;&lt;span&gt; classFile&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; classPool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;com.ks.test.app.Point&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;).&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getClassFile&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        Bytecode&lt;/span&gt;&lt;span&gt; bytecode&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Bytecode&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;classFile&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getConstPool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;())&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        bytecode&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;addLload&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        bytecode&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;addInvokespecial&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;java/lang/Object&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span&gt; MethodInfo&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;nameInit&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;()V&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        bytecode&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;addReturn&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // addInvokespecial&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // 调用 java.lang.Object &amp;lt;init&amp;gt; 方法&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        MethodInfo&lt;/span&gt;&lt;span&gt; methodInfo&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; MethodInfo&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;classFile&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getConstPool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(),&lt;/span&gt;&lt;span&gt; MethodInfo&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;nameInit&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;()V&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        methodInfo&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;setCodeAttribute&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;bytecode&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;toCodeAttribute&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;())&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        classFile&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;addMethod&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;methodInfo&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        CodeIterator&lt;/span&gt;&lt;span&gt; codeIterator&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; bytecode&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;toCodeAttribute&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;iterator&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // 打印字节码&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        while&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;codeIterator&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;hasNext&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            int&lt;/span&gt;&lt;span&gt; index&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; codeIterator&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            int&lt;/span&gt;&lt;span&gt; op&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; codeIterator&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;byteAt&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;index&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            System&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;out&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;Mnemonic&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;OPCODE&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[&lt;/span&gt;&lt;span&gt;op&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;])&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;hot-load-java-class&quot;&gt;Hot load Java Class&lt;/h3&gt;
&lt;p&gt;运行时替换 Java Class，可以通过以下2种方式：&lt;/p&gt;
&lt;h4 id=&quot;redefineclassagent&quot;&gt;RedefineClassAgent&lt;/h4&gt;
&lt;p&gt;RedefineClassAgent 工具类，生成 jvm agent，并load agent，利用 &lt;code&gt;Instrumentation&lt;/code&gt; &lt;code&gt;redefineClasses&lt;/code&gt; 更新运行时类字节码信息；&lt;/p&gt;
&lt;p&gt;以下为关键代码：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;创建和加载Agent&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;  /**&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     * Lazy loads the agent that populates {@link #instrumentation}. OK to call multiple times.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     * &lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;@throws FailedToLoadAgentException&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; if agent either failed to load or if the agent wasn&amp;#39;t able to get an&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     *                                    instance of {@link Instrumentation} that allows class redefinitions.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    private static void&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; ensureAgentLoaded&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span&gt; throws FailedToLoadAgentException &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;instrumentation &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;!= null&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;            // already loaded&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            return;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // load the agent&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        try&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;            File&lt;/span&gt;&lt;span&gt; agentJar&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; createAgentJarFile&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;            // Loading an agent requires the PID of the JVM to load the agent to. Find out our PID.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;            String&lt;/span&gt;&lt;span&gt; nameOfRunningVM&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; ManagementFactory&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getRuntimeMXBean&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getName&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;            String&lt;/span&gt;&lt;span&gt; pid&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; nameOfRunningVM&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;substring&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; nameOfRunningVM&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;indexOf&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;))&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;            // load the agent&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;            VirtualMachine&lt;/span&gt;&lt;span&gt; vm&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; VirtualMachine&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;attach&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;pid&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            vm&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;loadAgent&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;agentJar&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getAbsolutePath&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(), &amp;quot;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            vm&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;detach&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; catch&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;Exception&lt;/span&gt;&lt;span&gt; e&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            throw new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; FailedToLoadAgentException&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // wait for the agent to load&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        for&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;int&lt;/span&gt;&lt;span&gt; sec&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; sec &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; AGENT_LOAD_WAIT_TIME_SEC&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;span&gt; sec&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;instrumentation &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;!= null&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;                // success!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;                return;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            try&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                LOGGER&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;info&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Sleeping for 1 second while waiting for agent to load.&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                Thread&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;sleep&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; catch&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;InterruptedException&lt;/span&gt;&lt;span&gt; e&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                Thread&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;currentThread&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;interrupt&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;                throw new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; FailedToLoadAgentException&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // agent didn&amp;#39;t load&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        throw new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; FailedToLoadAgentException&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    /**&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     * An agent must be specified as a .jar where the manifest has an Agent-Class attribute. Additionally, in order&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     * to be able to redefine classes, the Can-Redefine-Classes attribute must be true.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     * This method creates such an agent Jar as a temporary file. The Agent-Class is this class. If the returned Jar&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     * is loaded as an agent then {&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;@link&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; #&lt;/span&gt;&lt;span&gt;agentmain(String, Instrumentation)&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;} will be called by the JVM.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     * &lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;@return&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; a temporary {@link File} that points at Jar that packages this class.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     * &lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;@throws IOException&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; if agent Jar creation failed.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    private static&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; File&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; createAgentJarFile&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span&gt; throws IOException &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        File&lt;/span&gt;&lt;span&gt; jarFile&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; File&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;createTempFile&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;agent&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;.jar&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        jarFile&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;deleteOnExit&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // construct a manifest that allows class redefinition&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        Manifest&lt;/span&gt;&lt;span&gt; manifest&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Manifest&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        Attributes&lt;/span&gt;&lt;span&gt; mainAttributes&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; manifest&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getMainAttributes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        mainAttributes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;Attributes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;Name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;MANIFEST_VERSION&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;1.0&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        mainAttributes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;new&lt;/span&gt;&lt;span&gt; Attributes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Agent-Class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;),&lt;/span&gt;&lt;span&gt; RedefineClassAgent&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getName&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;())&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        mainAttributes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;new&lt;/span&gt;&lt;span&gt; Attributes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Can-Retransform-Classes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;), &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        mainAttributes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;new&lt;/span&gt;&lt;span&gt; Attributes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;Name&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Can-Redefine-Classes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;), &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        try&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;JarOutputStream&lt;/span&gt;&lt;span&gt; jos&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; JarOutputStream&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; FileOutputStream&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;jarFile&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;),&lt;/span&gt;&lt;span&gt; manifest&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;            // add the agent .class into the .jar&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;            JarEntry&lt;/span&gt;&lt;span&gt; agent&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; JarEntry&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;RedefineClassAgent&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getName&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;replace&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;, &amp;#39;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;.class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            jos&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;putNextEntry&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;agent&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;            // dump the class bytecode into the entry&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;            ClassPool&lt;/span&gt;&lt;span&gt; pool&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; ClassPool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getDefault&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;            CtClass&lt;/span&gt;&lt;span&gt; ctClass&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; pool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;RedefineClassAgent&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getName&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;())&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            jos&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;write&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ctClass&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;toBytecode&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;())&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            jos&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;closeEntry&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; catch&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;CannotCompileException&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; NotFoundException&lt;/span&gt;&lt;span&gt; e&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;            // Realistically this should never happen.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            LOGGER&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;Level&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;SEVERE&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;, &amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Exception while creating RedefineClassAgent jar.&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span&gt; e&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            throw new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; IOException&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        return&lt;/span&gt;&lt;span&gt; jarFile&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;运行时更新类字节码&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    /**&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     * Attempts to redefine class bytecode.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     * &amp;lt;p&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     * On first call this method will attempt to load an agent into the JVM to obtain an instance of&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     * {@link Instrumentation}. This agent load can introduce a pause (in practice 1 to 2 seconds).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     * &lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;@see&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; Instrumentation#redefineClasses(ClassDefinition...)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     *&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     * &lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;@param&lt;/span&gt;&lt;span&gt; definitions&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; classes to redefine.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     * &lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;@throws UnmodifiableClassException&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; as thrown by {&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;@link Instrumentation&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;#&lt;/span&gt;&lt;span&gt;redefineClasses(ClassDefinition...)&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     * &lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;@throws ClassNotFoundException&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; as thrown by {&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;@link Instrumentation&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;#&lt;/span&gt;&lt;span&gt;redefineClasses(ClassDefinition...)&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     * &lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;@throws FailedToLoadAgentException&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt; if agent either failed to load or if the agent wasn&amp;#39;t able to get an&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     *                                    instance of {@link Instrumentation} that allows class redefinitions.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;     */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public static void&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; redefineClasses&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;ClassDefinition&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;...&lt;/span&gt;&lt;span&gt; definitions&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span&gt; throws UnmodifiableClassException&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; ClassNotFoundException&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span&gt; FailedToLoadAgentException &lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;        ensureAgentLoaded&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        instrumentation&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;redefineClasses&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;definitions&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;测试代码&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; java&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;lang&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;instrument&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;ClassDefinition&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; javassist&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;ClassPool&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; javassist&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;CtClass&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; javassist&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;CtMethod&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;public class&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Demo5&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public static void&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; main&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[]&lt;/span&gt;&lt;span&gt; args&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; throws&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Exception&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        ClassPool&lt;/span&gt;&lt;span&gt; classPool&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; ClassPool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getDefault&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        CtClass&lt;/span&gt;&lt;span&gt; ctClass&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; classPool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;com.ks.test.app.Point&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ctClass&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;stopPruning&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // javaassist freezes methods if their bytecode is saved&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;        // defrost so we can still make changes.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;/span&gt;&lt;span&gt;ctClass&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;isFrozen&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            ctClass&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;defrost&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        CtMethod&lt;/span&gt;&lt;span&gt; ctMethod&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; ctClass&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getDeclaredMethod&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;move&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ctMethod&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;insertBefore&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;{ System.out.println(&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;Wheeeeee!&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;); }&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        byte&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[]&lt;/span&gt;&lt;span&gt; bytecode&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; ctClass&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;toBytecode&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        ClassDefinition&lt;/span&gt;&lt;span&gt; definition&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; ClassDefinition&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;Class&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;forName&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;com.ks.test.app.Point&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;),&lt;/span&gt;&lt;span&gt; bytecode&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        RedefineClassAgent&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;redefineClasses&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;definition&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        Point&lt;/span&gt;&lt;span&gt; point&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Point&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        point&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;move&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;hotswapper&quot;&gt;HotSwapper&lt;/h4&gt;
&lt;p&gt;使用 javassist HotSwapper 工具，该工具依赖 &lt;a rel=&quot;external&quot; href=&quot;https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/introclientissues005.html&quot;&gt;JDWP&lt;/a&gt;；&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;JDWP: Provides the implementation of the Java Debug Wire Protocol (JDWP) agent.&lt;/p&gt;
&lt;p&gt;使用方法：&lt;code&gt;java -Xdebug -Xrunjdwp:transport=dt_socket,address=8888,server=y,suspend=y Test&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;参考文档：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://www.baeldung.com/java-application-remote-debugging&quot;&gt;Java Application Remote Debugging | Baeldung&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://docs.oracle.com/en/java/javase/12/docs/specs/jpda/architecture.html&quot;&gt;JDWP Structure Overview&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://mahmoudanouti.wordpress.com/2019/07/07/remote-debugging-java-applications-with-jdwp/&quot;&gt;Remote Debugging Java Applications With JDWP | Learning Quest&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;测试代码：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; javassist&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;ClassPool&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; javassist&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;CtClass&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; javassist&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;CtMethod&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; javassist&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;util&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;HotSwapper&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;public class&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Demo6&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    //执行命令&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;    //java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=10240 Demo6&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    public static void&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; main&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[]&lt;/span&gt;&lt;span&gt; args&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; throws&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; Exception&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        HotSwapper&lt;/span&gt;&lt;span&gt; hs&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; = new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; HotSwapper&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt;10240&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Hello&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        ClassPool&lt;/span&gt;&lt;span&gt; classPool&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; ClassPool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getDefault&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        byte&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;[]&lt;/span&gt;&lt;span&gt; originBytes&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; classPool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;com.ks.test.app.Hello&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;).&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;toBytecode&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        System&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;out&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;** reload a v2 version&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        CtClass&lt;/span&gt;&lt;span&gt; ctClass&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; classPool&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;com.ks.test.app.Hello&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ctClass&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;stopPruning&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;/span&gt;&lt;span&gt;ctClass&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;isFrozen&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()){&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            ctClass&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;defrost&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;        CtMethod&lt;/span&gt;&lt;span&gt; ctMethod&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;/span&gt;&lt;span&gt; ctClass&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getDeclaredMethod&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ctMethod&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;insertBefore&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;{System.out.println(&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;** HelloWorld.print()&lt;/span&gt;&lt;span style=&quot;color: #EBCB8B;&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;);}&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        hs&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;reload&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;com.ks.test.app.Hello&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span&gt; ctClass&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;toBytecode&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;())&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Hello&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        System&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span&gt;out&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;** reload the original version&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        hs&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;reload&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;com.ks.test.app.Hello&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span&gt; originBytes&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        new&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; Hello&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;测试命令：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;mvn clean &lt;/span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;package&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;java &lt;/span&gt;&lt;span style=&quot;background-color: #BF616A;&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;cp &amp;quot;$&lt;/span&gt;&lt;span style=&quot;background-color: #EBCB8B;&quot;&gt;JAVA&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;background-color: #EBCB8B;&quot;&gt;HOME&lt;/span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;/lib&lt;/span&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;/*:target/javassit-tour-jar-with-dependencies.jar&amp;quot; -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=10240 com.ks.test.app.Demo6&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;注意：需要把 jdk 目录里 lib 下 jar 加载到 classpath&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;运行结果：&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Listening for transport dt_socket at address: 10240&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;hello world&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;** reload a v2 version&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;** HelloWorld.print()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;hello world&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;** reload the original version&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;hello world&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content>
        
    </entry>
</feed>
