<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Hai&apos;s blog</title><description>AI · 科研 · 折腾</description><link>https://blog.990915.xyz/</link><language>zh-Hans</language><item><title>在 WSL2 中获得完整桌面体验（X11 方案为主）</title><link>https://blog.990915.xyz/posts/wsl2-full-desktop-x11/</link><guid isPermaLink="true">https://blog.990915.xyz/posts/wsl2-full-desktop-x11/</guid><description>在 WSL2 的 WSLg 里搭出带 LightDM 登录界面、XFCE 窗口管理和 GPU 加速的完整桌面：用 Xwayland 顶替 Xorg、修 X0 软链、强制 GDK_BACKEND=x11 并开 d3d12，附 glmark2 实测、排错清单与 niri/Mesa 补丁。</description><pubDate>Fri, 30 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;环境：Windows 11 + WSL2 + WSLg 1.0.79，发行版为 Fedora 44，桌面为 XFCE，显示管理器为 LightDM。
目标：在 WSLg 里跑起一个「有登录界面、有窗口管理器、能用 GPU」的完整桌面，而不是只有一个孤零零的 X11 小程序。&lt;/p&gt;
&lt;p&gt;本文以 &lt;strong&gt;X11（Xwayland + LightDM + XFCE）&lt;/strong&gt; 为主线，把原理、配置、以及一路上踩过的坑都讲清楚；文章最后再附带聊聊 &lt;strong&gt;niri（Wayland）&lt;/strong&gt; 的玩法，以及我为此给 Mesa 打的一个补丁。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://img.990915.xyz/2026/10/30/1793350036813-bead7539-232e-4474-9cf5-94a685aee1df.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;0. TL;DR&lt;/h2&gt;
&lt;p&gt;如果你只想快速复现，核心就四件事：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;让 WSL 用 systemd 启动&lt;/strong&gt;，并装好桌面环境 + 显示管理器；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;用 &lt;code&gt;wslg-fix.service&lt;/code&gt; 修 &lt;code&gt;/tmp/.X11-unix&lt;/code&gt;&lt;/strong&gt;，把 &lt;code&gt;X0&lt;/code&gt; 软链到 &lt;code&gt;/mnt/wslg/.X11-unix/X0&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;把 &lt;code&gt;/usr/bin/Xorg&lt;/code&gt; 换成一个调用 &lt;code&gt;Xwayland&lt;/code&gt; 的包装脚本&lt;/strong&gt;，让 LightDM 以为自己在启动 Xorg，实际起的是 Xwayland；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;强制 GTK/Qt 走 X11 后端（&lt;code&gt;GDK_BACKEND=x11&lt;/code&gt;），并设 &lt;code&gt;GALLIUM_DRIVER=d3d12&lt;/code&gt;&lt;/strong&gt; 让 X11 也能吃到 GPU。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;剩下的都是排错。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://img.990915.xyz/2026/10/30/1793350183954-be4d0ba8-356d-4875-87a5-06d92231970b.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;1. 背景：WSLg 到底给了我们什么&lt;/h2&gt;
&lt;p&gt;WSLg 的本质是：在 Windows 上跑一个 &lt;strong&gt;Weston（Wayland 合成器）&lt;/strong&gt;，再通过 &lt;strong&gt;RDP RAIL/VAIL&lt;/strong&gt; 把每个窗口“远程”到 Windows 桌面里。它默认只提供：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一个 Wayland socket（&lt;code&gt;/mnt/wslg/runtime-dir/wayland-0&lt;/code&gt;）；&lt;/li&gt;
&lt;li&gt;一个 X11 socket（&lt;code&gt;/mnt/wslg/.X11-unix/X0&lt;/code&gt;，&lt;code&gt;DISPLAY=:0&lt;/code&gt;）；&lt;/li&gt;
&lt;li&gt;音频、剪贴板等集成。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;它&lt;strong&gt;不是&lt;/strong&gt;一个完整的桌面环境：没有登录管理器、没有窗口管理器（对 X11 而言）、没有一台“真的显卡设备”。&lt;/p&gt;
&lt;p&gt;我们的目标，是在这套基础上“骗”一个完整的会话出来：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Windows 桌面
   │  (RDP RAIL/VAIL，本地传输)
   ▼
WSLg: Weston (合成器)
   │  Wayland socket
   ▼
Xwayland (我们让 LightDM 启动的“Xorg”)
   │  X11
   ▼
LightDM → slick-greeter / XFCE(xfwm4, panel, apps)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;关键点：&lt;strong&gt;LightDM 原本要启动真正的 Xorg，但 WSL 没有真实的 DRM/VT，真 Xorg 起不来。&lt;/strong&gt; 于是我们用包装脚本把 &lt;code&gt;Xorg&lt;/code&gt; 换成 &lt;code&gt;Xwayland&lt;/code&gt;，让 X11 程序跑在一个嵌套的 Xwayland 里，再由 Weston 显示到 Windows。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;2. 前置条件&lt;/h2&gt;
&lt;h3&gt;2.1 打开 systemd&lt;/h3&gt;
&lt;p&gt;编辑 &lt;code&gt;/etc/wsl.conf&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[boot]
systemd=true

[interop]
appendWindowsPath=false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;改完在 Windows 侧执行 &lt;code&gt;wsl.exe --shutdown&lt;/code&gt;，重新打开终端。&lt;/p&gt;
&lt;h3&gt;2.2 安装桌面与显示管理器（Fedora 为例）&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;sudo dnf install -y \
  xfce4-session xfwm4 xfce4-panel xfdesktop thunar \
  lightdm slick-greeter \
  xorg-x11-server-Xwayland
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;说明：&lt;code&gt;lightdm-gtk-greeter&lt;/code&gt; 也能装，但它在 WSL 下更容易踩坑（见 §4.3）。这里我们直接用 &lt;code&gt;slick-greeter&lt;/code&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;3. 核心改造&lt;/h2&gt;
&lt;h3&gt;3.1 修复 &lt;code&gt;/tmp/.X11-unix&lt;/code&gt; 并准备 &lt;code&gt;X0&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;WSLg 默认把 &lt;code&gt;/tmp/.X11-unix&lt;/code&gt; 挂成只读，且里面没有 &lt;code&gt;X0&lt;/code&gt;。我们创建一个 oneshot 服务，把它换成可写目录，并把 &lt;code&gt;X0&lt;/code&gt; 软链到 WSLg 的共享目录：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo tee /etc/systemd/system/wslg-fix.service &amp;gt;/dev/null &amp;lt;&amp;lt;&apos;EOF&apos;
[Service]
Type=oneshot
ExecStart=-/usr/bin/umount /tmp/.X11-unix
ExecStart=/usr/bin/rm -rf /tmp/.X11-unix
ExecStart=/usr/bin/mkdir /tmp/.X11-unix
ExecStart=/usr/bin/chmod 1777 /tmp/.X11-unix
ExecStart=/usr/bin/ln -s /mnt/wslg/.X11-unix/X0 /tmp/.X11-unix/X0
ExecStart=/usr/bin/chmod 0777 /mnt/wslg/runtime-dir
ExecStart=/usr/bin/chmod 0666 /mnt/wslg/runtime-dir/wayland-0.lock

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl enable wslg-fix.service
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;坑&lt;/strong&gt;：在 WSLg 1.0.79 上，&lt;code&gt;umount /tmp/.X11-unix&lt;/code&gt; 有时会因“多层 tmpfs / Device or resource busy”失败，导致 &lt;code&gt;rm&lt;/code&gt; 失败、服务起不来，Fedora 44是有一个tmpfs配置文件存在冲突的。可以：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;重启 WSL（&lt;code&gt;wsl --shutdown&lt;/code&gt;）后再让它跑；&lt;/li&gt;
&lt;li&gt;或先手动 &lt;code&gt;sudo umount -R -l /tmp/.X11-unix&lt;/code&gt;，再 &lt;code&gt;sudo systemctl start wslg-fix.service&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;检查：&lt;code&gt;journalctl -u wslg-fix.service -b&lt;/code&gt; 和 &lt;code&gt;ls -l /tmp/.X11-unix/X0&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h3&gt;3.2 把 &lt;code&gt;/usr/bin/Xorg&lt;/code&gt; 换成 Xwayland 包装脚本&lt;/h3&gt;
&lt;p&gt;先备份真 Xorg，再写包装脚本：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo mv /usr/bin/Xorg /usr/bin/Xorg.original

sudo tee /usr/bin/Xorg.Xwayland &amp;gt;/dev/null &amp;lt;&amp;lt;&apos;EOF&apos;
#!/bin/bash
# 把 Xorg 的参数做一点适配，再转交给 Xwayland
for arg do
  shift
  case $arg in
    # Xwayland 不支持 vtxx，转成 ttyxx
    vt*) set -- &quot;$@&quot; &quot;${arg//vt/tty}&quot; ;;
    # Xwayland 不支持 -keeptty / -novtswitch，丢掉
    -keeptty) ;;
    -novtswitch) ;;
    *) set -- &quot;$@&quot; &quot;$arg&quot; ;;
  esac
done

# Xwayland 需要一个指向 WSLg Weston 的 XDG_RUNTIME_DIR
if [ ! -d &quot;$HOME/runtime-dir&quot; ]; then
  mkdir &quot;$HOME/runtime-dir&quot;
  ln -s /mnt/wslg/runtime-dir/wayland-0 \
        /mnt/wslg/runtime-dir/wayland-0.lock &quot;$HOME/runtime-dir/&quot;
fi
export XDG_RUNTIME_DIR=&quot;$HOME/runtime-dir&quot;

# 选一个空闲显示号（注意：Xwayland 实际取最后一个 :N，见下方说明）
for displayNumber in $(seq 1 100); do
  [ ! -e /tmp/.X11-unix/X$displayNumber ] &amp;amp;&amp;amp; break
done

# 窗口模式：去掉 -fullscreen，给固定分辨率
command=(&quot;/usr/bin/Xwayland&quot; &quot;:${displayNumber}&quot; &quot;-geometry&quot; &quot;1600x900&quot; &quot;$@&quot;)

systemd-cat -t /usr/bin/Xorg echo &quot;Starting Xwayland:&quot; &quot;${command[@]}&quot;
exec &quot;${command[@]}&quot;
EOF

sudo chmod 0755 /usr/bin/Xorg.Xwayland
sudo ln -sf Xorg.Xwayland /usr/bin/Xorg
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;📌 &lt;strong&gt;实测结论&lt;/strong&gt;：当命令行里出现多个 &lt;code&gt;:N&lt;/code&gt;（包装脚本加的 &lt;code&gt;:1&lt;/code&gt; 和 LightDM 传的 &lt;code&gt;:0&lt;/code&gt;）时，&lt;strong&gt;Xwayland 绑定的是最后一个 &lt;code&gt;:N&lt;/code&gt;&lt;/strong&gt;。所以包装脚本前面的“空闲显示号”其实会被 LightDM 传进来的 &lt;code&gt;:0&lt;/code&gt; 覆盖。&lt;/p&gt;
&lt;p&gt;真正让整套方案跑通的是 &lt;strong&gt;§3.1 的 &lt;code&gt;X0&lt;/code&gt; 软链&lt;/strong&gt;：Xwayland 启动 &lt;code&gt;:0&lt;/code&gt; 时会创建 &lt;code&gt;/tmp/.X11-unix/X0&lt;/code&gt;，因为它是软链，socket 实际落在了 &lt;code&gt;/mnt/wslg/.X11-unix/X0&lt;/code&gt;，从而被 WSLg 暴露给 Windows。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;3.3 强制 GTK/Qt 走 X11&lt;/h3&gt;
&lt;p&gt;这是整个方案里&lt;strong&gt;最容易踩、也最隐蔽的坑&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;WSLg 会为每个用户会话创建 &lt;code&gt;/run/user/&amp;lt;uid&amp;gt;/wayland-0&lt;/code&gt; 软链。即使你没有设置 &lt;code&gt;WAYLAND_DISPLAY&lt;/code&gt;，GTK 的 Wayland 后端在默认情况下也会去找 &lt;code&gt;wayland-0&lt;/code&gt;，一旦找到就直接用 &lt;strong&gt;Wayland 后端&lt;/strong&gt;。于是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;登录界面（&lt;code&gt;lightdm-gtk-greeter&lt;/code&gt; / &lt;code&gt;slick-greeter&lt;/code&gt;）是 X11-only 的程序 → 调 &lt;code&gt;gdk_x11_*&lt;/code&gt; 时断言失败 → &lt;strong&gt;SIGSEGV 闪退&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;XFCE 里的 GTK 程序也会跑到 Wayland 上，绕过 &lt;code&gt;xfwm4&lt;/code&gt;，窗口没有边框、不被管理。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;文章里常见的做法是改 &lt;code&gt;user-runtime-dir@.service&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo mkdir -p /etc/systemd/system/user-runtime-dir@.service.d
sudo tee /etc/systemd/system/user-runtime-dir@.service.d/override.conf &amp;gt;/dev/null &amp;lt;&amp;lt;&apos;EOF&apos;
[Service]
ExecStartPost=-/usr/bin/rm -f /run/user/%i/wayland-0 /run/user/%i/wayland-0.lock
EOF
sudo systemctl daemon-reload
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ 但在 WSLg 1.0.79 上，&lt;strong&gt;WSLg 会把 &lt;code&gt;wayland-0&lt;/code&gt; 软链重新造回来&lt;/strong&gt;，这条 &lt;code&gt;rm&lt;/code&gt; 挡不住。所以我们改用更稳的方式：&lt;strong&gt;直接强制后端&lt;/strong&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;给 greeter 强制 X11&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;sudo tee /usr/local/bin/slick-greeter-x11 &amp;gt;/dev/null &amp;lt;&amp;lt;&apos;EOF&apos;
#!/bin/bash
export GDK_BACKEND=x11
unset WAYLAND_DISPLAY
exec /usr/bin/slick-greeter &quot;$@&quot;
EOF
sudo chmod 0755 /usr/local/bin/slick-greeter-x11

sudo tee /usr/share/xgreeters/slick-greeter-x11.desktop &amp;gt;/dev/null &amp;lt;&amp;lt;&apos;EOF&apos;
[Desktop Entry]
Name=Slick Greeter (X11)
Comment=LightDM greeter forced to GDK X11 backend
Exec=slick-greeter-x11
Type=Application
EOF

sudo mkdir -p /etc/lightdm/lightdm.conf.d
sudo tee /etc/lightdm/lightdm.conf.d/50-greeter.conf &amp;gt;/dev/null &amp;lt;&amp;lt;&apos;EOF&apos;
[Seat:*]
greeter-session=slick-greeter-x11
EOF
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;给用户会话强制 X11 + 开 GPU&lt;/h4&gt;
&lt;p&gt;X 会话会读取 &lt;code&gt;/etc/X11/xinit/xinitrc.d/*&lt;/code&gt;，在这里注入环境最干净：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo tee /etc/X11/xinit/xinitrc.d/99-force-x11.sh &amp;gt;/dev/null &amp;lt;&amp;lt;&apos;EOF&apos;
# 强制 GTK/Qt 走 X11，绕过 WSLg 的 wayland-0
export GDK_BACKEND=x11
export QT_QPA_PLATFORM=xcb

# 让 Mesa 走 WSL 的 D3D12 后端（GPU: NVIDIA ...），而不是 llvmpipe
export GALLIUM_DRIVER=d3d12

# WSL 的 GPU 工具在 /usr/lib/wsl/lib
export PATH=&quot;$PATH:/usr/lib/wsl/lib&quot;
EOF
sudo chmod 0755 /etc/X11/xinit/xinitrc.d/99-force-x11.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;再给登录 shell 也补上（方便在终端里直接跑 GL 程序）：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo tee /etc/profile.d/99-wsl-gpu.sh &amp;gt;/dev/null &amp;lt;&amp;lt;&apos;EOF&apos;
case &quot;:$PATH:&quot; in
  *:/usr/lib/wsl/lib:*) ;;
  *) export PATH=&quot;$PATH:/usr/lib/wsl/lib&quot; ;;
esac
export GALLIUM_DRIVER=d3d12
EOF
sudo chmod 0644 /etc/profile.d/99-wsl-gpu.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3.4 让 LightDM 成为默认显示管理器&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl disable gdm 2&amp;gt;/dev/null
sudo systemctl enable lightdm
sudo systemctl set-default multi-user.target   # 或 graphical.target，见下
sudo systemctl start lightdm
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果你希望开机自动进图形，用 &lt;code&gt;graphical.target&lt;/code&gt;；如果想像文章那样“手动起”，就保持 &lt;code&gt;multi-user.target&lt;/code&gt;，需要时：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl start graphical.target
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;4. 验证与排错&lt;/h2&gt;
&lt;h3&gt;4.1 确认 Xwayland 在跑、分辨率正确&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;pgrep -a Xwayland
# 用 greeter/会话的 XAUTHORITY 查 :0
sudo xrandr --display :0   # 或在会话里 xrandr
# 期望看到 1600x900

# 包装脚本日志
journalctl -b -t /usr/bin/Xorg | tail
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4.2 确认 GPU 真的用上了&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;glxinfo -B | grep -E &quot;renderer|Accelerated&quot;
# 期望：D3D12 (NVIDIA GeForce RTX 4060) / Accelerated: yes

glmark2 -s 800x600 -b desktop
nvidia-smi
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我们实测的数据（RTX 4060）：&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;Score&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;X11&lt;/td&gt;
&lt;td&gt;800×600&lt;/td&gt;
&lt;td&gt;llvmpipe（默认）&lt;/td&gt;
&lt;td&gt;156&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;X11&lt;/td&gt;
&lt;td&gt;800×600&lt;/td&gt;
&lt;td&gt;d3d12&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;529&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;X11&lt;/td&gt;
&lt;td&gt;1920×1080&lt;/td&gt;
&lt;td&gt;d3d12&lt;/td&gt;
&lt;td&gt;153&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;原生 Wayland&lt;/td&gt;
&lt;td&gt;800×600&lt;/td&gt;
&lt;td&gt;d3d12&lt;/td&gt;
&lt;td&gt;540&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;原生 Wayland&lt;/td&gt;
&lt;td&gt;1920×1080&lt;/td&gt;
&lt;td&gt;d3d12&lt;/td&gt;
&lt;td&gt;171&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;📌 &lt;strong&gt;别用 &lt;code&gt;glxgears&lt;/code&gt; 判断 GPU&lt;/strong&gt;：它默认开 vsync（锁 60Hz），而且负载太轻，CPU 都能 800+ FPS。要比性能用 &lt;code&gt;glmark2&lt;/code&gt;，并且&lt;strong&gt;比较时一定用同一个 &lt;code&gt;-s&lt;/code&gt; 分辨率&lt;/strong&gt;——800×600 和 1080p 的像素量差 4 倍多，帧率会差 3～4 倍。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;4.3 坑：greeter 一启动就闪退&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;现象&lt;/strong&gt;：&lt;code&gt;/var/log/lightdm/lightdm.log&lt;/code&gt; 里反复出现&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Greeter closed communication channel
Seat seat0: Stopping; failed to start a greeter
Display manager stopped ... Exiting with return value 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;seat0-greeter.log&lt;/code&gt; 末尾：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Gdk-CRITICAL: gdk_x11_window_get_xid: assertion &apos;GDK_IS_X11_WINDOW (window)&apos; failed
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;dmesg：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;lightdm-gtk-gre[xxxx]: segfault at ... in libX11.so.6
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;根因&lt;/strong&gt;：不是 lightdm 崩，而是 &lt;strong&gt;greeter 崩&lt;/strong&gt;。而且根因是 &lt;strong&gt;GDK 选了 Wayland 后端&lt;/strong&gt;（见 §3.3）：greeter 是 X11-only 程序，拿到的 window/display 不是 X11 对象，随后把野指针传给 &lt;code&gt;XInternAtom&lt;/code&gt; → SIGSEGV。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决&lt;/strong&gt;：按 §3.3 用 &lt;code&gt;GDK_BACKEND=x11&lt;/code&gt; 包装 greeter。&lt;code&gt;lightdm-gtk-greeter&lt;/code&gt; 和 &lt;code&gt;slick-greeter&lt;/code&gt; 都会中招，任选其一 + 包装脚本即可。&lt;/p&gt;
&lt;h3&gt;4.4 坑：登录后窗口没有边框、没有最小化/最大化/关闭&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;根因&lt;/strong&gt;：XFCE 的窗口管理器 &lt;strong&gt;&lt;code&gt;xfwm4&lt;/code&gt; 没启动&lt;/strong&gt;。检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pgrep -a xfwm4        # 没有输出就是没起
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;~/.xsession-errors&lt;/code&gt; 开头会有：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Failed to fetch _NET_NUMBER_OF_DESKTOPS; assuming 1
Failed to get _NET_WORKAREA; using full screen dimensions
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这些 &lt;code&gt;_NET_*&lt;/code&gt; 都是窗口管理器设置的——没有它，自然没有标题栏。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;原因&lt;/strong&gt;：&lt;code&gt;~/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-session.xml&lt;/code&gt; 里 &lt;code&gt;SessionName=Default&lt;/code&gt;，但 &lt;code&gt;Failsafe&lt;/code&gt; 的 &lt;code&gt;Client*_Command&lt;/code&gt; 被写空，导致 &lt;code&gt;xfce4-session&lt;/code&gt; 没有拉起 &lt;code&gt;xfwm4&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决&lt;/strong&gt;（重置会话配置 + 兜底自启动）：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 备份并移走有问题的会话配置，改用系统默认 Failsafe（第一个客户端就是 xfwm4）
mv ~/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-session.xml \
   /tmp/xfce4-session.xml.orig

# 清空会话缓存
rm -rf ~/.cache/sessions/*

# 兜底：在 autostart 里显式启动 xfwm4
mkdir -p ~/.config/autostart
cat &amp;gt; ~/.config/autostart/xfwm4.desktop &amp;lt;&amp;lt;&apos;EOF&apos;
[Desktop Entry]
Type=Application
Name=Xfwm4
Comment=Xfce Window Manager
Exec=xfwm4 --replace
Terminal=false
NoDisplay=true
EOF
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注销重登后 &lt;code&gt;pgrep xfwm4&lt;/code&gt; 应该有输出，窗口也就有边框和按钮了。&lt;/p&gt;
&lt;h3&gt;4.5 坑：会话里 &lt;code&gt;nvidia-smi: command not found&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;WSL 的 GPU 工具在 &lt;code&gt;/usr/lib/wsl/lib/&lt;/code&gt;，但 &lt;strong&gt;LightDM 给会话的 PATH 很精简&lt;/strong&gt;（可能只有 &lt;code&gt;/usr/local/bin:/usr/bin&lt;/code&gt;），所以找不到。两条一起做：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 立刻可用
sudo ln -sf /usr/lib/wsl/lib/nvidia-smi /usr/local/bin/nvidia-smi

# 登录 shell 也补上 PATH（见 §3.3 的 /etc/profile.d/99-wsl-gpu.sh）
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4.6 坑：整个桌面是全屏，想窗口化&lt;/h3&gt;
&lt;p&gt;改包装脚本里的 &lt;code&gt;-geometry&lt;/code&gt; 和 &lt;code&gt;-fullscreen&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 原来： Xwayland ... &quot;-geometry&quot; &quot;1920x1080&quot; &quot;-fullscreen&quot; ...
# 改成： Xwayland ... &quot;-geometry&quot; &quot;1600x900&quot; ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后 &lt;code&gt;sudo systemctl restart lightdm&lt;/code&gt;。想改回全屏就把 &lt;code&gt;-fullscreen&lt;/code&gt; 加回去。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注意：这是&lt;strong&gt;嵌套式 Xwayland&lt;/strong&gt;，整个桌面是&lt;strong&gt;一个&lt;/strong&gt; X 窗口。缩放外层 Windows 窗口时，X 根分辨率不一定跟着变；要换分辨率就改 &lt;code&gt;-geometry&lt;/code&gt; 重启。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;4.7 坑：GDM/GNOME 方案在 Fedora 44 上是死路&lt;/h3&gt;
&lt;p&gt;之前参考的网上一篇文章（“在 wsl2 中使用 wslg 实现完整桌面环境”）是用 &lt;strong&gt;GDM + GNOME（Ubuntu 24.04）&lt;/strong&gt; 演示的。它能把 &lt;code&gt;/usr/bin/Xorg&lt;/code&gt; 换成 Xwayland，是因为 &lt;strong&gt;GDM 当时会用 Xorg 起 greeter&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;但在 &lt;strong&gt;Fedora 44 / GNOME 50&lt;/strong&gt; 上：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;gnome-shell --help&lt;/code&gt; 里&lt;strong&gt;已经没有 &lt;code&gt;--x11&lt;/code&gt;&lt;/strong&gt;，GNOME 50 是 Wayland-only；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/usr/share/xsessions/&lt;/code&gt; 里不再有 GNOME 的 X11 会话；&lt;/li&gt;
&lt;li&gt;GDM 的 greeter 就是 &lt;code&gt;gnome-shell --mode=gdm&lt;/code&gt;，只能跑 Wayland；&lt;/li&gt;
&lt;li&gt;而 Wayland greeter 需要 DRM/KMS，WSL 的 &lt;code&gt;/dev/dri&lt;/code&gt; 是假的 vgem（&lt;code&gt;/devices/faux/vgem/...&lt;/code&gt;）→ 直接失败：&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;Running GNOME Shell ... as a Wayland display server
MESA-EGL: warning: egl: failed to create dri2 screen
MESA-EGL: warning: NEEDS EXTENSION: falling back to kms_swrast
org.gnome.Shell@gdm.service: Failed with result &apos;protocol&apos;
GdmDisplay: Session never registered
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;WaylandEnable=false&lt;/code&gt; 也救不了（因为 greeter 本身没有 X11 模式了）。&lt;strong&gt;所以 Fedora 44 上请走 LightDM + X11 桌面（XFCE 等）。&lt;/strong&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;5. 原理补充：为什么 WSL 下 X11/Wayland 都“没有真 GPU”&lt;/h2&gt;
&lt;p&gt;这是理解后面所有现象的关键。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;WSL 里的 &lt;code&gt;/dev/dri/card0&lt;/code&gt; / &lt;code&gt;renderD128&lt;/code&gt; 来自 &lt;strong&gt;&lt;code&gt;faux vgem&lt;/code&gt;&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cat /sys/class/drm/card0/device/uevent
# DRIVER=faux_driver
udevadm info -q property /sys/class/drm/renderD128 | grep DEVPATH
# DEVPATH=/devices/faux/vgem/drm/renderD128
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它们不是真正的 GPU 设备，所以依赖 DRM/KMS/GBM 的东西（真 Xorg、GNOME Wayland greeter、glamor、dmabuf）都会失败或回退。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;真正的 GPU 通过 &lt;strong&gt;&lt;code&gt;/dev/dxg&lt;/code&gt;（dxgkrnl）&lt;/strong&gt; 暴露，Mesa 用 &lt;strong&gt;&lt;code&gt;d3d12&lt;/code&gt; gallium 驱动&lt;/strong&gt;访问它（配合 &lt;code&gt;/usr/lib/wsl/lib&lt;/code&gt; 里的 &lt;code&gt;libd3d12core.so&lt;/code&gt; / &lt;code&gt;libdxcore.so&lt;/code&gt;）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&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;真 DRM render node&lt;/td&gt;
&lt;td&gt;❌（faux vgem）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;EGL_EXT_device_drm&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dmabuf 零拷贝&lt;/td&gt;
&lt;td&gt;❌（Wayland 走 &lt;code&gt;wl_shm&lt;/code&gt;；Xwayland glamor 退软件）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;d3d12（GPU 渲染）&lt;/td&gt;
&lt;td&gt;✅ 需 &lt;code&gt;GALLIUM_DRIVER=d3d12&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CUDA（&lt;code&gt;nvidia-smi&lt;/code&gt;）&lt;/td&gt;
&lt;td&gt;✅ 通过 &lt;code&gt;/dev/dxg&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;所以你会看到这类“警告”，它们都是&lt;strong&gt;能力降级&lt;/strong&gt;，不是错误：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Xwayland glamor: GBM Wayland interfaces not available
Failed to initialize glamor, falling back to sw
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以及 Wayland 侧 niri 的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;failed building default dmabuf feedback, falling back to v3:
  error getting EGL device render node
EGL_EXT_device_drm ... at least one is required
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;影响：普通 2D 桌面无感；3D/高帧率会有“显存→内存”的额外拷贝开销；依赖 DRM 枚举/零拷贝的功能（多 GPU 选择、DRM leasing、部分录屏）受限。这些都&lt;strong&gt;不是配置错误&lt;/strong&gt;，换到有真 &lt;code&gt;/dev/dri/renderD128&lt;/code&gt; 的裸机/虚拟机就消失了。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;6. 附带：niri 方案（Wayland）&lt;/h2&gt;
&lt;p&gt;如果你想要更现代、更流畅的平铺式体验，也可以直接在 WSLg 里跑 &lt;strong&gt;niri&lt;/strong&gt;（一个用 Rust 写的滚动平铺 Wayland 合成器）。&lt;/p&gt;
&lt;h3&gt;6.1 基本玩法&lt;/h3&gt;
&lt;p&gt;niri 以 &lt;strong&gt;winit 嵌套后端&lt;/strong&gt; 运行在 WSLg 的 Weston 里：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 你的 shell 里需要有指向 WSLg Weston 的 Wayland 环境
# （WSLg 登录会话通常已经设好 WAYLAND_DISPLAY=wayland-0 / XDG_RUNTIME_DIR=/run/user/1000）
niri --session
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;niri 自己会监听 &lt;code&gt;wayland-1&lt;/code&gt;（给它启动的客户端）和 X11 socket（通过 &lt;code&gt;xwayland-satellite&lt;/code&gt;）。它的外层窗口由 winit 创建，因为 WSLg 不提供服务端装饰（没有 &lt;code&gt;zxdg_decoration_manager_v1&lt;/code&gt;），所以窗口边框是 &lt;strong&gt;CSD（客户端自绘）&lt;/strong&gt;——这也是为什么 niri 的窗口看起来有边框，而 sway 没有。&lt;/p&gt;
&lt;h3&gt;6.2 坑：点“最大化”时 niri 闪退&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;现象&lt;/strong&gt;：niri 外层窗口点标题栏最大化，niri 偶尔/经常 SIGSEGV：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;niri[xxxx]: segfault at 40 ... in libEGL_mesa.so.0.0.0[...]
niri.service: Main process exited, code=killed, status=11/SEGV
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;根因&lt;/strong&gt;：WSLg 没有 dmabuf，Mesa 只能走 &lt;strong&gt;Wayland 软件呈现路径&lt;/strong&gt;。resize 的瞬间，&lt;code&gt;dri2_surf-&amp;gt;back&lt;/code&gt; 还没就绪，而 Mesa 里只有一句被 release 构建编译掉的 &lt;code&gt;assert&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;static void *
dri2_wl_swrast_get_backbuffer_data(struct dri2_egl_surface *dri2_surf)
{
   assert(dri2_surf-&amp;gt;back);        // release 下无效
   return dri2_surf-&amp;gt;back-&amp;gt;data;   // back == NULL → [NULL+0x40] → SIGSEGV
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;（&lt;code&gt;libEGL_mesa&lt;/code&gt; 里 &lt;code&gt;dri2_wl_swrast_put_image2&lt;/code&gt; 调它，对应 &lt;code&gt;platform_wayland.c&lt;/code&gt; 的 &lt;code&gt;dst += y * dst_stride;&lt;/code&gt;。）&lt;/p&gt;
&lt;p&gt;我们查了 Mesa 26.2.6 和 main，&lt;strong&gt;上游都还没修&lt;/strong&gt;。于是我给它打了个补丁并重编 &lt;code&gt;libEGL_mesa&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/* 1) 判空而不是 assert */
static void *
dri2_wl_swrast_get_backbuffer_data(struct dri2_egl_surface *dri2_surf)
{
   if (!dri2_surf-&amp;gt;back)
      return NULL;
   return dri2_surf-&amp;gt;back-&amp;gt;data;
}

/* 2) put_image2 里 back 没就绪就跳过这一帧 */
dst = dri2_wl_swrast_get_backbuffer_data(dri2_surf);
if (!dst)
   return;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;效果：resize 时极端情况下&lt;strong&gt;丢一帧&lt;/strong&gt;而不是崩溃（可能表现为轻微闪烁），最大化就稳定了。&lt;/p&gt;
&lt;h3&gt;6.3 编译与替换（简述）&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# 1. 装构建依赖（Fedora：用 mesa 的 spec 最省事）
sudo dnf builddep -y ./mesa.spec

# 2. 打补丁后，用 meson 只编 libEGL_mesa
meson setup build -Dprefix=/usr -Dbuildtype=release \
  -Dplatforms=x11,wayland -Dgallium-drivers=softpipe \
  -Dvulkan-drivers= -Dvulkan-layers= \
  -Dgallium-rusticl=false -Dmicrosoft-clc=disabled \
  -Dglx=dri -Degl=enabled -Dgles1=enabled -Dgles2=enabled -Dopengl=true \
  -Dgbm=enabled -Dglvnd=enabled -Dllvm=disabled \
  -Dbuild-tests=false -Dtools= -Dvideo-codecs=
ninja -C build src/egl/libEGL_mesa.so.0.0.0

# 3. 去掉 build 目录 RPATH（让它用系统的 libgallium），备份后替换
patchelf --remove-rpath build/src/egl/libEGL_mesa.so.0.0.0
sudo cp -a /lib64/libEGL_mesa.so.0.0.0 /lib64/libEGL_mesa.so.0.0.0.orig
sudo cp build/src/egl/libEGL_mesa.so.0.0.0 /lib64/libEGL_mesa.so.0.0.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;验证：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;objdump -d /lib64/libEGL_mesa.so.0.0.0 | grep -A3 &apos;450&apos;   # 应能看到 test %rax,%rax; je
glxinfo -B | grep -E &quot;renderer|Accelerated&quot;                # D3D12 / yes
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ 以后 &lt;code&gt;dnf update mesa-*&lt;/code&gt; 会覆盖这个补丁，需要重新打。回滚：
&lt;code&gt;sudo cp -a /lib64/libEGL_mesa.so.0.0.0.orig /lib64/libEGL_mesa.so.0.0.0&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;6.4 niri 的日志里那些 warning 要不要管？&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;MESA-EGL: failed to get driver name for fd -1
MESA-LOADER: failed to retrieve device information
failed building default dmabuf feedback ... error getting EGL device render node
EGL_EXT_device_drm ... at least one is required
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;不用管，也不影响其他软件&lt;/strong&gt;。它们只是说明「WSL 没有真 DRM、没有 &lt;code&gt;EGL_EXT_device_drm&lt;/code&gt;、dmabuf 零拷贝不可用，自动回退到 shm」。GPU 渲染（d3d12）、CUDA 都正常。真的受影响的是多 GPU 选择、DRM leasing、VR、部分录屏工具这些边缘功能。&lt;/p&gt;
&lt;p&gt;另外两条：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;error inhibiting power key: AccessDenied
XDG_SESSION_ID is unset or invalid; logind LockedHint won&apos;t be set
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;是 logind 集成的小问题（电源键抑制、锁屏状态），与图形无关。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;7. X11 vs niri 对比与选择&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;维度&lt;/th&gt;
&lt;th&gt;X11（Xwayland + LightDM + XFCE）&lt;/th&gt;
&lt;th&gt;niri（Wayland）&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;登录界面&lt;/td&gt;
&lt;td&gt;✅ LightDM + slick-greeter&lt;/td&gt;
&lt;td&gt;一般直接 &lt;code&gt;niri --session&lt;/code&gt;，无独立登录界面&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;窗口管理&lt;/td&gt;
&lt;td&gt;xfwm4（标题栏/最小化/最大化）&lt;/td&gt;
&lt;td&gt;niri 平铺/滚动，自绘边框&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;外层窗口装饰&lt;/td&gt;
&lt;td&gt;无（WSLg 不画；内部窗口有 xfwm4 装饰）&lt;/td&gt;
&lt;td&gt;winit CSD，有边框&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPU&lt;/td&gt;
&lt;td&gt;✅ &lt;code&gt;GALLIUM_DRIVER=d3d12&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;✅ 默认/可设&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dmabuf 零拷贝&lt;/td&gt;
&lt;td&gt;❌ → shm&lt;/td&gt;
&lt;td&gt;❌ → shm&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;稳定性&lt;/td&gt;
&lt;td&gt;成熟，踩坑主要在 greeter 后端&lt;/td&gt;
&lt;td&gt;需注意 resize 的 Mesa NULL bug（已给补丁）&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;hr /&gt;
&lt;h2&gt;8. 一页排查清单&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;systemctl is-active lightdm&lt;/code&gt;、&lt;code&gt;pgrep -a Xwayland&lt;/code&gt;、&lt;code&gt;pgrep -a slick-greeter&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;看 &lt;code&gt;/var/log/lightdm/lightdm.log&lt;/code&gt; 是 greeter 崩还是 X 起不来。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;journalctl -u wslg-fix.service -b&lt;/code&gt;、&lt;code&gt;ls -l /tmp/.X11-unix/X0&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;journalctl -b -t /usr/bin/Xorg&lt;/code&gt; 看包装脚本实际参数。&lt;/li&gt;
&lt;li&gt;greeter 崩 → 十有八九是 GDK 走了 Wayland，确认 &lt;code&gt;GDK_BACKEND=x11&lt;/code&gt; 包装脚本生效。&lt;/li&gt;
&lt;li&gt;没边框 → &lt;code&gt;pgrep xfwm4&lt;/code&gt;，检查 &lt;code&gt;~/.xsession-errors&lt;/code&gt; 的 &lt;code&gt;_NET_*&lt;/code&gt; 报错。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nvidia-smi&lt;/code&gt; 找不到 → PATH 没 &lt;code&gt;/usr/lib/wsl/lib&lt;/code&gt;，软链到 &lt;code&gt;/usr/local/bin&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;帧率低 → &lt;code&gt;glxinfo -B&lt;/code&gt; 看是不是 &lt;code&gt;llvmpipe&lt;/code&gt;；设 &lt;code&gt;GALLIUM_DRIVER=d3d12&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;比较性能 → 用 &lt;code&gt;glmark2&lt;/code&gt;，固定 &lt;code&gt;-s&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;GDM/GNOME 在 Fedora 44 起不来 → 正常，换 LightDM + X11 桌面。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;9. 参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;WSLg 官方仓库与 README（RAIL/VAIL、vGPU 经系统内存的限制）：&lt;a href=&quot;https://github.com/microsoft/wslg&quot;&gt;https://github.com/microsoft/wslg&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;社区文章《在 wsl2 中使用 wslg 实现完整桌面环境》（GDM/GNOME 版思路来源）&lt;/li&gt;
&lt;li&gt;Mesa &lt;code&gt;src/egl/drivers/dri2/platform_wayland.c&lt;/code&gt;（&lt;code&gt;dri2_wl_swrast_put_image2&lt;/code&gt; / &lt;code&gt;dri2_wl_swrast_get_backbuffer_data&lt;/code&gt;）&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;免责声明：本文基于 WSLg 1.0.79 + Fedora 44 实测，不同 WSL/发行版/桌面版本细节可能不同；升级 Mesa 会覆盖第 6 节的补丁。&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded><category>折腾</category><category>WSL2</category><category>WSLg</category><category>Linux</category><category>X11</category><category>XFCE</category><category>Mesa</category></item><item><title>一个网关，让 Claude Code 用上 DeepSeek、Codex 用上 Kimi：magpie 上手</title><link>https://blog.990915.xyz/posts/magpie-intro/</link><guid isPermaLink="true">https://blog.990915.xyz/posts/magpie-intro/</guid><description>magpie 在你电脑上跑一个网关，在 OpenAI 与 Anthropic 两种协议之间双向翻译，让 Claude Code 用上 DeepSeek、Codex 用上 Kimi。本文说清它怎么工作、五步上手、用量怎么算，以及更新节奏和数据风险。</description><pubDate>Wed, 28 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;大家好，这里是王先生的播客。先来看个数字：magpie 的 GitHub 仓库 9 月 23 日才建，截至 10 月 27 日下午已经有两万三千多个 star，版本号跑到了 v0.1.1711。&lt;/p&gt;
&lt;p&gt;这篇就简单说说，它是干啥的、好在哪、怎么用。&lt;/p&gt;
&lt;p&gt;如果你手上同时开着 Claude Code、Codex 好几个编码 Agent，又想让它们用上 DeepSeek、Kimi、GLM、Qwen 这些模型，大概率被各家的配置文件折腾过。magpie 就是冲着这个来的。&lt;/p&gt;
&lt;p&gt;王先生自己的电脑上就装着，用下来的感觉是这样的：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;非常不错，ui很漂亮，特别是路由动画，一个喜鹊很有趣。功能也特别丰富，支持很多agent，模型提供商也支持的特别多。我电脑基本使用的所有agent都使用这个magpie代理了。包括pi,claude code/desktop,codex,deepseek harness。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://img.990915.xyz/2026/10/28/1793165692709-29070a63-ee13-4985-adc6-c730ce08729c.png&quot; alt=&quot;图 1　王先生的 magpie Windows 桌面版 Agent 页&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;它是干啥的：本机一个网关，替 Agent 翻译协议&lt;/h2&gt;
&lt;p&gt;麻烦出在协议上。按官网的说法，Codex 只讲 OpenAI 的 Responses 协议，Claude Code 只讲 Anthropic 的 Messages 协议，各家模型厂商又各有各的接口。&lt;/p&gt;
&lt;p&gt;magpie 在你电脑上跑一个网关，地址是 &lt;code&gt;127.0.0.1:3425&lt;/code&gt;，在 OpenAI 和 Anthropic 两种协议之间双向翻译。你在界面里给某个 Agent 点选一个模型，它只改写这个 Agent 配置里被改动的那一个键；选回原生模型，就还原回去。&lt;/p&gt;
&lt;p&gt;官方给自己的定位也很直白：同时用不止一个 Agent、不止一家模型的人。&lt;/p&gt;
&lt;p&gt;至于翻译之后各模型在各 Agent 里表现如何，这篇没有做对比测试，换了模型效果会不会一样，得你自己跑跑看。&lt;/p&gt;
&lt;h2&gt;有啥优点&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;一个界面管多个 Agent&lt;/strong&gt;：上面那张图就是王先生的 Windows 桌面版，Claude Code、Claude Desktop、Codex、Pi、DeepSeek Harness 都接进来了，每个各选了自己的模型。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;预设厂商多&lt;/strong&gt;：内置预设里有 DeepSeek、Kimi、智谱 GLM、Qwen、MiniMax、火山方舟、百度千帆、腾讯云等，国内常见的几家都有现成预设。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;平台全&lt;/strong&gt;：macOS、Windows、Linux 都有安装包，也能用 Docker 跑；README 里列的支持 Agent 有 60 多个，各家接入的成熟度不太一样。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;软件免费、MIT 开源&lt;/strong&gt;：magpie 本身不收钱，模型费用按你自己在各厂商的 key 付。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;用量和费用一眼看到&lt;/strong&gt;：内置用量页，能看调用次数、token、缓存命中，还会按价格表估算花了多少钱。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;怎么用：从安装到给 Agent 换上模型&lt;/h2&gt;
&lt;p&gt;先说清楚来源：下面第 1～3 步，团队在一台 Linux 测试机上用终端版跑过（安装脚本是先读过源码、再按同样流程手动下载校验的），截图来自那台测试机；第 4、5 步需要真实 key，按官方文档写，界面用王先生的 Windows 截图对照。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第 1 步：安装&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;官方一行命令：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl -fsSL https://usemagpie.ai/install.sh | sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个脚本会先查最新版本的下载地址和 SHA-256 校验值，下载、校验后装到 &lt;code&gt;~/.local/bin/magpie&lt;/code&gt;。Linux 上检测到 WebKitGTK 4.1 就装桌面版，否则装终端版。macOS 和 Windows 也可以直接下载 dmg、exe 安装包；国内网络不顺可以加 &lt;code&gt;--proxy&lt;/code&gt; 或 &lt;code&gt;--mirror&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;装完看一下版本：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;magpie --version
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;第 2 步：启动网关（桌面版应用打开就启动）&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;magpie serve
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;正常会看到 &lt;code&gt;magpie gateway on http://127.0.0.1:3425&lt;/code&gt;，同时列出 OpenAI 的 &lt;code&gt;/v1/chat/completions&lt;/code&gt;、&lt;code&gt;/v1/responses&lt;/code&gt; 和 Anthropic 的 &lt;code&gt;/v1/messages&lt;/code&gt; 几个端点。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://img.990915.xyz/2026/10/28/1793165727775-0c167027-3902-4a90-93ed-897640bbb77b.png&quot; alt=&quot;图 2　Linux 终端版实测（团队测试机运行）&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第 3 步：看看有哪些厂商预设&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;magpie presets
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://img.990915.xyz/2026/10/28/1793165760621-965a0100-e732-47ce-9dfb-3137e0ea2180.png&quot; alt=&quot;图 3　Linux 终端版实测（团队测试机运行），顶部为赞助位&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第 4 步：添加厂商 key&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;命令行一条就够（&lt;code&gt;sk-…&lt;/code&gt; 换成你自己的 key）：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;magpie provider add deepseek sk-…
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;桌面版在供应商页面里添加，粘贴 key 就行。本地跑 Ollama 的话，&lt;code&gt;magpie provider add ollama&lt;/code&gt; 不需要 key。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://img.990915.xyz/2026/10/28/1793165778692-8523cdd3-b297-4c13-8eef-9610be2483c4.png&quot; alt=&quot;图 4　王先生的供应商配置页（以 Command Code 为例，密钥已打码）&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第 5 步：给 Agent 指定模型&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;magpie claude deepseek/deepseek-v4-pro
magpie codex moonshot/kimi-k2.5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;想还原就用 &lt;code&gt;magpie &amp;lt;agent&amp;gt; default&lt;/code&gt;。改完之后新开的会话才生效。桌面版就是在 Agent 页里点选，效果见开头那张图。&lt;/p&gt;
&lt;p&gt;其他支持自定义 base URL 的客户端，也可以直接指向网关，key 随便填（网关只监听本机）：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export ANTHROPIC_BASE_URL=http://127.0.0.1:3425 ANTHROPIC_API_KEY=magpie
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;看路由和用量&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;接好之后，托盘面板的「路由」页能看到今天的调用情况。截图那一刻，王先生这边是今日 720 次调用、3.6M token。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://img.990915.xyz/2026/10/28/1793165803587-c22b7520-6147-4fce-9c3c-50d7571a0431.png&quot; alt=&quot;图 5　托盘面板「路由」页，数据为截图当时&quot; /&gt;&lt;/p&gt;
&lt;p&gt;在「模型 › 路由」页还能看最近一个请求是怎么路由的：为什么走这个模型，上下文窗口里各部分各占多少 token。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://img.990915.xyz/2026/10/28/1793165812954-bba2697e-b739-4f01-9b3a-0a15dba21344.png&quot; alt=&quot;图 6a　路由详情&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://img.990915.xyz/2026/10/28/1793165834376-a8a0cfc5-3a02-46aa-8962-ddebb3d23bb8.png&quot; alt=&quot;图 6b　路由说明特写&quot; /&gt;&lt;/p&gt;
&lt;p&gt;提到的这个喜鹊路由动画，官网首页的路由一节有演示，其中「按意图」模式是这样分流的：每轮对话开始时先问一个小而快的分类模型，这条消息属于哪条规则，再交给对应的模型（我平时没用这个，意图这个判断感觉不靠谱）。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://img.990915.xyz/2026/10/28/1793165867014-c1649c9d-726a-4808-8da5-cdd893af41ad.png&quot; alt=&quot;图 7　路由示意（据官网按意图路由演示绘制）&quot; /&gt;&lt;/p&gt;
&lt;p&gt;用量页按模型拆分 token 和请求数，还能导出 CSV。王先生截图那天的估算是约 $9.03，这个数是 magpie 按价格表估出来的，实际以厂商账单为准。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://img.990915.xyz/2026/10/28/1793165880770-36ae0293-21ce-443f-8e9d-2c61e0ad8afb.png&quot; alt=&quot;图 8　用量页，金额为 magpie 按价格表估算&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;装之前要注意什么&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;项目很新，更新极快&lt;/strong&gt;：仓库建了一个多月，版本号一天能跳上百个。默认是每个版本都推，怕折腾的话，用 &lt;code&gt;magpie update channel stable&lt;/code&gt; 切到 stable 通道，大约每周一版。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;网关只听本机，请求照样发给厂商&lt;/strong&gt;：你的 prompt 和代码仍然会发到你选的那家模型厂商，用哪家就要接受哪家的数据政策。key 存在 magpie 里，Agent 拿不到。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;脱敏默认关闭，可以手动开启。&lt;/strong&gt; 可以将你个人信息在发送时加密，AI回复时如果出现就解密。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;预设列表顶上那几家是赞助位&lt;/strong&gt;：列表最前面一段标着 partners (sponsors)，这篇不作推荐，按自己需要选厂商。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;背后是个人开发者&lt;/strong&gt;：主要作者是 GitHub 上的 yetone。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;谁该试、谁先不用管&lt;/h2&gt;
&lt;p&gt;简单说：同时用好几个编码 Agent、又想在多家模型之间换着用的人，可以去试试；只用一个 Agent、只用它原生模型的，先不用管。王先生的建议是装的时候顺手切到 stable 通道，省得天天被更新打扰。&lt;/p&gt;
&lt;p&gt;你现在给 Claude Code、Codex 换模型用的是什么方案？评论区聊聊，王先生也想抄抄作业。&lt;/p&gt;
&lt;p&gt;项目地址再贴一次：https://github.com/yetone/magpie&lt;/p&gt;
&lt;p&gt;今天就简单说到这儿，王先生下篇见。&lt;/p&gt;
&lt;h2&gt;参考资料&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;magpie 官网：https://usemagpie.ai&lt;/li&gt;
&lt;li&gt;magpie GitHub 仓库与 Quick start：https://github.com/yetone/magpie#quick-start&lt;/li&gt;
&lt;li&gt;文中 star 数、版本号来自 GitHub API，查询于 2026-10-27 16:41（北京时间）&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><category>AI</category><category>magpie</category><category>AI Agent</category><category>模型路由</category><category>开源</category></item><item><title>ego(lite)：一个能和 AI Agent 共用的浏览器</title><link>https://blog.990915.xyz/posts/ego-lite-intro/</link><guid isPermaLink="true">https://blog.990915.xyz/posts/ego-lite-intro/</guid><description>ego(lite) 是一个能和 AI Agent 共用的桌面浏览器，内核 Chromium，Windows beta 已经放出。本文说清它是什么、怎么四步把 agent 接进来，以及 beta 阶段、隐私和还没有 Linux 版这些要注意的坑。</description><pubDate>Mon, 26 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;大家好，这里是王先生的AI播客。前段时间，ego(lite) 出了 Windows beta 版，王先生装上了、现在也在用，这篇文章就是在这个软件上写的。名字听着有点怪，但不要怕，说白了它就是一个浏览器：你自己照常上网，你的 AI agent（Codex、Claude Code 这类）也能接进来，帮你打开网页、操作页面。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://img.990915.xyz/2026/10/26/1792991144752-54b667e1-1845-4980-9d2e-929447dd45f4.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;想直接试的，下载页在这：&lt;a href=&quot;https://lite.ego.app/download&quot;&gt;ego(lite) 下载页&lt;/a&gt;。&lt;/p&gt;
&lt;h2&gt;它是干啥的&lt;/h2&gt;
&lt;p&gt;官方文档的定位是：一款可以和 AI agent 共用的浏览器，内核是 Chromium。截至 10 月 24 日的 0.6.1.9 版，用的是 Chromium 156.0.8078.48。&lt;/p&gt;
&lt;p&gt;关键在「共用」两个字。agent 通过官方的 &lt;code&gt;ego-browser&lt;/code&gt;（一个 skill 加命令行工具）接入，任务放在独立的 Space 里跑，你这边该刷网页还是刷网页。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://img.990915.xyz/2026/10/26/1792990696851-effbdbdf-6f97-4236-bc2d-b02be48bf729.png&quot; alt=&quot;图 1　ego(lite) 工作方式示意&quot; /&gt;&lt;/p&gt;
&lt;p&gt;之前王先生写过 Obscura，那是给 agent 单独用的无头浏览器（没有界面、跑在后台）。ego(lite) 走的是另一条路：人和 agent 一起用的桌面浏览器。两者场景不同，这篇不比高下。&lt;/p&gt;
&lt;h2&gt;有啥优点&lt;/h2&gt;
&lt;p&gt;下面几条都是官方写明的，截至 10 月 24 日：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;免费&lt;/strong&gt;：官方原话是 &quot;free to download and use, with no subscription, per-task charge, or browser-time fee&quot;，不收订阅费，也不按任务或使用时长收费。模型的钱由你自己接入的 agent 承担，原来用什么模型就用什么。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;能搬家&lt;/strong&gt;：0.6.1.9 支持从 Comet、Opera、Vivaldi、Arc、Dia、Firefox、Zen 等浏览器导入数据，换过来不用从头再来。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;能当日常浏览器&lt;/strong&gt;：同一版本能播放 Netflix、Spotify 这类受版权保护的内容，还加了一个 On-device AI（本地 AI）开关。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;两个平台都有&lt;/strong&gt;：macOS 版分 Intel 和 Apple Silicon，Windows 版目前是 beta。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;接入部分开源&lt;/strong&gt;：放 &lt;code&gt;ego-browser&lt;/code&gt; skill 的官方仓库 citrolabs/ego-lite 用 MIT 许可，截至 10 月 26 日约 1.9 万 star。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;怎么用&lt;/h2&gt;
&lt;p&gt;以下步骤来自官方仓库 citrolabs/ego-lite 里的安装说明，界面上的具体文字以你装的版本为准。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第一步，装浏览器。&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;macOS：官方 skill 带了一个安装脚本，会按你的芯片下载对应安装包，装进「应用程序」文件夹后打开。&lt;/li&gt;
&lt;li&gt;Windows：没有安装脚本，到官网下载安装包自己运行。安装包叫 &lt;code&gt;egoliteSetup.exe&lt;/code&gt;，是 x64 在线安装器，大约 19 MB（截至 10 月 26 日）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果 Windows 的 SmartScreen 拦下安装包，文档给的办法是点 &quot;More info&quot;（更多信息），再点 &quot;Run anyway&quot;（仍要运行）。macOS 首次启动如果被系统拦住，到「系统设置 → 隐私与安全性」里手动允许。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第二步，走完首次引导。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;打开 ego(lite)，按引导走一遍，需要的话可以在这一步导入旧浏览器的数据。引导结束时，它会把 &lt;code&gt;ego-browser&lt;/code&gt; 命令注册进系统。Windows 用户注意：要新开一个终端窗口，这个命令才能用。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第三步，检查环境。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;先确认命令能找到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# macOS
command -v ego-browser
# Windows PowerShell
Get-Command ego-browser
# Windows cmd
where ego-browser
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;再运行下面这条，输出 &lt;code&gt;ego-browser ready&lt;/code&gt; 就说明环境好了：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ego-browser nodejs
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;第四步，把 agent 接进来。&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ego-browser skill
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;按它输出的提示把 agent 接上。如果提示 &lt;code&gt;Unknown command: skill&lt;/code&gt;，说明装的 ego(lite) 比 skill 旧，文档给的办法是运行 &lt;code&gt;ego-browser upgrade&lt;/code&gt; 升级。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://img.990915.xyz/2026/10/26/1792990771557-9d5af4ab-e406-4c7a-9dfc-9a3baa99a342.png&quot; alt=&quot;图 2　ego(lite) 安装接入四步&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;装之前要注意什么&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Windows 还是 beta&lt;/strong&gt;：更新日志里，Windows 版 10 月 19 日到 24 日连发了好几个版本，其中一条是 &quot;Fixed ego-browser crashing right away on some Windows machines&quot;（修复部分 Windows 电脑上 ego-browser 一打开就崩溃）。还在快速修问题的阶段，重要工作别全押在上面。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;页面内容会经过模型&lt;/strong&gt;：官方文档写得很直白，&quot;Your agent may send the page content it reads to the model provider&quot;。网银、公司内网这类页面，交给 agent 之前想清楚。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;受保护内容 agent 截不了图&lt;/strong&gt;：播放 Netflix 这类 DRM 内容时，ego-browser 命令行和 agent 都没法对页面截图。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;暂时没有 Linux 版&lt;/strong&gt;：官方说 Linux 在路线图上，但还没有确定的发布日期。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;搞清楚是谁在做&lt;/strong&gt;：Windows 安装包带代码签名，签名方是 CITRO LABS PTE. LIMITED，和隐私政策里写的运营主体是同一个名字。签名只说明安装包出自谁，不代表安全性经过第三方检验。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;隐私政策管得比浏览器宽&lt;/strong&gt;：适用范围除了浏览器，还写了云端 agent 服务（&quot;cloud-based AI agent service&quot;）。在意数据去向的，装之前可以把&lt;a href=&quot;https://lite.ego.app/privacy&quot;&gt;隐私政策&lt;/a&gt;读一遍。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;谁该试、谁先不用管&lt;/h2&gt;
&lt;p&gt;平时就在用 Codex、Claude Code，想让 agent 操作一个真实浏览器的朋友，可以去试试。Mac 有官方安装脚本；Windows 也能装，心里有数它是 beta 就行。用 Linux 的，或者只想要一个稳定日用浏览器、用不上 agent 的，先不用管，等 Windows 正式版出来再说。&lt;/p&gt;
&lt;p&gt;王先生的建议是：先拿不那么重要的任务让 agent 跑几次，摸清它在你电脑上稳不稳，再决定要不要当主力。&lt;/p&gt;
&lt;p&gt;下载地址再贴一次：&lt;a href=&quot;https://lite.ego.app/download&quot;&gt;ego(lite) 下载页&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;你会拿它让 agent 干点啥？还是觉得暂时用不上？两种都欢迎说说，用不上的理由王先生也想听。&lt;/p&gt;
&lt;p&gt;今天就简单说到这儿，王先生下篇见。&lt;/p&gt;
&lt;h3&gt;参考资料&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;ego(lite) 下载页：https://lite.ego.app/download&lt;/li&gt;
&lt;li&gt;ego(lite) 更新日志：https://lite.ego.app/changelog&lt;/li&gt;
&lt;li&gt;What is ego(lite) (Windows)：https://lite.ego.app/document/en/docs/windows/product-introduce&lt;/li&gt;
&lt;li&gt;ego(lite) 隐私政策：https://lite.ego.app/privacy&lt;/li&gt;
&lt;li&gt;ego-browser 安装说明（citrolabs/ego-lite）：https://github.com/citrolabs/ego-lite/blob/main/skills/ego-browser/references/install.md&lt;/li&gt;
&lt;li&gt;citrolabs/ego-lite 仓库：https://github.com/citrolabs/ego-lite&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>AI</category><category>ego-lite</category><category>AI Agent</category><category>浏览器</category><category>开源</category></item><item><title>号称逆向一切的 REA，对 AI、技术大佬和 vibe coder 分别值多少？</title><link>https://blog.990915.xyz/posts/%E5%8F%B7%E7%A7%B0%E9%80%86%E5%90%91%E4%B8%80%E5%88%87%E7%9A%84rea/</link><guid isPermaLink="true">https://blog.990915.xyz/posts/%E5%8F%B7%E7%A7%B0%E9%80%86%E5%90%91%E4%B8%80%E5%88%87%E7%9A%84rea/</guid><description>morluto/rea 是一个跨二进制、应用与运行时的逆向工程 MCP，GitHub 已 29.6 万 Star。本文分别看它对 AI 模型、技术老手和 vibe coder 的价值，附 X 上 75 条抽样的吹贬比例，以及几个别踩的坑。</description><pubDate>Sat, 17 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;先看个数字：截至 10 月 17 日 15:53（北京时间），GitHub 上的 REA（&lt;code&gt;morluto/rea&lt;/code&gt;）有 295,719 个 Star、74,665 个 Fork，它的 npm 包 &lt;code&gt;rea-agents&lt;/code&gt; 在 10 月 6 日到 12 日这一周被下载了 231,579 次。王先生的第一反应是，逆向工程这么冷门的活儿，什么时候这么多人关心了（包括王先生自己）。这篇就简单说说，REA 到底给谁带来了什么，X 上又是在吹它还是在贬它。&lt;/p&gt;
&lt;h2&gt;它到底给模型什么&lt;/h2&gt;
&lt;p&gt;官方的一句话定位是：&quot;One MCP for reverse engineering across binaries, applications, and runtime behavior.&quot; 也就是一个 MCP（让 AI agent 调用外部工具的协议）服务，把逆向分析的能力交给 agent。MIT 许可，装起来就一行（需要 Node.js 22.19 以上、24.11 以上或 26 以上）：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npx rea-agents setup
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它交给 agent 的东西，更准确的叫法是&quot;证据&quot;。按官方文档，每个产生证据的工具都会返回一条带 ID 的 Evidence 记录，并标出覆盖状态 &lt;code&gt;coverage.status&lt;/code&gt;，要么是 complete，要么是 unknown。agent 再拿这些代码、引用和&quot;未知项&quot;去解释、实现、测试。&lt;/p&gt;
&lt;p&gt;官方也把边界说得很清楚。早期 npm 包的 README 里有一句：&quot;No decompiler can guarantee the original source.&quot; 它给的是伪代码、汇编、符号、字符串这些线索；原生二进制的分析，靠的是 Hopper、Ghidra 或 IDA。&lt;/p&gt;
&lt;h2&gt;对 AI 模型：少编一点，但聪明不了多少&lt;/h2&gt;
&lt;p&gt;把这两点放一起看，REA 对模型的价值大概是：让模型手里有可以引用、标了&quot;不知道&quot;的证据，少一点凭空瞎编。X 上 @oneruofeng 有篇长文，标题就叫&quot;它把「模型别瞎编」焊进了协议&quot;（&lt;a href=&quot;https://x.com/oneruofeng/status/2111101750124199956&quot;&gt;原帖&lt;/a&gt;，王先生只看到标题）。@0xwhrrari 则提醒了一句：&quot;But finding the code is not the same as proving the behavior&quot;（&lt;a href=&quot;https://x.com/0xwhrrari/status/2110762643036217620&quot;&gt;原帖&lt;/a&gt;）。&lt;/p&gt;
&lt;p&gt;另一个绕不开的问题是模型拒答。HN 上大家的说法互相打架：用户 Meleagris 说，只要对 Anthropic 或 OpenAI 的模型稍微提一下逆向，就很容易被拒；用户 Scaevolus 回复说，逆向和反编译目前没被拦，让它找漏洞才更容易被拒。X 上 @chenchaoge1900 也吐槽 Claude &quot;不给我做逆向&quot;。这些都是个人经验，没有系统的统计。&lt;/p&gt;
&lt;p&gt;王先生的理解是：REA 能让模型手里的材料更规整，模型本身的推理能力不会因此变强，能不能干成还得看模型肯不肯干、干不干得好。&lt;/p&gt;
&lt;h2&gt;对技术大佬：常见的质疑是&quot;一层胶水&quot;&lt;/h2&gt;
&lt;p&gt;先说明一下：这次王先生没找到知名逆向研究员在 X 上的直接表态，这一节主要靠 HN 上的讨论。&lt;/p&gt;
&lt;p&gt;HN 主帖（10 月 10 日发，截至 10 月 17 日 15:53 是 807 分、339 条评论）里，几条有代表性的看法：&lt;/p&gt;
&lt;p&gt;• HN 用户 ethin 问得很直接：这比直接让 Claude &quot;装一套完整的逆向环境，包括 Ghidra&quot; 好在哪？（这条下面有 9 条回复）
• HN 用户 fwlr 觉得，它面向的是那些还没有自己一套逆向方法的人。
• HN 用户 tptacek 的说法是：每个人都有自己的一套技能、脚本和工具，Ghidra 可以当工作流的核心，&quot;but you still want something more than just Claude freestyling, at least for now.&quot;&lt;/p&gt;
&lt;p&gt;X 上 @LinearUncle 把两派总结得挺形象：一批人说它是炒作，真正牛的是背后接的 Ghidra、Hopper 这些老牌工具，REA 只是一层 MCP 胶水；另一批人拿起 REA 就到处&quot;凿凿凿&quot;（&lt;a href=&quot;https://x.com/LinearUncle/status/2110936629221450214&quot;&gt;原帖&lt;/a&gt;）。另外，《Gray Hat Hacking》的作者之一 @allenharper 在几条热帖下推了自己的一个视频，标题是&quot;5 Reasons NOT to Use REA Reverse Engineer Anything to Clone Apps&quot;（王先生没看内容，只能提标题）。&lt;/p&gt;
&lt;p&gt;王先生的理解是，对已经有成熟工作流的人来说，REA 的增量更多在于把几种工具的输出统一成同一种证据格式。&lt;/p&gt;
&lt;h2&gt;对 vibe coder：门槛确实低了，但别信&quot;免费重建&quot;&lt;/h2&gt;
&lt;p&gt;X 上吹得最响的帖子，基本是冲着这一类读者来的：&lt;/p&gt;
&lt;p&gt;• @0xCodila 的帖子约 194 万次曝光（截至 10 月 17 日），说 REA 是&quot;most dangerous thing on the internet right now&quot;，还说&quot;you can rebuild any feature you pay for, for FREE&quot;（&lt;a href=&quot;https://x.com/0xCodila/status/2109623431763292649&quot;&gt;原帖&lt;/a&gt;）。
• @hanakoxbt 约 100 万次曝光，说它是&quot;the most dangerous repo on GitHub right now&quot;（&lt;a href=&quot;https://x.com/hanakoxbt/status/2110067711363457244&quot;&gt;原帖&lt;/a&gt;）。&lt;/p&gt;
&lt;p&gt;也有实打实的玩法：@0xProbabillity 说自己逆向了家里的 IoT 设备，用 vibe coding 把整个公寓的控制塞进了菜单栏（&lt;a href=&quot;https://x.com/0xProbabillity/status/2109978137794883621&quot;&gt;原帖&lt;/a&gt;）。独立博客 kingy.ai 做了一次实测，根据 REA 的发现写出的 CSV 格式化工具通过了全部 14 个测试用例，但它自己也说了，测试对象只是一个公开的 Electron 小示例（&lt;a href=&quot;https://kingy.ai/blog/reverse-engineer-anything-ai-rea-guide/&quot;&gt;原文&lt;/a&gt;）。&lt;/p&gt;
&lt;p&gt;&quot;免费重建任何付费功能&quot;这种说法，王先生建议别当真，原因有两个：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;官方自己不让这么干&lt;/strong&gt;。REA 的&lt;a href=&quot;https://github.com/morluto/rea/blob/main/DISCLAIMER.md&quot;&gt;免责声明&lt;/a&gt;明确禁止绕过 DRM 和授权检查、复制专有代码。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;服务端的东西拿不到&lt;/strong&gt;。X 上 @shbow77 说得很具体：前端 JS 能反推的只是渲染层和局部交互，协作状态机这些全在服务端。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;另外，X 上已经有人在传绕过模型拒答的提示词，这和官方免责声明是冲突的，王先生就不转了。&lt;/p&gt;
&lt;h2&gt;X 上到底是吹还是贬&lt;/h2&gt;
&lt;p&gt;10 月 17 日下午，Grok Bot 做了一次小抽样：用三个关键词（英文、链接、中文各一个）各取最新的 25 条原帖，一共 75 条，人工分成吹、贬、中立、无关四类。&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;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;吹&lt;/td&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;贬&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;中立（介绍、新闻、提问）&lt;/td&gt;
&lt;td&gt;43&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;无关或垃圾&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;几个限制必须说清楚：这 75 条基本落在 10 月 16、17 两天，没覆盖 10 月 10 日到 14 日最火的那几天；搜索接口怎么排序不透明；分类是人工判断；同一个人的多条帖子也分开算了。所以这只能当一个粗略的印象，算不上&quot;X 上多少人在吹&quot;的统计结论。&lt;/p&gt;
&lt;p&gt;在这次抽样里，大头是中立的介绍和搬运。抽样之外，从上面引到的帖子看，吹得最响的是营销型的爆款长文，质疑更多来自 HN 和少数技术人士。&lt;/p&gt;
&lt;h2&gt;顺手提醒几个坑&lt;/h2&gt;
&lt;p&gt;• &lt;strong&gt;加密币蹭热度&lt;/strong&gt;：有账号借作者的名字推一种代币，还有人回复作者说有代币收益&quot;等你来领&quot;，这是典型的诈骗或引流话术，别碰。
• &lt;strong&gt;照抄的仓库&lt;/strong&gt;：X 上有人提醒，有一批仓库直接照抄 REA 的描述（具体多少个没核实），装之前认准 &lt;code&gt;morluto/rea&lt;/code&gt;。
• &lt;strong&gt;功劳归属&lt;/strong&gt;：作者 @morluto 自己说过，功劳应该归 @r00tth3w0r1d，是他把工具做好、让 REA 变得易懂（&lt;a href=&quot;https://x.com/morluto/status/2110623537480540362&quot;&gt;原帖&lt;/a&gt;）。&lt;/p&gt;
&lt;p&gt;商业上也有个动作值得一提：Perplexity 把 REA 集成进了 Computer 产品，当作一个 skill，用 /reverse-engineer 的任务到 10 月 31 日前免费，上限 10,000 积分（&lt;a href=&quot;https://x.com/AskPerplexity/status/2111120664543596957&quot;&gt;官方帖&lt;/a&gt;、&lt;a href=&quot;https://x.com/AravSrinivas/status/2111124769450135880&quot;&gt;CEO 帖&lt;/a&gt;）。&lt;/p&gt;
&lt;h2&gt;王先生怎么看&lt;/h2&gt;
&lt;p&gt;王先生自己算是懂一点编程技术、但更喜欢 vibe coding 的那一类。REA 王先生不会用，主要是觉得风险比较大。&lt;/p&gt;
&lt;p&gt;对&quot;免费重建付费功能&quot;这类宣传，王先生偏负面，觉得吹得有点过了。&lt;/p&gt;
&lt;p&gt;所以王先生也没拿合法目标去测过，暂时也不打算用。&lt;/p&gt;
&lt;h2&gt;谁该看、谁先不用管&lt;/h2&gt;
&lt;p&gt;简单说：做 agent、想让模型少编东西的，可以去看看它的证据格式；已经有一套 Ghidra 工作流的老手，增量可能不大，看看就好；想靠它&quot;免费复刻付费软件&quot;的，先把免责声明读完再说。王先生的建议是，拿自己的东西去试，别拿别人的。&lt;/p&gt;
&lt;p&gt;项目地址再贴一次：https://github.com/morluto/rea&lt;/p&gt;
&lt;p&gt;这个东西你会拿来干嘛？还是觉得暂时用不上？两种都欢迎说说，说用不上的理由王先生也想听。&lt;/p&gt;
&lt;p&gt;王先生先说到这儿，下篇见。&lt;/p&gt;
</content:encoded><category>AI</category><category>REA</category><category>逆向工程</category><category>AI Agent</category><category>MCP</category><category>开源</category></item><item><title>100 万参数、18 MB、纯 CPU：Datalab 的 Indra OCR 号称快 11 倍，实际快多少？</title><link>https://blog.990915.xyz/posts/indraocr%E4%B8%80%E4%B8%AA%E8%BD%BB%E9%87%8F%E5%8C%96%E7%9A%84ocr%E6%A8%A1%E5%9E%8B/</link><guid isPermaLink="true">https://blog.990915.xyz/posts/indraocr%E4%B8%80%E4%B8%AA%E8%BD%BB%E9%87%8F%E5%8C%96%E7%9A%84ocr%E6%A8%A1%E5%9E%8B/</guid><description>Datalab 10 月 13 日发布的 Indra OCR 只有约 100 万参数、18 MB，纯 CPU 跑 ONNX，官方称 32 核上 49 页/秒。本文拆开「快 11 倍」的前提，附一台 6 核台式机的速度与内存实测，以及六条使用经验。</description><pubDate>Fri, 16 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;先看个数字：一个 OCR 模型，主识别模型只有约 100 万参数，模型文件加起来约 18 MB，不用 GPU，也不用装 PyTorch。这篇就简单说说 Datalab 10 月 13 日发布的 Indra OCR：成绩怎么样、速度到底快多少、谁值得用。&lt;/p&gt;
&lt;h2&gt;它是个啥&lt;/h2&gt;
&lt;p&gt;模型卡上的原话是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;Indra OCR is a 1M-parameter OCR model that reads up to 49 pages per second on CPU. It turns PDFs and images into markdown, plain text, or JSON with boxes&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;说白了，就是一个纯 CPU 跑的 OCR 包，能把 PDF 和图片转成 markdown、纯文本，或者带坐标框的 JSON，开发方是 Datalab。&lt;/p&gt;
&lt;p&gt;几个基本信息（截至 10 月 16 日）：&lt;/p&gt;
&lt;p&gt;• 主识别模型 &lt;code&gt;rec.onnx&lt;/code&gt; 约 100 万参数，模型文件合计约 18 MB
• 跑在 ONNX Runtime 上，不需要 PyTorch
• PyPI 最新版本 0.3.2&lt;/p&gt;
&lt;h2&gt;官方成绩：先说好，这些都是自报的&lt;/h2&gt;
&lt;p&gt;下面的分数全部来自 Datalab 的模型卡和博客，测的是 Datalab 自己做的 OmniParseBench，目前没有找到第三方复现。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;模型 / 模式&lt;/th&gt;
&lt;th&gt;headline&lt;/th&gt;
&lt;th&gt;text&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Indra OCR 默认&lt;/td&gt;
&lt;td&gt;62.1&lt;/td&gt;
&lt;td&gt;41.3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Indra OCR 开 &lt;code&gt;--math&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;66.8&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PaddleOCR PP-OCRv6 small（纯文本模型）&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;35.8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tesseract&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;19.3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PP-StructureV3&lt;/td&gt;
&lt;td&gt;58.4&lt;/td&gt;
&lt;td&gt;55.6&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;中文子集上，官方报的是 Indra 64.7，PP-OCRv5 mobile 65.4，PP-StructureV3 68.4。&lt;/p&gt;
&lt;p&gt;挺难得的一点是，官方自己把弱项也摆出来了：不开 &lt;code&gt;--math&lt;/code&gt; 时，PP-StructureV3 的 text 成绩（55.6）比 Indra（41.3）高；中文子集上它也排在两个 Paddle 方案后面；手写只有约 8%，老旧扫描件约 20%。&lt;/p&gt;
&lt;h2&gt;速度到底快多少&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;官方的说法&lt;/strong&gt;：同一台 32 核 x86 机器（无 GPU）、同一批 300 页，每核一个 worker、OCR 模式、默认设置下，Indra OCR 约 49 页/秒，是 PaddleOCR PP-OCRv6 small 纯文本模型的 11.5 倍、Tesseract 的 16.9 倍。所以&quot;快 11 倍&quot;说的是 32 核吞吐量，比的是 PP-OCR 纯文本模型。单页中位延迟约 228 ms 是在 4 个 vCPU 上测的。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;个人测试&lt;/strong&gt;：X 上的 @manateelazycat 说自己测了一下，Indra OCR 默认只快 1.24 倍，他深度优化后快 2.97 倍，并说经 AI 分析，&quot;快 11 倍是 32 个线程叠加的数据&quot;（&lt;a href=&quot;https://x.com/manateelazycat/status/2110539989218107644&quot;&gt;原帖&lt;/a&gt;）。他没有公开测试方法，所以这只能算一份个人测试。&lt;/p&gt;
&lt;p&gt;两边其实不完全矛盾：官方的倍数带着 32 核这个前提，个人测试的条件不一样。看到&quot;快 11 倍&quot;的时候，先问一句是在多少核上测的。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;王先生自己也测了一遍&lt;/strong&gt;。机器是一台 i5-12490F（6 核 12 线程）的 Windows 11 台式机，跑的是 indra-ocr 0.3.2，测试文件是一篇 14 页、带文本层的英文论文。先说清楚：这次只测了速度和内存，没测识别准确率，也没和 PaddleOCR 放在同一台机器上对比。&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;14 页 PDF，默认模式&lt;/td&gt;
&lt;td&gt;约 3.2 秒，约 4.3 页/秒&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;14 页 PDF，强制 OCR（&lt;code&gt;--mode ocr&lt;/code&gt;）&lt;/td&gt;
&lt;td&gt;约 7.1 秒，约 2 页/秒&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;单页 PDF&lt;/td&gt;
&lt;td&gt;3.5–5.5 秒&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;14 帧多页 TIFF&lt;/td&gt;
&lt;td&gt;约 43 秒&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;大约三分之一是启动成本&lt;/strong&gt;。14 页 3.2 秒里，进程池启动就占了 1.1–1.5 秒，所以零散地一页一页调用最不划算，空白页也要 3.2 秒左右。少于 4 页的文档不会开并行，能攒成一批就攒成一批。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;核数不是越多越好&lt;/strong&gt;。这台 6 核机器上开 8 个 worker 最快，开到 12 个反而回退。王先生的建议是把 &lt;code&gt;--cores&lt;/code&gt; 设成 6–8，别超过逻辑核数。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;多页图片先转成 PDF&lt;/strong&gt;。图片输入不走进程池，同样 14 页内容，TIFF 要 43 秒，PDF 强制 OCR 只要 7 秒左右。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;调 dpi 基本不影响速度&lt;/strong&gt;。150、200、300 dpi 的耗时都在 7 秒上下（准确率这次没测）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;内存&lt;/strong&gt;：默认 12 个 worker 时约 1.6 GB，强制 OCR 约 2.2 GB。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;中文 Windows 有两个编码坑&lt;/strong&gt;：&lt;code&gt;--math&lt;/code&gt; 会直接报错退出，设 &lt;code&gt;PYTHONUTF8=1&lt;/code&gt; 就好了；把结果输出到 stdout 再重定向到文件，遇到特殊字符也会崩，用 &lt;code&gt;--out&lt;/code&gt; 指定输出文件，或者设 &lt;code&gt;PYTHONIOENCODING=utf-8&lt;/code&gt;。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;说白了，在王先生这台 6 核机器上，默认模式处理一份带文本层的 PDF 确实挺快；这次没和 PaddleOCR 同机比，所以对&quot;快 11 倍&quot;下不了结论。&lt;/p&gt;
&lt;h2&gt;能读什么，读不了什么&lt;/h2&gt;
&lt;p&gt;按 GitHub README，扫描件和图片的 OCR 支持：&lt;/p&gt;
&lt;p&gt;• 拉丁文（约 50 种语言）、西里尔文、希腊文、天城文、孟加拉文
• 简体和繁体中文&lt;/p&gt;
&lt;p&gt;读不了的：日文、韩文、阿拉伯文、泰文的扫描件，还有竖排文字（比如繁体中文报纸那种）。&lt;/p&gt;
&lt;p&gt;X 上 @Gorden_Sun 也说它处理不了复杂表格和手写（&lt;a href=&quot;https://x.com/Gorden_Sun/status/2110554623404802133&quot;&gt;原帖&lt;/a&gt;），和官方自报的手写弱项对得上。&lt;/p&gt;
&lt;h2&gt;怎么装&lt;/h2&gt;
&lt;p&gt;需要 Python 3.10 及以上：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pip install indra-ocr
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;谁可以试、谁先不用管&lt;/h2&gt;
&lt;p&gt;简单说：手里有大量拉丁文或中文印刷体的 PDF、只有 CPU、想把 OCR 塞进 RAG 或文档解析管线的，可以去试试；要处理复杂表格、手写、日韩文或竖排的，先不用管，现在它不擅长这些。王先生的建议是，别只看&quot;快 11 倍&quot;，拿你自己的文档在你自己的机器上跑一遍再决定。&lt;/p&gt;
&lt;p&gt;王先生平时用的是 MinerU。这次没把两者放在一起比准确率，所以先不下谁更好的结论，后面有机会再拿同一批文档对一对。&lt;/p&gt;
&lt;p&gt;还有一点要提醒：代码是 Apache-2.0，但模型权重用的是修改版 OpenRAIL-M，研究、个人使用和融资或营收低于 2000 万美元的初创公司可以免费用，不能用来和 Datalab 的 API 竞争，更大规模的商用要另外买授权。准备放进自己产品里的，先把许可证看完。&lt;/p&gt;
&lt;p&gt;项目地址再贴一次：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GitHub：https://github.com/datalab-to/indra&lt;/li&gt;
&lt;li&gt;Hugging Face：https://huggingface.co/datalab-to/indra-ocr&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;你现在做文档解析用的是什么 OCR 方案？评论区聊聊，王先生也想抄抄作业。&lt;/p&gt;
&lt;p&gt;今天就简单说到这儿，王先生下篇见。&lt;/p&gt;
</content:encoded><category>AI</category><category>OCR</category><category>ONNX</category><category>开源</category><category>性能测试</category></item><item><title>简单说说 Herdr UI：herdr 的原生桌面客户端</title><link>https://blog.990915.xyz/posts/%E7%AE%80%E5%8D%95%E8%AF%B4%E8%AF%B4-herdr-ui/</link><guid isPermaLink="true">https://blog.990915.xyz/posts/%E7%AE%80%E5%8D%95%E8%AF%B4%E8%AF%B4-herdr-ui/</guid><description>Herdr UI 是 herdr 守护进程的原生桌面客户端，用 Rust/GPUI 写成，建仓不到一个月就有 1,367 Star。本文说清它是什么、侧栏审阅和 Teleport 这些功能、三个平台怎么装，以及王先生实际用下来的感受。</description><pubDate>Fri, 16 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Herdr UI，说白了它就是 herdr 守护进程的一个原生桌面客户端：herdr 照常在后台跑，Herdr UI 给它开一个窗口。要是你本来就在用 herdr 跑 Coding Agent，这篇可以花几分钟看看。&lt;/p&gt;
&lt;h2&gt;它到底是个啥&lt;/h2&gt;
&lt;p&gt;项目 README 的原话是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;A native Rust/GPUI client for macOS, Linux, and Windows, for a Herdr daemon you installed yourself. It paints the daemon&apos;s terminal cells, split panes included, without running another terminal emulator or wrapping the TUI.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;翻成大白话：它用 Rust/GPUI 写成，能在 macOS、Linux、Windows 上跑，连接的是你自己装好的 herdr 守护进程，然后把守护进程里的终端格子（包括分屏）直接画出来，中间不再套一个终端模拟器，也不去包 herdr 自带的 TUI。&lt;/p&gt;
&lt;p&gt;官网 &lt;a href=&quot;https://herdrui.dev&quot;&gt;herdrui.dev&lt;/a&gt; 上一句话说得更短：&quot;Herdr UI is a native client for the Herdr daemon you already run.&quot;&lt;/p&gt;
&lt;p&gt;几个基本信息（截至 10 月 15 日）：&lt;/p&gt;
&lt;p&gt;• 作者：Fabien Penso（官网页脚署名）
• 许可证：Apache-2.0
• 仓库 2026-09-20 创建，1,367 Star、103 Fork
• 最新版本 v20261014.1，10 月 15 日 08:01（北京时间）发布&lt;/p&gt;
&lt;p&gt;建仓还不到一个月。&lt;/p&gt;
&lt;h2&gt;项目介绍里说它能干这些&lt;/h2&gt;
&lt;p&gt;下面都来自 README 和官网的自述，王先生还没逐个实测，大家看的时候心里有个数。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;一个侧栏装下工作区、worktree 和 agent&lt;/strong&gt;：每个 agent 带着守护进程给的状态点，空闲、工作中、等你处理，一眼能看出来。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;像审 PR 一样审 agent 的改动&lt;/strong&gt;：点任意一行留言，然后点 Send to agent 把意见发回去。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;浏览器标注&lt;/strong&gt;：在页面上选元素或区域，写好备注，再发回给对应的 agent。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Teleport&lt;/strong&gt;：把一个 worktree 连同提交、未提交的改动、标签页、分屏、正在跑的程序和 agent 会话一起挪到另一台主机。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;其他&lt;/strong&gt;：官网还提到从 issue 派发任务、并排审阅、checkpoints、Devices 总览；README 里另有侧栏布局切换、AI 服务用量面板、每台主机的 CPU/内存、原生设置页（能用 Ghostty 主题）、亮/暗主题、SSH 文件复制、系统通知和 Dock 角标。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/penso/herdr-gpui/HEAD/docs/screenshots/workspaces.png&quot; alt=&quot;截图 1 工作区总览&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/penso/herdr-gpui/HEAD/docs/screenshots/review.png&quot; alt=&quot;截图 2 审阅改动&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/penso/herdr-gpui/HEAD/docs/screenshots/teleport.png&quot; alt=&quot;截图 3 Teleport&quot; /&gt;&lt;/p&gt;
&lt;p&gt;王先生觉得最有意思的是第 2 条：agent 改完代码，你逐行写意见再一键发回去，这跟平时给同事 review PR 的手感差不多。&lt;/p&gt;
&lt;h2&gt;怎么装&lt;/h2&gt;
&lt;p&gt;先记住官方这句话：&quot;Install the Herdr daemon first; this app is only its client.&quot; 也就是得先装好 herdr 本体，Herdr UI 只是客户端，它不会帮你装或者升级 herdr。&lt;/p&gt;
&lt;p&gt;macOS（要求 macOS 14.2 以上）：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;brew install penso/tap/herdr-gpui
open -a Herdr
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Linux（x86_64/ARM64，glibc 2.39 以上）：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl -fsSL https://herdrui.dev/install.sh | sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Windows（官方标的是实验性）：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;irm https://herdrui.dev/install.ps1 | iex
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;装好以后，官网的说法是：&quot;Then run herdr in a terminal and open Herdr UI: both show the same panes.&quot; 终端里的 herdr 和这个窗口看到的是同一组分屏，两边可以同时开着。&lt;/p&gt;
&lt;h2&gt;谁在用&lt;/h2&gt;
&lt;p&gt;目前没有官方的用户名单或者用户量数据，能找到的是 X 上几位开发者的个人说法：&lt;/p&gt;
&lt;p&gt;• @championswimmer 说它已经成了他的 &quot;daily driver terminal&quot;（&lt;a href=&quot;https://x.com/championswimmer/status/2109640472649937011&quot;&gt;原帖&lt;/a&gt;）
• @praneelrathore 说试了以后 &quot;never looked back. Even contributed to it&quot;（&lt;a href=&quot;https://x.com/praneelrathore/status/2110209996000743683&quot;&gt;原帖&lt;/a&gt;）
• @DanThompsonIV 说 &quot;working well&quot;（&lt;a href=&quot;https://x.com/DanThompsonIV/status/2110196369399124048&quot;&gt;原帖&lt;/a&gt;）&lt;/p&gt;
&lt;p&gt;这几条只能说明有人用得挺顺手，代表不了多少人在用。&lt;/p&gt;
&lt;h2&gt;王先生自己用下来&lt;/h2&gt;
&lt;p&gt;王先生自己也装上用了一阵，说几点直观感受（个人体验，仅供参考）：&lt;/p&gt;
&lt;p&gt;• 界面简洁，看着挺舒服，没有花里胡哨的东西。
• agent 可以在后台跑，窗口关掉、重启以后再打开，上次的工作状态和进度还在，接着看就行。
• 还能连到远程服务器上的 agent，不用非得在本机跑。&lt;/p&gt;
&lt;p&gt;后两点王先生觉得最实用：长任务丢给 agent 以后不用一直开着窗口盯，回来打开就能接上。&lt;/p&gt;
&lt;h2&gt;谁可以试、谁先不用管&lt;/h2&gt;
&lt;p&gt;简单说：已经在用 herdr、又想要一个能看状态、能审改动的窗口的，可以去试试；还没装 herdr 的，先把本体搞明白再说；Windows 用户可以等它脱掉&quot;实验性&quot;的标签。王先生的建议是先在一台不要紧的机器上装来玩玩，顺不顺手自己最清楚。&lt;/p&gt;
&lt;p&gt;项目地址再贴一次：https://github.com/penso/herdr-gpui&lt;/p&gt;
&lt;p&gt;你现在跑 Coding Agent，是直接在终端里开，还是用了什么客户端？评论区聊聊，王先生也想抄抄作业。&lt;/p&gt;
&lt;p&gt;今天就简单说到这儿，王先生下篇见。&lt;/p&gt;
</content:encoded><category>AI</category><category>Herdr</category><category>Rust</category><category>GPUI</category><category>AI Agent</category></item><item><title>Magpie：一个菜单栏小工具，把全网 AI Agent 吵翻了</title><link>https://blog.990915.xyz/posts/magpie%E4%B8%80%E4%B8%AA%E8%8F%9C%E5%8D%95%E6%A0%8F%E5%B0%8F%E5%B7%A5%E5%85%B7/</link><guid isPermaLink="true">https://blog.990915.xyz/posts/magpie%E4%B8%80%E4%B8%AA%E8%8F%9C%E5%8D%95%E6%A0%8F%E5%B0%8F%E5%B7%A5%E5%85%B7/</guid><description>magpie 能一键给 Claude Code、Codex 等 Agent 换模型，作者 yetone 却因「7×24 全 AI 自动化开发」被质疑，双方在 X 上吵翻。本文理清项目本身、AGENTS.md 与 LESSONS.md 的开发方式，以及这场争吵的来龙去脉。</description><pubDate>Tue, 13 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;最近几天，中文开源圈和 AI 编程圈被一个叫 magpie 的项目搅得有点热闹。&lt;/p&gt;
&lt;p&gt;项目本身倒是不复杂——一个跑在菜单栏里的小工具，能让你给 Claude Code、Codex、Gemini CLI、OpenCode 这些 Agent 一键换模型。但它的作者 yetone 因为「7×24 全 AI 自动化开发」被喷「快餐式服务」，后来直接开骂，双方在 X 上吵了个昏天黑地。&lt;/p&gt;
&lt;p&gt;吃瓜归吃瓜，先把项目本身说清楚。&lt;/p&gt;
&lt;h2&gt;它到底是干什么的？&lt;/h2&gt;
&lt;p&gt;一句话：&lt;strong&gt;所有 Agent 的模型，一处搞定。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;现在很多人同时开着好几个编程 Agent。Claude Code 用一个模型，Codex 用另一个，Gemini CLI 再换一个，每个工具的配置文件格式都不一样，订阅账号更是各管各的。额度用完了就得手动切，烦得很。&lt;/p&gt;
&lt;p&gt;magpie 做的事情很简单：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;扫描你机器上装了哪些 Agent，在菜单栏统一展示&lt;/li&gt;
&lt;li&gt;点一下就能给任意 Agent 切换模型&lt;/li&gt;
&lt;li&gt;背后跑一个本地网关（默认 &lt;code&gt;127.0.0.1:3425&lt;/code&gt;），做协议转换&lt;/li&gt;
&lt;li&gt;所以你可以让 Claude Code 跑 Kimi，让 Codex 跑 DeepSeek，让 Gemini CLI 用你的 ChatGPT 订阅&lt;/li&gt;
&lt;li&gt;支持把多个账号做成路由组，一个额度用完自动切下一个&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;支持的 Agent 已经很多了，Claude Code、Codex、Gemini CLI、OpenCode、Cursor CLI、Cline、各种小众的都有。安装也简单，一行命令：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl -fsSL https://usemagpie.ai/install.sh | sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;仓库是 &lt;a href=&quot;https://github.com/yetone/magpie&quot;&gt;yetone/magpie&lt;/a&gt;，MIT 协议，目前 1 万多 stars，三个星期左右的时间。作者 yetone 之前做过 avante.nvim。&lt;/p&gt;
&lt;h2&gt;为什么能这么快？&lt;/h2&gt;
&lt;p&gt;真正让它引发争议的，不是功能，而是开发方式。&lt;/p&gt;
&lt;p&gt;根据仓库里的记录和后来有人扒出来的分析，magpie 的代码确实主要是由 Agent 写、审、合并、发版的。仓库里有两个关键文件：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;AGENTS.md&lt;/code&gt;：相当于一张路由表，告诉 Agent 改什么之前先看哪份文档。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;LESSONS.md&lt;/code&gt;：一本「错题本」。每天夜里 Agent 会复盘当天的 commit，把返工的、不该合的、验证做得太糙的问题记下来。同一条教训出现三次，就会被升级成硬规则，写进代码规范。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;另外还有一些比较具体的机制：改界面的 PR 会自动录屏、要求做回退测试（把旧代码放回去必须真挂）、没跑过的检查必须明确写出来、风险操作要等人放行等。&lt;/p&gt;
&lt;p&gt;也就是说，它不是「让 AI 随便写一写就合并」，而是在尝试用 Agent 自己积累规则、自己复盘、自己刹车。当然，这些规则本身也是 Agent 写的，人主要负责方向和关键闸门。&lt;/p&gt;
&lt;h2&gt;吵架是怎么起来的？&lt;/h2&gt;
&lt;p&gt;10 月 11 日晚上到 12 日凌晨，事情爆发。&lt;/p&gt;
&lt;p&gt;芒果刀（@ThirteenYizuka）发帖质疑 magpie 的质量，说自己主要是「听说」，担心 AI 全流程开发因为上下文有限，只能做局部最优，缺少人类全局 review，版本滚得太快不太敢用。&lt;/p&gt;
&lt;p&gt;Seefs 在评论里直接用了「快餐式服务」「这种作者」「成什么样子都无所谓」这类表述。yetone 看到后感到被冒犯，引用回复，强调自己是自费订阅最贵的模型、7×24 小时免费做产品，质问为什么被说成快餐。&lt;/p&gt;
&lt;p&gt;后面清凤下场，说 yetone「不像人类」，还说他提最贵模型是在「卖惨」。两人还发了「警惕推特饭圈化」相关内容，当时名字后面都挂着相同的 memoh 认证 logo。yetone 认为这是小团体抱团抹黑，彻底爆发，开始大量国骂，并自嘲「重回低素质巅峰时期」。&lt;/p&gt;
&lt;p&gt;yetone 后来发了一篇长文，配了对方已删帖的截图，梳理自己的心路历程：最初看到质疑时还想分享工作流，真正被激怒的是扣帽子和后续的阴阳怪气。他认为对方是无证据的有罪推定，对这种行为用国骂回应是「最大的尊重」。&lt;/p&gt;
&lt;p&gt;芒果刀后来也承认话说太快了，应该带证据再质疑。&lt;/p&gt;
&lt;h2&gt;怎么看这件事？&lt;/h2&gt;
&lt;p&gt;技术层面，质疑「全 AI 自动化开发到底靠不靠谱」本身是合理的。上下文窗口有限、容易局部最优、人类 review 的价值，这些都是真实问题。magpie 试图用「错题本 + 规则沉淀 + 回退测试」来缓解，但效果如何，最终还是要看用户实际用下来稳不稳。&lt;/p&gt;
&lt;p&gt;但质疑方式确实有问题。在没有具体证据、自己也没怎么用的情况下，直接扣「快餐式服务」「这种作者」的帽子，很容易让人觉得是在攻击人而不是讨论事。尤其当产品是免费开源、作者还在自费砸模型的时候，这种说法会特别刺耳。&lt;/p&gt;
&lt;p&gt;yetone 后面的国骂，从结果上看确实把技术讨论变成了人身攻击和饭圈对立，也让一部分人觉得作者情绪管理有问题。但他自己也说得很直白：对这种他认为是阴阳怪气和抱团抹黑的行为，他选择用国骂回应。&lt;/p&gt;
&lt;p&gt;两边其实都有点典型：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一方觉得「AI 写的代码质量存疑，应该谨慎」&lt;/li&gt;
&lt;li&gt;一方觉得「你没证据就扣帽子，还阴阳怪气，我为什么要惯着你」&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;产品本身倒是挺有意思的。它把一个很实际的痛点（多 Agent 模型切换和订阅互通）做成了轻量工具，又在尝试用 Agent 来维持自己的迭代速度。至于这套工作流最终能不能稳住质量，还是得看后面几个月的实际表现。&lt;/p&gt;
&lt;p&gt;你怎么看这种「全 AI 自动化开发」的项目？是真有潜力，还是迟早翻车？评论区可以说说。&lt;/p&gt;
</content:encoded><category>AI</category><category>magpie</category><category>AI Agent</category><category>开源</category><category>行业观察</category></item><item><title>有人用 AI 将 Adobe 全家桶重写了</title><link>https://blog.990915.xyz/posts/%E6%9C%89%E4%BA%BA%E7%94%A8ai%E5%B0%86adobe%E5%85%A8%E5%AE%B6%E6%A1%B6%E9%87%8D%E5%86%99%E4%BA%86/</link><guid isPermaLink="true">https://blog.990915.xyz/posts/%E6%9C%89%E4%BA%BA%E7%94%A8ai%E5%B0%86adobe%E5%85%A8%E5%AE%B6%E6%A1%B6%E9%87%8D%E5%86%99%E4%BA%86/</guid><description>10 月 ArtCraft 用 Claude Opus 5.5 一口气开源了 7 个对标 Adobe 的应用，全网刷屏。本文从 PhotoCraft 自己那份「诚实」的 roadmap 出发，看 25%–35% 的专业可用度、按 agent 小时计价的账单，以及 Adobe 还剩下的护城河。</description><pubDate>Sat, 10 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;01 「我一把梭出了Photoshop」，四天后全网刷屏&lt;/h2&gt;
&lt;p&gt;10月2日早上7点多，Hacker News上一个最无聊的帖子下面，出现了一条一点都不无聊的评论。&lt;/p&gt;
&lt;p&gt;那个帖子是每月例行的「Who is hiring」，大家在里面贴招聘、找工作，平平无奇。&lt;/p&gt;
&lt;p&gt;然后有个ID叫echelon的人，在底下留了这么几句。&lt;/p&gt;
&lt;p&gt;「Software is over. But for real. I just one-shotted Photoshop. The whole thing.」&lt;/p&gt;
&lt;p&gt;软件完了，我是认真的，我刚刚一把梭出了一个Photoshop，完整的那种。&lt;/p&gt;
&lt;p&gt;他还补了一句，说他搞建筑承包的邻居，一点软件经验都没有，做了个养老护理的App，已经有用户了。最后一句是，「Our career is worthless soon.」&lt;/p&gt;
&lt;p&gt;我们这行，很快就不值钱了。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://img.990915.xyz/2026/10/09/1791533688588-691ed81b-2427-42bf-9afb-bc3a2155b5d2.png&quot; alt=&quot;Brandon Thomas在HN招聘帖下的评论&quot; /&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;这个echelon，真名叫Brandon Thomas，是一个叫ArtCraft的开源工作室的开发者。ArtCraft原来是做AI图像和视频创作工具的，9月30日晚上到10月1日，他们在GitHub上一口气开了7个仓库。&lt;/p&gt;
&lt;p&gt;PhotoCraft对标Photoshop，VectorCraft对标Illustrator，FilmCraft对标Premiere Pro，LightCraft对标Lightroom，PdfCraft对标Acrobat，EffectCraft对标After Effects，DesignCraft对标InDesign。&lt;/p&gt;
&lt;p&gt;全部纯Rust写，MIT和Apache双协议开源，免费，Mac、Windows、Linux原生跑，大部分还能编译成WebAssembly，直接在浏览器里打开。&lt;/p&gt;
&lt;p&gt;写代码的主力，是Claude Opus 5.5。&lt;/p&gt;
&lt;p&gt;10月6日深夜，一个叫Kevin的创业者在X上发了条推，「This guy re-created all the adobe apps with opus-5.5, ported them to rust, and opensourced them」。&lt;/p&gt;
&lt;p&gt;5.1万赞，188万浏览。&lt;/p&gt;
&lt;p&gt;几个小时后，开源圈的老炮Eric S. Raymond，就是写《大教堂与集市》的那位，转发说了一句狠话，「Adobe just got nuked. And closed source is dead, dead, dead.」&lt;/p&gt;
&lt;p&gt;Adobe被核平了，闭源软件死了，死透了。&lt;/p&gt;
&lt;p&gt;这条被看了386万次。&lt;/p&gt;
&lt;p&gt;然后就是大家熟悉的剧本。「Adobe is cooked」，「Adobe lawyers right now」的梗图刷屏，中文圈也跟上了，「AI花了4天，把Adobe全家桶重写了一遍」，「Adobe后背发凉了」。PhotoCraft的star数，到我写这篇文章的10月9日上午，已经快3万了，距离建仓库不到10天。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://img.990915.xyz/2026/10/09/1791533707411-ed2374c9-979f-4fce-b361-41bb4407c7c5.png&quot; alt=&quot;PhotoCraft的GitHub页面&quot; /&gt;&lt;/p&gt;
&lt;p&gt;应用打开第一印象是&lt;strong&gt;非常快&lt;/strong&gt;，UI界面也&lt;strong&gt;挺漂亮&lt;/strong&gt;，打开PSD文件的&lt;strong&gt;功能也一切OK。&lt;/strong&gt; 但我对PS不熟悉，具体功能就不测试了。&lt;/p&gt;
&lt;h2&gt;02 Adobe完了吗？PhotoCraft自己先说了，没有&lt;/h2&gt;
&lt;p&gt;我知道你现在想问什么。&lt;/p&gt;
&lt;p&gt;所以Adobe到底完了没有？&lt;/p&gt;
&lt;p&gt;坦率的讲，没有，差得还远。&lt;/p&gt;
&lt;p&gt;而且这话不是我说的，是PhotoCraft自己说的。&lt;/p&gt;
&lt;p&gt;我去翻了这个项目的仓库，有个地方让我挺意外，它的roadmap写得非常老实，老实到跟外面的热搜完全是两个世界。&lt;/p&gt;
&lt;p&gt;PhotoCraft的README里直接写，现在是early alpha，「not yet a Photoshop replacement for daily professional work」，还不能拿来替代Photoshop干专业的活。缺AI生成类功能，缺大概二十个工具，排版深度不够，插件也兼容不了。&lt;/p&gt;
&lt;p&gt;roadmap里还有一节，叫「Honest parity assessment」，诚实的对齐度评估，10月5日写的。结论是，真正的Photoshop对齐度「still well below 50%」，远低于一半。功能表面大概覆盖了普通Photoshop用户会碰到的东西的60%到70%，但如果问一个专业的人能不能明天就切过去天天用，他们自己估的是25%到35%。&lt;/p&gt;
&lt;p&gt;他们甚至把丢人的地方也写进去了。第一批用户一上手，就挖出了一堆基础问题，文字选区错位，214个快捷键失灵，面板自己乱改尺寸，裁切框拖不动。而这些功能，在他们自己的对照表里，原来全都标的是「已上线」。&lt;/p&gt;
&lt;p&gt;还有一个数字特别有意思。PhotoCraft说Photoshop的菜单项，他们已经接上了85.1%。但紧跟着一句，这个数字「measures wiring, not behaviour」，只算接线，不算行为。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;菜单点得开，不等于功能做得对。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;所以你看，「AI重写了Adobe全家桶」这个说法，就是在传播链条里一层一层加上去的。作者本人在Reddit上喊过「一个月内100%对齐」，被HN上的人追着问，后来自己改口成「99%要花一段时间，但我确定是以月计，不是以年计」。&lt;/p&gt;
&lt;p&gt;天没塌。&lt;/p&gt;
&lt;p&gt;但我看完他们的roadmap，脑子里一直挥之不去的，根本不是Photoshop什么时候被追上。&lt;/p&gt;
&lt;p&gt;而是另一行字。&lt;/p&gt;
&lt;h2&gt;03 真正吓人的，是roadmap里写的那个单位&lt;/h2&gt;
&lt;p&gt;在FilmCraft，也就是对标Premiere的那个项目的roadmap里，有一段估算剩余工作量的话。&lt;/p&gt;
&lt;p&gt;我原样翻译一下。&lt;/p&gt;
&lt;p&gt;「上一个工作时段（10月1日夜到10月2日），5个Opus 5.5 agent并行跑了大约4.5个小时（算上集成，大约18个agent小时），把对齐度往前推了大约4个点，折合每个点4到5个agent小时。」&lt;/p&gt;
&lt;p&gt;后面还跟着一张表。离功能清单对齐还剩大约19个点，需要90到125个Opus 5.5 agent小时。要做到他们说的「100% and better」，总共210到325个agent小时，换算成墙钟时间，4到5个agent加一个人做集成，是50到82个小时，括号里写着，「≈2–3.5 days, 24/7」。&lt;/p&gt;
&lt;p&gt;VectorCraft那边也是一模一样的写法。功能对齐，单个agent要210到330小时，4到6个agent并行要55到95小时。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://img.990915.xyz/2026/10/09/1791533725618-45b164aa-50f0-4d3e-b986-ba66d5d33b21.png&quot; alt=&quot;FilmCraft roadmap里的agent小时估算表&quot; /&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;而这份roadmap里，写的是Opus 5.5 agent小时。&lt;/p&gt;
&lt;p&gt;一个功能点，4到5个agent小时。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;这是一张算力账单。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;说到人月，我突然想起一本老书。&lt;/p&gt;
&lt;p&gt;很多做软件的朋友都知道，叫《人月神话》，1975年Fred Brooks写的。里面最有名的一条叫布鲁克斯定律，大意是，给一个已经延期的项目加人，只会让它更延期。人一多，沟通、磨合、等待的成本，涨得比你加进来的产能还快。&lt;/p&gt;
&lt;p&gt;这条定律统治了软件工程差不多五十年。人和月不能互换，这是行业常识。&lt;/p&gt;
&lt;p&gt;然后，我在FilmCraft的roadmap里，看到了几乎一模一样的话，只不过主角从人换成了agent。&lt;/p&gt;
&lt;p&gt;他们写，速度的瓶颈在一台机器的CPU和硬盘，超过大概5个agent，所有agent都会变慢，每个工作副本编译一次要6到7个G，跑一次完整的CI要20到60分钟。还有一个瓶颈，是那个唯一负责合并代码、解决冲突的集成者。比如两个agent同时去改了项目的schema，就得有人去收拾。&lt;/p&gt;
&lt;p&gt;那个负责收拾的，是人。&lt;/p&gt;
&lt;p&gt;我当时看到这段，差点笑出来。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;布鲁克斯定律没死，它只是搬了个家。&lt;/strong&gt; 以前卡在人和人之间的沟通，现在卡在agent和agent之间的合并冲突，卡在最后那个人类集成者的脑子里。&lt;/p&gt;
&lt;p&gt;但有一点，跟五十年前完全不一样了。&lt;/p&gt;
&lt;p&gt;以前你说「再加5个人干4个半小时」，这句话本身就没意义，5个人4个半小时，连需求都还没对完。现在这句话有意义了，而且被白纸黑字写进了一个快3万star项目的官方roadmap里。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;人月，正在变成token账单上的一行。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;顺着这个再聊聊，这件事也不是孤例。&lt;/p&gt;
&lt;p&gt;差不多同一时间，9月底，Ruby on Rails的作者DHH，拿AI agent把他们公司的聊天应用Campfire整个用Rust重写了一遍，跑分比原来的Rails版本快了几十倍。他对生成出来的代码有一句评价，特别经典。&lt;/p&gt;
&lt;p&gt;「The code really is hilariously hideous. But again, I don&apos;t intend to spend any time writing it or reading it. It&apos;s a prompt compilation target. So who cares.」&lt;/p&gt;
&lt;p&gt;代码丑得离谱，但我不打算写它，也不打算读它，它只是prompt的编译产物，谁在乎呢。&lt;/p&gt;
&lt;p&gt;一个写了二十多年Ruby、一辈子都在讲「程序员的幸福感」的人，说出who cares这两个词。&lt;/p&gt;
&lt;p&gt;我是真的觉得，这比Photoshop被复刻本身，更让人后背发凉一点。&lt;/p&gt;
&lt;p&gt;当然，也有人专门写文章反驳DHH那组跑分，说那组benchmark测的其实是agent在每种语言上下了多少功夫，而不是语言本身。这个我觉得也对，&lt;strong&gt;具体的数字可以吵，但方向很难吵。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;对于Vibe Coding，我觉得GPT写的代码确实比较丑陋，虽然能干活，Claude我十分想用，但...唉...都懂。&lt;/p&gt;
&lt;h2&gt;04 骂的人不少，而且很多骂得有道理&lt;/h2&gt;
&lt;p&gt;说真的，这次HN和X上的批评，我觉得必须认真摆一摆。&lt;/p&gt;
&lt;h3&gt;第一种，是「这玩意根本不能用」。&lt;/h3&gt;
&lt;p&gt;HN上有个搞摄影的朋友试了一下，说LightCraft的RAW处理，就像一个业余选手从第一性原理开始瞎摸，连最基本的色彩配置都没有，放在Lightroom旁边一比，「completely different and not in a good way」。还有人发现，有两个测试用例里，PSD存回去以后，导出的渲染就变了样。还有人照着README装Flatpak，结果README里提到的文件压根没打包进去。&lt;/p&gt;
&lt;p&gt;X上也有人冷静得很，说你不能指望一个AI聊天机器人，干完200多个性能工程师15年干的活。&lt;/p&gt;
&lt;p&gt;还有个开发者valigo，发了一条1700多赞的吐槽，说下载了一个，空闲占5个G内存，CPU 100%，打开一看，里面是Tauri。&lt;/p&gt;
&lt;p&gt;不过这事有个反转。ArtCraft官方回他，你下的是ArtCraft自己那个AI应用，那个确实是Tauri，我们也想换掉，但那7个Craft应用不是。底下一堆人笑他looks inside the wrong app。&lt;/p&gt;
&lt;p&gt;所以你看，&lt;strong&gt;捧的和踩的，都有人没搞清楚自己在说什么&lt;/strong&gt;。。。&lt;/p&gt;
&lt;h3&gt;第二种批评，我觉得更有分量，是「token不该这么花」。&lt;/h3&gt;
&lt;p&gt;开发者Santanu Sinha发了一条，大意是，我很困惑，为什么大家要烧几十亿token去复刻Adobe，而不是把力气花在GIMP、Darktable、Krita这些优秀的开源项目上？那些项目，人家已经花了那么多年。这感觉就是巨大的浪费。&lt;/p&gt;
&lt;p&gt;1800多赞，465条回复。&lt;/p&gt;
&lt;p&gt;我非常理解这种感觉。你想想看，你是一个给Krita默默提交了好几年代码的志愿者，你一点一点磨出来的东西，突然被一个「AI一周复刻Photoshop」的热搜盖过去了。而作者本人在HN上说的是，他受够了GIMP、Krita、Inkscape就是开源世界能拿出来的最好的东西。&lt;/p&gt;
&lt;p&gt;换我，我也会有点不是滋味。&lt;/p&gt;
&lt;h3&gt;第三种，是能活多久。&lt;/h3&gt;
&lt;p&gt;有人直接预言，这种AI项目要的就是上头条，目的已经达到了，一个月内就会被扔掉。HN上也有人追问，既然人人都能vibe code一个自己的Adobe，那谁还会来维护别人的？就在同一个帖子底下，已经有好几个人贴出了自己用AI做的Photoshop平替，其中一个做了六个月的开发者说，他觉得现在这种项目大概有十几个了。&lt;/p&gt;
&lt;h3&gt;第四种，是法律和伦理。&lt;/h3&gt;
&lt;p&gt;项目自称clean-room，就是只看公开规范和软件运行时的外部表现，不碰Adobe一行代码。VectorCraft甚至写明了规矩，Illustrator安装包里的东西，除了名字和目录，不许读，不许反汇编，不许抄。但HN上有人怼得很直接，「There is no such thing as clean-room vibe coding」，模型本身就是吃着全世界的开源代码长大的，你怎么证明它是干净的？Ars Technica的报道也提了一句，功能层面的逆向一般被认为是合法的，但界面做得太像，可能会踩到trade dress，也就是商业外观的线。&lt;/p&gt;
&lt;p&gt;至于Raymond那句「肯定是先反编译了Photoshop」，那是他的猜测，到目前为止我没看到任何证据。&lt;/p&gt;
&lt;p&gt;截至我能查到的10月8日，Adobe官方没有公开回应，也没有律师函或者诉讼的报道。&lt;/p&gt;
&lt;p&gt;最后还有一条评论，我觉得特别值得记住。HN上有人说，你去读一下这个项目的git log就明白了，「This can only be done with careful guidance from experienced developers. It doesn&apos;t work at all for a vibe coder.」只有在有经验的开发者手把手引导下才做得出来，纯vibe coder根本搞不定。&lt;/p&gt;
&lt;p&gt;Brandon Thomas自称有15年从业经验，其中大约10年在写Rust。&lt;/p&gt;
&lt;p&gt;这个细节，跟那张算力账单放在一起看，就很有意思了。&lt;strong&gt;账单上写的是agent小时，但账单的抬头，是一个干了15年的老工程师。&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;05 复制成本塌了，Adobe还剩几条护城河&lt;/h2&gt;
&lt;p&gt;回到那张账单这块。&lt;/p&gt;
&lt;p&gt;我一直觉得，看这件事最容易犯的错，就是盯着那个百分比。25%也好，50%也好，87%也好，FilmCraft自己都在roadmap里承认，那些百分比有一部分是干活的agent自己报上来的，「nothing stops a number drifting upward」，没有任何机制拦着这个数字往上飘。&lt;/p&gt;
&lt;p&gt;AI给自己打分，你敢全信？？？&lt;/p&gt;
&lt;p&gt;所以百分比没那么重要，我也不信两三天就能追平Premiere。&lt;/p&gt;
&lt;p&gt;真正重要的是，估算这件事本身变了。剩下的活，不再用「我们得再招一个十人团队干一年」来衡量，而是用「再烧多少个agent小时」来衡量。&lt;strong&gt;前者是融资问题，后者，是信用卡问题。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;当一个软件的复制成本，从人年掉到了算力账单，那些靠「这东西太难做了，没人愿意重做一遍」活着的公司，就得重新回答一个问题。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;你的护城河，到底是什么？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;那就拿Adobe当样本，一层一层往下扒，看看它还剩什么。&lt;/p&gt;
&lt;p&gt;最表面的一层，是软件功能本身。&lt;/p&gt;
&lt;p&gt;这一层正在被侵蚀，这是事实。哪怕PhotoCraft现在只有25%到35%的专业可用度，它的菜单接线率，按他们roadmap里的记录，是在10月1日一天之内从35.8%干到85.1%的。功能表面的复制，已经不贵了。&lt;/p&gt;
&lt;p&gt;再往下一层，是文件格式。PSD这些格式，是Adobe几十年攒下来的城墙。但PhotoCraft的PSD支持，是照Adobe公开的规范写的，在psd-tools的309个测试文件里，307个打开再保存，渲染没变。这堵墙，也开始漏风了。&lt;/p&gt;
&lt;p&gt;再往下，就开始硬了。&lt;/p&gt;
&lt;p&gt;插件生态。插件兼容是PhotoCraft自己列出的最大缺口之一。一个设计师的工作流里，往往挂着一串第三方插件，这些东西不是agent小时能复刻的，因为它们压根就不是Adobe写的。&lt;/p&gt;
&lt;p&gt;AI能力。FilmCraft的roadmap里有一句特别坦诚的话，Premiere里的Generative Extend，「Not reachable clean-room and locally」，用clean-room的办法加本地运行，做不到，因为它需要一个很大的视频生成模型。这其实就是Firefly那一层，要模型，要数据，要算力，你在本地用Rust是重写不出来的。&lt;/p&gt;
&lt;p&gt;还有云、素材库、团队协作、企业采购合同、内容凭证。一家公司几百个设计师共用的品牌素材库和审批流，不是一个开源App能接得住的。&lt;/p&gt;
&lt;p&gt;最后，是习惯。说来讽刺，PhotoCraft官网给自己的定位，叫「The image editor you already know how to use」，你本来就会用的图像编辑器。快捷键照着Photoshop摆，面板照着Photoshop摆。它在借的，恰恰是Adobe花了几十年给全世界设计师养出来的肌肉记忆。&lt;/p&gt;
&lt;p&gt;这说明习惯是护城河。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;但也说明，这条护城河，谁都能借。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;再看看Adobe自己的账本，这个反差特别有意思。&lt;/p&gt;
&lt;p&gt;9月10日，美国时间，Adobe发了Q3财报。营收67.6亿美元，同比涨13%，创纪录。年度经常性收入275亿美元，他们口中的AI-first ARR同比涨了150%以上，创意和办公两条线的月活加起来过了10亿。&lt;/p&gt;
&lt;p&gt;怎么看，都不像一家快要被干掉的公司。&lt;/p&gt;
&lt;p&gt;但另一边，股价在过去一个月里跌了16.4%（截至10月6日，Trefis的统计）。合同积压，也就是RPO，只涨了8%，管理层的解释是在主推免费增值、拉新用户，暂时没去动价格。9月初，Adobe还宣布了CEO交接，Shantanu Narayen在12月1日退下来做执行董事长，Anil Chakravarthy接任。&lt;/p&gt;
&lt;p&gt;再往前，今年4月，Adobe跟美国司法部的那个官司正式落地，和解金1.5亿美元，7500万罚款，7500万作为给用户的免费服务。案子的核心，就是隐藏高额提前退订费、让人很难取消订阅。&lt;/p&gt;
&lt;p&gt;而Brandon Thomas在HN上说，他做这一整套东西的起因，就是被那种叫cancellation fee的dark pattern坑了太多次。&lt;/p&gt;
&lt;p&gt;你看，这就串起来了。&lt;/p&gt;
&lt;p&gt;财报说明，Adobe今天的生意依然很好。股价说明，市场已经开始提前给某种东西定价。而那1.5亿的和解说明，Adobe这些年攒下来的，除了用户，还有很多怨气。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;怨气，现在有了一个非常便宜的出口。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;一个老工程师，加几个Opus 5.5 agent，加一张信用卡。&lt;/p&gt;
&lt;h2&gt;06 以后用Photoshop的，可能一半不是人&lt;/h2&gt;
&lt;p&gt;聊到这儿，我反而想到另一件事，就是MCP。&lt;/p&gt;
&lt;p&gt;这7个Craft应用，有一个设计，我觉得被热搜严重低估了。PhotoCraft里，每一个菜单项、每一个工具、每一个对话框，背后都是同一套命令注册表里的一条命令，一共500多条。界面点的是它，命令行调的是它，JSON控制通道调的是它，MCP服务器调的也是它。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;你能点的，Claude也能点。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;HN上有个用户分享了一件小事。他有两张在同一个地方拍的照片，一张里有3个人，一张里有1个人，想合成一张。一个月前，他用ChatGPT的生图试了好几次，每次都会把人脸改掉。这次他让Claude连上PhotoCraft的MCP，5分钟试了3次，搞定了。&lt;/p&gt;
&lt;p&gt;这个小故事，我觉得比「复刻了Photoshop」更值得琢磨。&lt;/p&gt;
&lt;p&gt;Adobe卖了三十多年的东西，核心是一套给人用的界面。而这批AI时代长出来的软件，从出生那天起就默认，它的用户里，可能有一半不是人。&lt;/p&gt;
&lt;p&gt;如果以后修图、剪片、排版，越来越多是agent在调命令，那界面做得像不像Photoshop，可能就没那么重要了。重要的是，谁的接口更开放，谁更方便被agent驱动。&lt;/p&gt;
&lt;p&gt;Adobe当然也会做这件事。HN上有个自称Adobe员工的人，就回了一句，「We have access to LLMs and tokens as well.」我们也有大模型，也有token。&lt;/p&gt;
&lt;p&gt;这话没毛病。&lt;/p&gt;
&lt;p&gt;但底下马上有人回他，你们还有五百层的组织架构，几十年的遗留代码，几十个微服务，对二十年前文件格式的向后兼容，还有一群你一改工作流就炸毛的老用户。&lt;/p&gt;
&lt;p&gt;这才是大象的难处。不是它不会跳舞，是它身上挂的东西太多了。&lt;/p&gt;
&lt;h2&gt;07 Software is over？我不同意&lt;/h2&gt;
&lt;p&gt;最后，说回Brandon Thomas那句Software is over。&lt;/p&gt;
&lt;p&gt;我不同意。&lt;/p&gt;
&lt;p&gt;至少从PhotoCraft自己那份诚实到有点狼狈的roadmap来看，软件远没有结束。把一个东西做到「看起来像」，变便宜了。但要做到「专业的人愿意把饭碗交给它」，依然很贵，贵在测试，贵在边缘情况，贵在真实用户的反馈，贵在那个凌晨还在收拾合并冲突的人类集成者。&lt;/p&gt;
&lt;p&gt;但我也不觉得，这只是一场炒作。&lt;/p&gt;
&lt;p&gt;因为真正变化的，从来不是那个百分比，而是写在百分比旁边的那个单位。&lt;/p&gt;
&lt;p&gt;以前，复刻一个Photoshop，是一件没人会认真去估算的事，它是一个神话。&lt;/p&gt;
&lt;p&gt;现在，它是一张可以被估算、被拆分、被并行的账单。账单可能估错，可能超支，可能烧完了也做不出来。&lt;/p&gt;
&lt;p&gt;但它是一张账单。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;神话没法讨价还价，账单可以。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;天没塌。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;塌的，是造软件的成本。&lt;/strong&gt;&lt;/p&gt;
</content:encoded><category>AI</category><category>Adobe</category><category>开源</category><category>Rust</category></item><item><title>MyGo：一个把网页和原生界面放进同一个 Go 程序的桌面框架</title><link>https://blog.990915.xyz/posts/mygo%E4%B8%80%E4%B8%AA%E6%8A%8A%E7%BD%91%E9%A1%B5%E5%92%8C%E5%8E%9F%E7%94%9F%E7%95%8C%E9%9D%A2%E6%94%BE%E8%BF%9B%E5%90%8C%E4%B8%80%E4%B8%AAgo%E7%A8%8B%E5%BA%8F%E7%9A%84%E6%A1%8C%E9%9D%A2%E6%A1%86%E6%9E%B6/</link><guid isPermaLink="true">https://blog.990915.xyz/posts/mygo%E4%B8%80%E4%B8%AA%E6%8A%8A%E7%BD%91%E9%A1%B5%E5%92%8C%E5%8E%9F%E7%94%9F%E7%95%8C%E9%9D%A2%E6%94%BE%E8%BF%9B%E5%90%8C%E4%B8%80%E4%B8%AAgo%E7%A8%8B%E5%BA%8F%E7%9A%84%E6%A1%8C%E9%9D%A2%E6%A1%86%E6%9E%B6/</guid><description>EGOIST 发布的纯 Go 桌面框架：窗口可以用系统 webview，也可以由框架自己在 GPU 上画原生界面，hello world 约 7 MB。本文讲清两条内容路径、分层与线程模型、不用 Cgo 的取舍，以及现在能不能用。</description><pubDate>Wed, 07 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://img.990915.xyz/2026/10/06/1791281332403-90570032-3ec2-436e-8da0-c24320ec0fa3.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;图 1 同一个程序里，左半边可以是网页，右半边可以是框架自己画出来的界面。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;10 月 3 日，做 tsup 和 ChatWise 的 EGOIST 在 X 上丢出一句话：MyGo 是一个纯 Go 的桌面框架，窗口可以用系统 webview，也可以用它自己画的原生界面，&quot;像 GPUI 和 Tauri 生了个孩子，但用 Go 写，所以编译快&quot;。&lt;/p&gt;
&lt;p&gt;仓库公开两天，星标冲过 500，协议是 MIT，版本停在 0.2.7。它还很新。值得写，不是因为它已经能替换谁，而是它把近十年桌面应用的几条路线，收成了一个人自己用得动的形状。&lt;/p&gt;
&lt;h2&gt;先看它要解决什么&lt;/h2&gt;
&lt;p&gt;Electron 把整份 Chromium 捆进安装包。能做的事最多，体积和内存也最重。Tauri 把浏览器换成系统自带的 webview，后端改用 Rust，安装包掉到几兆到十几兆。Wails 走同一条路，后端换成 Go，Go 团队不用再学一套所有权系统。&lt;/p&gt;
&lt;p&gt;EGOIST 三条都走过。2023 年他发过一张图：同一个应用，Tauri 和 Electron 各写了一遍。今年 9 月他还说，宁可 Rust，也不要 Electron。问题出在下一段：Tauri 和 GPUI 的界面能力他认，Rust 的编译时间和磁盘占用把他自己的节奏拖慢了。发布当天他补了一句，从 Rust 换到 Go 之后，可以随便开 git worktree。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://img.990915.xyz/2026/10/06/1791281412105-f73ff5c2-d3d6-4064-aaf8-f8488af6853b.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;图 2 从左到右：捆浏览器的重窗口、Rust 后端的瘦窗口、Go 加 webview、以及把网页和自绘界面拆开的第四种。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&quot;Rust 编译慢，还占很多磁盘。我用 Tauri 和 GPUI 做过很多应用。Go 的内存效率确实不如 Rust，但在桌面应用上，这个差别没那么大。&quot;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;所以 MyGo 不是为了填一个&quot;Go 版 Tauri&quot;的生态空位。顺序是反过来的：人先在做 ChatWise、kero、waku、lorca 这些桌面产品，工具跟不上，才把工具抽成框架。他在 9 月先放了一个叫 QuickGUI 的 GPU 界面实验，有人问差异点，他的回答最接近动机：组件、打包、自动更新可以做成一整套，但唯一的原因是想用 Go 或 TypeScript 快速迭代。发布 MyGo 时他把两者切开：QuickGUI 是实验，MyGo 是拿去生产的。lorca 的 Windows 和 Linux 端已经在用它的 webview，并准备迁到原生界面。&lt;/p&gt;
&lt;h2&gt;一个窗口，两条内容路径&lt;/h2&gt;
&lt;p&gt;MyGo 的窗口壳是共用的：标题、菜单、托盘、对话框、通知、全局快捷键、深链、文件关联。壳里面的内容二选一，同一个应用可以混用。&lt;/p&gt;
&lt;p&gt;第一条是网页。它不打包浏览器，用操作系统已经有的 webview：macOS 的 WKWebView，Linux 的 WebKitGTK，Windows 的 WebView2。前端仍是 HTML、CSS 和 JavaScript，模板默认 Vite 加 TypeScript。页面调用 Go，走的是框架从 Go 代码生成的客户端，类型和注释一起带过去。&lt;/p&gt;
&lt;p&gt;第二条没有网页。界面用 Go 写，框架自己在 GPU 上画，不启动 webview 进程。作者的说法是，工具、设置页、小实用程序往往不需要一个浏览器引擎。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://img.990915.xyz/2026/10/06/1791281516420-fcddba24-0081-4462-9717-4cd7f35758ff.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;图 3 上路是网页经消息调用 Go；下路是界面在 Go 里建好，交给 GPU 画出来。窗口壳只有一个。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;官方给出的量级：hello world 大约 7 MB；带 webview 的进程起来，macOS 上大约 62 MB；原生界面窗口空闲大约 44 MB；空闲 CPU 为 0。这些是作者自己的测量，不是第三方基准，读的时候留一点余地。但方向是清楚的：不轮询，工作由原生事件或显式唤醒驱动。&lt;/p&gt;
&lt;h2&gt;架构上，它在防什么&lt;/h2&gt;
&lt;p&gt;仓库大约 93% 是 Go。公开 API 在根包，平台差异被压进一份很小的契约。文档写明，改内部实现之前先读架构说明。这不是礼貌，是因为分层是硬的。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://img.990915.xyz/2026/10/06/1791281466609-73c3a45d-86fc-4cfc-b249-51d466a0e9fa.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;图 4 上是你的程序，中是框架自己的策略层，下是 macOS、Linux、Windows 三份只做翻译的后端。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;根包做策略：选项默认值、窗口表、退出顺序、调用路由、菜单、自定义协议、信任判断。它不直接碰 AppKit、GTK 或 Win32。中间那层契约只提供事件循环、建窗口、菜单、对话框和剪贴板，事件再回调回来。三个后端只做翻译。另有一个内存后端，用来在没有图形界面的环境里测核心逻辑。不支持的系统在启动时给出明确错误，而不是悄悄半残。&lt;/p&gt;
&lt;p&gt;这条分层换来两件具体的事。第一，新增一个桌面能力有固定清单：先设计可以从任意 goroutine 调用的 API，再给契约加最小机制，然后五个后端都要实现，包括测试用的假后端。第二，原生界面那套绘制代码不反向依赖根包。不用它的应用，不会把 GPU 渲染链进去。&lt;/p&gt;
&lt;p&gt;线程模型也写死了。Cocoa 和 GTK 必须由进程启动的那个线程驱动，所以主 goroutine 被锁在主线程上，事件循环从这里进去。对外的方法仍可以从别的 goroutine 调，框架负责把工作投回主线程；如果调用方已经在主线程上等待结果，它会抽原生事件，避免自己把自己卡住。绑定的 Go 方法在单独的 goroutine 里跑，允许阻塞。窗口关闭这种事件则在主线程同步执行，所以监听者可以取消关闭。&lt;/p&gt;
&lt;h2&gt;不用 Cgo，是取舍不是口号&lt;/h2&gt;
&lt;p&gt;整个项目要求关掉 cgo。任意一台机器可以交叉编译出其他平台的程序，不需要先装一套 C 工具链。macOS 和 Linux 在运行时打开系统库，Windows 走系统调用。回调按函数签名在启动时建一次，用窗口编号区分目标，不为每个窗口单独建。Metal 着色器提前编译进库，避开启动时那一百多毫秒。&lt;/p&gt;
&lt;p&gt;换来的限制同样具体。macOS 的签名和磁盘映像仍然只能在 Mac 上做。Linux 的全局快捷键在 X11 和 Wayland 上不是同一条路。托盘在 Linux 上只有菜单。半透明材质在 Linux 上被忽略。框架把这些差异写进表里，而不是假装三个系统长一样。&lt;/p&gt;
&lt;h2&gt;网页怎么安全地叫到 Go&lt;/h2&gt;
&lt;p&gt;网页侧的调用不是约定，是运行时强制的。你把一个 Go 值绑进去，导出方法就能被页面调用。方法可以带上下文，页面关掉或导航走，这次调用就取消。返回值最多一个结果加一个错误。需要连续吐数据时，用通道，大约每半兆字节要一次确认，避免页面被冲垮。&lt;/p&gt;
&lt;p&gt;线上是带密钥的 JSON。每个窗口有一把启动时生成的随机密钥，没有密钥的消息直接丢掉。来源还必须是应用自己的页面、自定义协议、本地文件，或开发时的本机服务器；导航之后重新计算。不可信的调用不会执行 Go。macOS 上还要求消息来自主框架，挡住 iframe。&lt;/p&gt;
&lt;p&gt;类型客户端由反射和源码一起生成。嵌入的结构体会被展平，可选字段保持可选，字节切片变成 base64。参数名和注释从 Go 源文件里抽出来，所以编辑器里能看到你写在方法上的说明。开发时 Go 一改，客户端就重写。&lt;/p&gt;
&lt;h2&gt;原生界面不是套了一层控件&lt;/h2&gt;
&lt;p&gt;原生界面是即时模式：每一帧都是状态的函数，焦点、滚动、编辑和动画按位置或显式的键留在元素上。布局有弹性盒和网格。组件覆盖按钮、表单、列表、表格、树、菜单、富文本和路由，输入法有单独的替换区间。&lt;/p&gt;
&lt;p&gt;绘制不经过浏览器。界面先变成一幅场景，再交给 Metal、Direct3D 11 或 OpenGL。没有硬件，或者 GPU 路径失败，就在同一帧换成 CPU 绘制。这套 CPU 路径也是测试用的对照图。文本走系统排版：macOS 的 Core Text，Windows 的 DirectWrite，Linux 的 Pango。无障碍同样是每帧一棵树，后端为每个节点维持系统原生的辅助对象，读屏的操作走和键鼠同一套动作。&lt;/p&gt;
&lt;p&gt;这是它和 Wails 真正分开的地方。有人在发布帖下说这不就是 Wails，作者回了两个词：更好的开发体验，加上原生界面。webview 在他这里是选项，不是身份。&lt;/p&gt;
&lt;h2&gt;现在能不能用&lt;/h2&gt;
&lt;p&gt;能用来做自己的小工具，不适合当成已经稳定三年的 ABI。原生界面是 10 月 2 日才合进主干的，版本仍是 0.2。发布后两天，作者用它在 20 分钟里做了一个差异查看器，又测了一次全新构建加 Windows 安装包，21 秒。这证明的是他自己的迭代速度，不是社区已经补齐了边角。&lt;/p&gt;
&lt;p&gt;适合现在试的人很具体：已经在写 Go，不想为了一个桌面壳引入 Rust，又希望设置页和工具窗不必付浏览器进程的钱。不适合的也同样具体：需要和 Chromium 完全一致的网页能力，或者需要一份一年内不会动的插件接口。Linux 上的网页窗口仍受系统 WebKitGTK 版本拖累，这是所有系统 webview 方案的共同账单。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;开发需要 Go 1.27 或更新。网页项目还要 Bun，原生界面项目只要 Go。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;macOS 12 及以上没有额外运行时。Windows 的网页窗口需要 WebView2，Windows 11 已自带。Linux 需要 GTK 3，网页窗口还要 WebKitGTK。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;打包覆盖 macOS 应用和磁盘映像、Windows 安装包、Linux 可执行文件、桌面项和 deb，并带签名更新和增量包。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;它真正留下的问题&lt;/h2&gt;
&lt;p&gt;桌面应用这十年的主线，是用网页换开发速度，再用系统 webview 把体积还回去。MyGo 承认这笔交易，但拒绝让它成为唯一交易。需要网页的窗口继续用网页；不需要的窗口，回到 Go 里自己画。编译速度被放在内存极限前面，交叉编译被放在调用系统 API 方便前面。&lt;/p&gt;
&lt;p&gt;这是一个作者为了自己的产品抽出来的框架，不是一个委员会设计的平台。它的好处和风险是同一件事：迭代会很快，接口也会动。如果它能活过接下来几个月，值得看的不是星标，而是那条原生界面能不能在三个系统上都保持&quot;打开即用、空闲不转&quot;。在那之前，把它当成一条新路线的样品，比当成下一个默认选项更准确。&lt;/p&gt;
</content:encoded><category>折腾</category><category>Go</category><category>桌面开发</category><category>框架</category><category>开源</category></item><item><title>Pi 已经够小了，为什么还要再做一个会自己活下去的 Agent？</title><link>https://blog.990915.xyz/posts/%E4%B8%BA%E5%95%A5%E6%9C%89pi-durable/</link><guid isPermaLink="true">https://blog.990915.xyz/posts/%E4%B8%BA%E5%95%A5%E6%9C%89pi-durable/</guid><description>Pi 1.0 发布的同时，Earendil 还放出了实验性的 Pi Durable。它不是 Pi 的升级版，而是把存储、并行对话和执行环境拆出去的运行时。本文说清两者区别、它解决哪一种「死法」，以及现在谁该看。</description><pubDate>Mon, 05 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;10 月 1 日，Earendil 同时交出 Pi 1.0 和实验性的 Pi Durable。最容易产生的误会是，Durable 是 Pi 的升级版。不是。一个继续待在终端里，一个是故意拆出去的运行时。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://img.990915.xyz/2026/10/04/1791132673540-e36c1a87-4248-45f4-be77-2e66153e4ad7.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;先把两个东西拆开&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Pi 跑在你的机器上，终端里一个人驱动。进程死了，你看一眼，再让它继续。Pi Durable 不是这个程序。它是 npm 包，大约一万五千行 TypeScript，负责存储、并行对话、工具和执行环境。API 还在变。天天在终端里写代码的人，可以当它不存在。&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;为什么不能直接把 Pi 改大&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;终端形态的边界很具体：一台机器，一个人，断了可以人肉续上。一旦要进 Slack 和网页、对话长到人不盯着、容器会重启、多个人同时插手，缺的就不是新工具，而是每一步先落盘。硬塞进 Pi，日常那个极简客户端会被拖重。所以不合并。&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Durable 在解决哪一种死法&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;部署机器人查完日志，准备发布，容器被杀掉。普通 Agent 留下半段输出，再跑可能发两次。Durable 把模型请求和工具调用都做成任务，往前走之前先写检查点。新进程打开同一份存储接着跑。只读工具可以重放，部署这种不能重放的，不自动再执行，而是告诉模型上次被打断了。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://img.990915.xyz/2026/10/04/1791132760254-c1017cd6-5626-4285-9147-9833cbe9fef4.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;对话也可以从任意一句分叉。子对话看得到父历史，但不复制。频道继续跑，线程从那一句出去，两场互不堵住。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://img.990915.xyz/2026/10/04/1791132774128-58cbd7e6-71cc-442b-8ec6-9fcf44585fb3.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Cloudflare 已经把它接进 Agents SDK。有人用它替换自己补了两天的恢复逻辑，也有人把它理解成不用再为 harness 开一台虚拟机。&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;它和 DeepSeek Harness 像，但不是同一个赌&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;DSH 是能直接跑的运行时，连循环都是插件，装上就有界面。Pi Durable 没有日常界面。它押的是看得见的进度必须先落盘。X上热门对比帖比的多半是 Pi 编码 Agent 和 DSH 谁更会写代码，关于 Durable的对比讨论比较少。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://img.990915.xyz/2026/10/04/1791132796130-37018d73-801e-4418-9bba-2a78baa5e0dc.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;这和 Agent 自己变强有什么关系&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;自我改进死得最多的地方，常常不是插件不够多，而是试验跑到一半现场没了。检查点和分叉给的是一条能续的时间线。它不会因此变成通用智能，只是让一个已经够用的模型更不容易把工作做丢。&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;谁现在该看&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;还在终端里写代码的，继续用 Pi。要做夜间任务、机器人、多人同时看一场执行的，再打开 Durable，并把它当成会变的实验底座。值得留下的是那条规则：没有落盘的进度，就不算发生过。&lt;/p&gt;
</content:encoded><category>AI</category><category>Pi</category><category>AI Agent</category><category>开源</category></item><item><title>AI 什么都会，那读博到底在学什么？</title><link>https://blog.990915.xyz/posts/ai%E4%BB%80%E4%B9%88%E9%83%BD%E4%BC%9A%E9%82%A3%E8%AF%BB%E5%8D%9A%E5%88%B0%E5%BA%95%E5%9C%A8%E5%AD%A6%E4%BB%80%E4%B9%88/</link><guid isPermaLink="true">https://blog.990915.xyz/posts/ai%E4%BB%80%E4%B9%88%E9%83%BD%E4%BC%9A%E9%82%A3%E8%AF%BB%E5%8D%9A%E5%88%B0%E5%BA%95%E5%9C%A8%E5%AD%A6%E4%BB%80%E4%B9%88/</guid><description>当 AI 能写代码、读文献、给答案，读博真正训练的不是&quot;知道很多&quot;，而是&quot;会判断&quot;。</description><pubDate>Sun, 04 Oct 2026 14:52:00 GMT</pubDate><content:encoded>&lt;p&gt;最近我经常有一种割裂感。&lt;/p&gt;
&lt;p&gt;抽空写写代码，想法发给 AI，等着就行；&lt;/p&gt;
&lt;p&gt;读文献，丢给 AI 一个 PDF，几秒钟就能得到摘要、方法和结论；&lt;/p&gt;
&lt;p&gt;讨论研究想法，刚开始自己还有自我意识，聊着聊着就丢失自我了；&lt;/p&gt;
&lt;p&gt;效率高得吓人，爽也是真的爽，爽了过后却是无尽的空虚。&lt;/p&gt;
&lt;p&gt;如果未来 AI 什么都能写，那我这几年的训练，到底在训练什么？&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://img.990915.xyz/2026/10/04/1791088756021-f0f80907-5cad-4a7c-89fb-fb1f32d88b8d.jpg&quot; alt=&quot;AI 与读博的思考&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;一、AI 给了我答案，却没给我判断力&lt;/h2&gt;
&lt;p&gt;我是一个 vibe code 爱好者，早期也粗浅学过编程，但一直没有项目实战经验，现在 AI 出来，倒是补全了这一块。&lt;/p&gt;
&lt;p&gt;遇到一个没写过的功能，先让 AI 生成一版；遇到一个不熟的库，先让 AI 给个示例；遇到一个报错，先让 AI 解释一遍。大多数时候，它都能给出看起来非常正确的答案。&lt;/p&gt;
&lt;p&gt;问题也恰恰在这里。&lt;/p&gt;
&lt;p&gt;它给得太快了，快到我还没来得及困惑，答案就已经摆在面前。代码跑通了，功能实现了，但我心里清楚：我并没有真正理解为什么这样写。如果明天需求变了，如果性能出了问题，如果这段代码需要重构，我可能根本不知道从哪里下手。&lt;/p&gt;
&lt;p&gt;AI 能告诉你这段代码能不能跑，但它不会告诉你：这个 socket 应该由谁创建？线程之间应该用共享状态还是消息传递？这个抽象是不是过度设计？这个类型到底该不该放在 &lt;code&gt;Arc&lt;/code&gt; 后面？&lt;/p&gt;
&lt;p&gt;这些不是语法问题，是设计问题。&lt;/p&gt;
&lt;p&gt;语法问题，编译器会冲你大喊。设计问题，编译器一声不吭。&lt;/p&gt;
&lt;p&gt;而设计判断力，恰恰是 AI 最不容易替你长出来的东西。&lt;/p&gt;
&lt;h2&gt;二、读博最痛苦的部分，恰恰是最不能外包的部分&lt;/h2&gt;
&lt;p&gt;写论文也是一样。&lt;/p&gt;
&lt;p&gt;AI 可以在几分钟内总结一百篇文献，但你不等于理解了那一百篇文献。AI 可以帮你生成一段漂亮的讨论，但你不等于真正想清楚了那个论证。&lt;/p&gt;
&lt;p&gt;真正让我成长的，从来不是那些顺利的时刻。&lt;/p&gt;
&lt;p&gt;是花三个小时读一篇看不懂的论文，反复查术语、画框架图，最后终于隐约摸到作者的问题意识；是写了五千字，突然发现整个论证链条是断的，只能推倒重来；是组会上提出一个自以为漂亮的观点，被导师连续追问五次，最后只能承认&quot;我不知道&quot;；是发现自己信了很多年的东西可能根本站不住脚，只能重新找证据、改观点。&lt;/p&gt;
&lt;p&gt;这些事情效率都极低。&lt;/p&gt;
&lt;p&gt;但正是在这些低效、痛苦、反复推翻自己的过程中，我的理解力、表达力、逻辑能力和判断力，才一点点长出来。&lt;/p&gt;
&lt;p&gt;AI 可以制造出&quot;学习已经发生&quot;的外观，却绕过了真正发生学习的过程。&lt;/p&gt;
&lt;p&gt;一篇论文可以看起来很完整，但如果论证不是你自己搭的，你就没有真正学会论证。一段代码可以跑得很完美，但如果设计不是你自己想的，你就没有真正学会设计。&lt;/p&gt;
&lt;h2&gt;三、如果大学只是知识仓库，那它早就输了&lt;/h2&gt;
&lt;p&gt;我有时候会想，如果读博只是为了获取知识，那这件事在今天已经越来越不划算了。&lt;/p&gt;
&lt;p&gt;互联网早就把知识变得触手可及，AI 正在把知识的获取成本压到接近于零。一个本科生，一部手机，就能随时拥有一个耐心无限、随叫随到的私人教师。&lt;/p&gt;
&lt;p&gt;那大学还剩下什么？读博还剩下什么？&lt;/p&gt;
&lt;p&gt;如果大学只是知识仓库，互联网已经削弱了它。如果大学只是论文工厂，AI 正在冲击它。如果大学只是职业培训机构，在线教育、企业培训和新的认证体系，迟早会分走它的功能。&lt;/p&gt;
&lt;p&gt;但反过来想，如果大学是一个社会专门保留下来的地方，让年轻人在进入一个越来越快、越来越功利、越来越碎片化的世界之前，有几年时间认真阅读、写作、质疑、争论、失败、修正自己，&lt;strong&gt;认识完全不同的人（非常重要，最重要没有之一）&lt;/strong&gt;，并最终形成独立判断——那么 AI 越强大，这种地方反而越重要。&lt;/p&gt;
&lt;p&gt;读博也是一样。&lt;/p&gt;
&lt;p&gt;它真正应该训练的，不是&quot;知道很多&quot;，而是&quot;会判断&quot;。知道很多，不等于会判断；会考试，不等于会判断；会熟练使用 AI，更不等于会判断。&lt;/p&gt;
&lt;p&gt;甚至恰恰相反。当获得答案越来越容易，判断答案的能力反而越来越珍贵。&lt;/p&gt;
&lt;h2&gt;四、AI 应该当导师，而不是代笔者&lt;/h2&gt;
&lt;p&gt;我并不是反对 AI。恰恰相反，我觉得它是我这几年最重要的工具之一。我写论文，写基金，写项目，都依赖这个天才程序员。&lt;/p&gt;
&lt;p&gt;但我越来越警惕一种用法：让 AI 替我做那些我本该自己做的决定。&lt;/p&gt;
&lt;p&gt;写代码时，如果 AI 直接生成了架构，我就失去了思考架构的机会。写论文时，如果 AI 直接生成了论证，我就失去了搭建论证的机会，甚至到看不懂的情况，直接失去论证资格。做研究时，如果 AI 直接给出了结论，我就失去了判断结论是否可靠的机会。&lt;/p&gt;
&lt;p&gt;这些决定，才是真正塑造我的东西。&lt;/p&gt;
&lt;p&gt;所以我慢慢调整了用法：先自己来。&lt;/p&gt;
&lt;p&gt;先自己想一个方案，先自己写一版，先自己搭一个论证。哪怕很粗糙，哪怕很幼稚，哪怕最后被推翻。然后，再让 AI 来挑战它。&lt;/p&gt;
&lt;p&gt;问它：这个设计可能哪里出问题？这个论证有没有漏洞？这个所有权模型合理吗？如果是一个有经验的开发者，他会怎么做？如果是一个严格的审稿人，他会怎么质疑？&lt;/p&gt;
&lt;p&gt;让 AI 当导师，而不是代笔者。&lt;/p&gt;
&lt;p&gt;让它帮我学得更快、更有效，但始终由我来做那些我正试图学会做的决定。&lt;/p&gt;
&lt;h2&gt;五、去真实世界里，让问题来找你&lt;/h2&gt;
&lt;p&gt;我还发现一件事：练习题是有边界的，真实世界没有。&lt;/p&gt;
&lt;p&gt;以前我总想找更难的题、更高级的教程、更复杂的项目。后来才意识到，真正让我进步的，不是难度，而是真实。&lt;/p&gt;
&lt;p&gt;真实的项目会逼你面对那些没人能提前设计好的问题。你会遇到所有权问题、并发问题、抽象泄漏、接口设计、同步机制、错误处理、部署运维……这些问题不会出现在任何一本教材的习题里，因为它们是长出来的，不是编出来的。&lt;/p&gt;
&lt;p&gt;所以，如果你也在读博，也在写代码，也在用 AI，我的建议是：选一个你真正感兴趣的领域，用你的技术去探索它。&lt;/p&gt;
&lt;p&gt;去学网络，去学嵌入式，去学并发，去学机器人，去做一个你一直想做但觉得太难的东西。不要只做那些有标准答案的练习。去真实世界里，让问题来找你。&lt;/p&gt;
&lt;p&gt;你会被卡住，会写出丑陋的代码，会推翻自己的设计，会发现自己什么都不懂。但你也正是在这些时刻，长出真正属于你的判断力。&lt;/p&gt;
&lt;h2&gt;六、AI 越强大，越要亲自经历判断的形成&lt;/h2&gt;
&lt;p&gt;未来最不缺的，就是答案。&lt;/p&gt;
&lt;p&gt;AI 可以几秒钟给你一个答案，几分钟给你一篇论文，几个小时给你一个项目。答案会越来越便宜，越来越丰富，越来越&quot;看起来正确&quot;。&lt;/p&gt;
&lt;p&gt;但真正越来越稀缺的是：当所有人都可以轻易得到一个答案时，你有没有能力判断哪个答案值得相信。&lt;/p&gt;
&lt;p&gt;读博也好，写代码也好，最终的目的都不是产出论文或代码。那些只是副产品。&lt;/p&gt;
&lt;p&gt;真正的产品，是你自己。&lt;/p&gt;
&lt;p&gt;是一个能够阅读复杂材料的人，一个能够独立思考的人，一个知道证据比立场重要的人，一个能够与不同意见相处的人，一个面对不确定性不会立刻寻找标准答案的人，一个在机器给出答案之后，仍然会追问&quot;为什么&quot;的人。&lt;/p&gt;
&lt;p&gt;AI 越强大，我们越需要保护那些低效的、缓慢的、痛苦的、不能外包的过程。&lt;/p&gt;
&lt;p&gt;因为正是那些过程，在塑造我们的判断力。&lt;/p&gt;
&lt;p&gt;而判断力，才是这个时代最贵的东西。&lt;/p&gt;
</content:encoded><category>科研</category><category>AI</category><category>读博</category><category>思考</category></item><item><title>Fingerprint Browser：我用 Rust 写了一个本地指纹浏览器管理器</title><link>https://blog.990915.xyz/posts/fingerprint-browser%E6%88%91%E7%94%A8-rust-%E5%86%99%E4%BA%86%E4%B8%80%E4%B8%AA%E6%9C%AC%E5%9C%B0%E6%8C%87%E7%BA%B9%E6%B5%8F%E8%A7%88%E5%99%A8%E7%AE%A1%E7%90%86%E5%99%A8/</link><guid isPermaLink="true">https://blog.990915.xyz/posts/fingerprint-browser%E6%88%91%E7%94%A8-rust-%E5%86%99%E4%BA%86%E4%B8%80%E4%B8%AA%E6%9C%AC%E5%9C%B0%E6%8C%87%E7%BA%B9%E6%B5%8F%E8%A7%88%E5%99%A8%E7%AE%A1%E7%90%86%E5%99%A8/</guid><description>一个用 Rust + GPUI 写的桌面指纹浏览器管理器：把每个档案编译成可复现的浏览器运行环境，基于现成的 fingerprint-chromium 与 Xray，不 fork 内核、不偷偷下载、也不让代理悄悄直连。</description><pubDate>Fri, 02 Oct 2026 12:30:00 GMT</pubDate><content:encoded>&lt;p&gt;今天想介绍一个我自己写的开源项目：&lt;strong&gt;Fingerprint Browser&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;仓库地址：&lt;a href=&quot;https://github.com/denislov/fingerprint-browser&quot;&gt;https://github.com/denislov/fingerprint-browser&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;简单说，它是一个跑在桌面上的&lt;strong&gt;指纹浏览器管理器&lt;/strong&gt;，用 Rust + &lt;a href=&quot;https://crates.io/crates/gpui-kit&quot;&gt;GPUI Kit&lt;/a&gt; 写的，围绕现成的 &lt;code&gt;fingerprint-chromium&lt;/code&gt;（指纹版 Chromium）和 &lt;code&gt;Xray&lt;/code&gt; 工作。目前最新版本 0.3.0，Windows 安装包、Linux 归档和 Debian 包都已经发在 Releases 里，MIT 协议。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://img.990915.xyz/2026/10/02/1790930933245-9767c2a9-00e9-4a81-95d9-c353046b1ec5.png&quot; alt=&quot;档案列表：每个档案有自己的指纹种子、数据目录、代理和独立进程&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;h2&gt;为什么要自己写一个&lt;/h2&gt;
&lt;p&gt;市面上的指纹浏览器不少，但用起来总有几件事让我别扭：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;是云服务。&lt;/strong&gt; 档案、Cookie、代理凭据都放在别人的服务器上，我要的是本地一个目录能装下全部东西。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;是黑盒。&lt;/strong&gt; 它宣称「指纹隔离」「代理生效」，但你没法验证——代理到底通没通，浏览器到底有没有真的走代理，页面看到的出口 IP 是哪一个，全靠信。&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;的版本。它不 fork Chromium，不去改内核，只做一件事：把「一份档案配置」编译成「一个稳定、可复现的浏览器运行环境」，然后可靠地管理它的生命周期。&lt;/p&gt;
&lt;h2&gt;它是什么，也不是什么&lt;/h2&gt;
&lt;p&gt;先说清楚边界，避免期待错位。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;它是：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一个桌面端的多档案管理器，每个档案有独立的 &lt;code&gt;user-data-dir&lt;/code&gt;、稳定的指纹种子和独立进程；&lt;/li&gt;
&lt;li&gt;一个代理编排器：每个走代理的档案配一个独立的 Xray 进程，支持 SOCKS5/HTTP 表单，也能导入 Shadowsocks、VMess、VLESS、Trojan 分享链接；&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;不是 Playwright / Puppeteer 那样的自动化平台；&lt;/li&gt;
&lt;li&gt;没有云同步、团队协作、账号权限；&lt;/li&gt;
&lt;li&gt;不做扩展市场，也不自己打 Chromium 补丁；&lt;/li&gt;
&lt;li&gt;不暴露远程 CDP，不把浏览器变成别人可以远程操控的入口。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;CDP 只监听回环地址，而且只用于「启动就绪、正常关闭、读回指纹」这几件本机的事。这一点是刻意的。&lt;/p&gt;
&lt;h2&gt;界面走一遍&lt;/h2&gt;
&lt;h3&gt;1. 档案：一个档案 = 一套独立环境&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://img.990915.xyz/2026/10/02/1790930996513-51d8fd12-b52a-4e9a-9a57-657166f18019.png&quot; alt=&quot;新建档案：种子、品牌、平台、语言、时区、窗口尺寸、WebRTC 策略都在这里定&quot; /&gt;&lt;/p&gt;
&lt;p&gt;每个档案都拥有自己的指纹种子、数据目录和浏览器进程。新建时你可以指定：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;种子（Seed）&lt;/strong&gt;：驱动这个档案声称的所有易变指纹项，一键换新；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;品牌 / 平台&lt;/strong&gt;：Chrome、Edge、Opera、Vivaldi，配 Windows / macOS / Linux；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;语言、时区、窗口尺寸&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WebRTC 策略&lt;/strong&gt;：禁用非代理 UDP、仅公开接口、公开与私有；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;浏览器内核与代理&lt;/strong&gt;：都从下拉里选，代理在启动时选定，改完从下次启动生效。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;档案可以启动、停止、重启，启动过程中还能取消；正常停止会先通过 CDP 发 &lt;code&gt;Browser.close&lt;/code&gt;，让 Cookie 和持久状态有机会落盘，然后才强制清理。删除档案时&lt;strong&gt;只删记录，磁盘上的浏览器数据保留&lt;/strong&gt;——手滑删错了，数据还在。&lt;/p&gt;
&lt;p&gt;列表支持按名称、种子、品牌、平台、内核、代理筛选。但这里有个我刻意的取舍：**筛选只影响「显示什么」，不会批量操作一个隐藏的档案。**一个被筛掉的档案该跑还是跑，详情面板回答的也还是它。多选和批量操作我不打算做，理由记在仓库文档里。&lt;/p&gt;
&lt;h3&gt;2. 代理：一个能连上的端口，不等于一个能用的代理&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://img.990915.xyz/2026/10/02/1790930691760-4ae09719-a617-48e1-aaf3-0d5e2e0e8f18.png&quot; alt=&quot;代理页：每个代理都记录了最近一次测试的出口地址与耗时&quot; /&gt;&lt;/p&gt;
&lt;p&gt;这是我在这个项目里最坚持的一点。&lt;/p&gt;
&lt;p&gt;一个&lt;strong&gt;开着的回环端口不等于一个能用的代理&lt;/strong&gt;。启动器最多只能知道 Xray 把本地入口绑定成功了；至于它上游凭据被拒、域名解析不了、还是根本没把任何字节送出去，这个检查一个都发现不了。结果就是：档案展示一个指纹，却被另一个地址看到——这正是这个项目想要避免的失败。&lt;/p&gt;
&lt;p&gt;所以我做的是&lt;strong&gt;发一个真实的 HTTP 请求，然后报告出口端看到的地址&lt;/strong&gt;，或者报告失败停在哪一层：引擎、配置、认证、域名解析、不可达、超时、TLS、HTTP 状态、响应不可读。测试端点故意是明文 HTTP 的（默认 &lt;code&gt;http://api.ipify.org&lt;/code&gt;，可用 &lt;code&gt;FP_BROWSER_ECHO_URL&lt;/code&gt; 改），因为走 TLS 的话证书问题会被误报成代理问题。&lt;/p&gt;
&lt;p&gt;更关键的一条：**启动一个走代理的档案时，会先问代理。**按下「启动」，程序先发一次和代理页同样的真实请求，只有真的有字节从引擎回来，才把启动排进队列。代理不通，浏览器就根本不启动，行上显示「启动中」，拒绝信息会点名是哪个档案、哪条代理、卡在路径的哪一段。代价是每次启动多一个往返，换来的是「浏览器在跑、看起来很健康、其实在裸奔」这件事不会发生。&lt;/p&gt;
&lt;p&gt;在此基础上还有两件事：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;**代理崩了，浏览器就关。**Xray 必须就绪 Chromium 才启动；运行中 Xray 崩掉，它的浏览器会被一起关掉，而不是悄悄退回直连。&lt;/li&gt;
&lt;li&gt;**读回浏览器自己的出口地址。**测代理只能证明&lt;em&gt;代理&lt;/em&gt;在做什么，证明不了&lt;em&gt;浏览器&lt;/em&gt;被指到了它。所以验证一个走代理的档案时，程序会在一个临时标签页里让浏览器自己请求一次端点，再把看到的地址读回来，并把四种结果分开：拿到地址、从未到达、没在时限内完成、返回里没有地址。「从未到达」和「没完成」是从页面状态读出来的，不是用一个超时去猜的。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3. 浏览器内核：版本决定它能说什么指纹&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://img.990915.xyz/2026/10/02/1790930760129-d6249790-4ec3-45c9-8ee2-5c80426eee12.png&quot; alt=&quot;浏览器内核：检测到的版本决定档案可以声明哪些指纹开关&quot; /&gt;&lt;/p&gt;
&lt;p&gt;内核就是一个个 &lt;code&gt;fingerprint-chromium&lt;/code&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;Windows 上还会读清单和 PE 元数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;内核页上的「下载内核」会列出 &lt;code&gt;adryfish/fingerprint-chromium&lt;/code&gt; 发布过的东西，按新到旧排，每个系统一个按钮——本机的那颗标出来，另外两颗留给别台机器。下载是&lt;strong&gt;可移植版本，解压到数据目录后走和手动添加完全相同的版本探测&lt;/strong&gt;：大版本是从二进制里读出来的，不是从 release tag 抄的。一次只下载一个，进度显示在它自己那一行。&lt;/p&gt;
&lt;p&gt;同样的规则也适用于 Xray：设置页里有对应的卡片，从 &lt;code&gt;XTLS/Xray-core&lt;/code&gt; 下载本机对应平台架构的构建，解压、写进设置、下次启动生效。**而且——不点就不下载。**这是整个项目的一条硬规则：程序不会替你下载任何东西。&lt;/p&gt;
&lt;h3&gt;4. 日志：这个窗口做过什么、看到什么&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://img.990915.xyz/2026/10/02/1790930846512-358c0fdf-60f2-44c7-be1b-c6bb760d75df.png&quot; alt=&quot;日志页：最新的在最前，同时写入 activity.log&quot; /&gt;&lt;/p&gt;
&lt;p&gt;所有操作都有记录：启动、停止、警告、错误与读数。日志同时写进 &lt;code&gt;logs/activity.log&lt;/code&gt;，达到 512 KiB 轮转一份备份，内存里的历史上限 500 行。「清空列表」只影响当前页面，文件里的内容一律保留。启动日志里能看到 PID、CDP 端口、SOCKS 端口、Xray PID，以及用了多少个启动参数。&lt;/p&gt;
&lt;h3&gt;5. 设置：有效值、来源，都说清楚&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://img.990915.xyz/2026/10/02/1790930877898-b87e952a-fa20-4135-b45f-cab371363f25.png&quot; alt=&quot;设置页：深色/浅色、English/简体中文，以及关闭窗口时做什么&quot; /&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;：English / 简体中文，两项都立刻作用于当前窗口；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;关闭窗口时&lt;/strong&gt;：每次询问、后台继续运行（窗口隐藏，托盘图标可唤回）、仅退出程序（浏览器留着跑）、退出全部。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;一个目录 = 一整套安装&lt;/h3&gt;
&lt;p&gt;配置、数据库、日志、档案、导出文件，全都在同一个数据目录里，用 &lt;code&gt;FP_BROWSER_DATA_DIR&lt;/code&gt; 或平台默认值选定。程序会对数据目录加&lt;strong&gt;内核级文件锁&lt;/strong&gt;，同一目录只允许开一个窗口：第二个副本拿不到锁，会打印出「谁」占着这个目录然后以退出码 3 退出，而不是打开同一个数据库、把第一个副本正在跑的浏览器停掉。锁是内核的，所以崩溃也不会留下死锁。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;--version&lt;/code&gt;、&lt;code&gt;--help&lt;/code&gt;、&lt;code&gt;--diagnostics&lt;/code&gt; 三个选项不打开窗口就能用。&lt;code&gt;--diagnostics&lt;/code&gt; 会写出这个安装的一份报告——构建信息、有效设置及来源、它维护的每个文件的状态和权限、日志尾部——&lt;strong&gt;从不包含代理凭据，也从不读浏览器数据&lt;/strong&gt;。&lt;/p&gt;
&lt;h2&gt;有多轻&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://img.990915.xyz/2026/10/02/1790931513825-6dc94930-dcd0-46a8-a9a1-cdc47eb20ca4.png&quot; alt=&quot;Windows 任务管理器里的管理器进程：16.5 MB 内存，CPU 0.1%&quot; /&gt;&lt;/p&gt;
&lt;p&gt;这是任务管理器里的它：&lt;strong&gt;16.5 MB 内存，0.1% CPU，0 网络&lt;/strong&gt;。不是随便一帧的峰值，而是它开着窗口、平时待着的常态。&lt;/p&gt;
&lt;p&gt;之所以能这么小，是因为它从一开始就没打算把「一个浏览器」塞进自己身体里：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;原生 Rust + GPUI Kit&lt;/strong&gt;，不是 Electron、不是 CEF 套壳。没有打包进去的 Chromium 运行时，没有 Node 运行时，没有几百 MB 的 &lt;code&gt;node_modules&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;不内嵌内核和代理引擎&lt;/strong&gt;。&lt;code&gt;fingerprint-chromium&lt;/code&gt; 和 Xray 是外部可执行文件，用哪个、放哪里都由你决定，管理器本身不背着它们；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;空闲就是真的空闲&lt;/strong&gt;。不启动任何浏览器、不起任何 Xray、不建连接——只有你按下「启动」，进程才会被拉起来。关窗口选「后台继续运行」常驻在托盘时，也还是这个量级。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;作为对照，一个 Electron 的空窗口往往就要一两百 MB 起步。对这一类需要长期挂在托盘里、时不时看一眼状态的小工具来说，这一层省下来的内存是实打实的。&lt;/p&gt;
&lt;p&gt;不过有一句得说清楚：**省下的只是「管理器」这一层，不是浏览器本身。**真正开起档案之后，内存大头是 Chromium 自己的，和直接用 Chrome 差不多；而且每个档案是独立进程加独立 &lt;code&gt;user-data-dir&lt;/code&gt;，开得越多自然涨得越多。这是隔离换来的成本，也是它本来就该有的样子——管理器不该为浏览器的开销背锅，也不该假装自己不占内存。&lt;/p&gt;
&lt;h2&gt;工程上我在意的事&lt;/h2&gt;
&lt;p&gt;这个项目维护着一份&lt;a href=&quot;https://github.com/denislov/fingerprint-browser/blob/master/docs/fingerprint-matrix.md&quot;&gt;指纹开关矩阵&lt;/a&gt;：哪些开关在哪些大版本上可用，凭据是什么。其中有个例子我很想分享，因为它说明了「证据」和「假设」的差别。&lt;/p&gt;
&lt;p&gt;矩阵一开始以 Chromium 144 为分界，这个分界是从兄弟项目那里继承来的，本仓库并没有测过 144 以下。后来我把一个 142 的构建拉出来实测，结果推翻了继承的结论：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;在 142 / 144 / 148 上实测&lt;/th&gt;
&lt;th&gt;142&lt;/th&gt;
&lt;th&gt;144&lt;/th&gt;
&lt;th&gt;148&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--fingerprinting-canvas-image-data-noise&lt;/code&gt; 能改变 &lt;code&gt;toDataURL&lt;/code&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;code&gt;--disable-spoofing=canvas|clientrects|audio&lt;/code&gt; 被采纳&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;否&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;是&lt;/td&gt;
&lt;td&gt;是&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;也就是说，噪声开关&lt;strong&gt;不是&lt;/strong&gt; 144 才有的特性，而排除开关&lt;strong&gt;才是&lt;/strong&gt;。表格和测试都被修正了。150 行不到的文档背后是这类反复的实测——所以至今 145–147 仍然标注为「推断」，而不是「已知」。&lt;/p&gt;
&lt;p&gt;其他一些细节：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;分层清晰&lt;/strong&gt;：Rust workspace 分成 &lt;code&gt;domain&lt;/code&gt;、&lt;code&gt;storage&lt;/code&gt;、&lt;code&gt;runtime&lt;/code&gt;、&lt;code&gt;application&lt;/code&gt;、&lt;code&gt;app&lt;/code&gt; 五个 crate。UI 不直接 &lt;code&gt;Command::spawn()&lt;/code&gt;，Storage 不认识 GPUI 类型，Domain 不依赖 SQLite / GPUI / Xray JSON / Chromium CLI。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;启动计划不可变&lt;/strong&gt;：所有外部进程启动前，先生成一个不可变的 &lt;code&gt;LaunchPlan&lt;/code&gt;，之后再执行。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;慢操作进 worker&lt;/strong&gt;：代理测试、指纹校验、打开目录、浏览器数据复制、导入导出，都交给 worker，结果经各自的通道回到 tick 循环。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Windows 生命周期&lt;/strong&gt;：Chromium 和 Xray 在创建时就用 &lt;code&gt;PROC_THREAD_ATTRIBUTE_JOB_LIST&lt;/code&gt; 放进独立的 Job Object，赋值和创建是原子的，没有「先创建后赋值」的空窗。会话日志记录 PID 和原生创建时间，用 &lt;code&gt;GetProcessTimes&lt;/code&gt; 校验身份，把「已退出」和「读不到」区分开。Unix 上则用独立进程组，Linux 用 &lt;code&gt;/proc&lt;/code&gt; 做恢复。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CI 门禁&lt;/strong&gt;：&lt;code&gt;scripts/check.ps1&lt;/code&gt; / &lt;code&gt;check.sh&lt;/code&gt; 跑 fmt、check、测试和严格 clippy，在 Ubuntu 和 Windows 上都会跑。真实引擎的验收测试是 opt-in 的，故意和门禁分开。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;现状与限制&lt;/h2&gt;
&lt;p&gt;说点实话：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;0.3.0 已经发布&lt;/strong&gt;，Releases 里有 Windows 安装包、Linux 归档和 Debian 包，每个都带 &lt;code&gt;.sha256&lt;/code&gt;；发布 workflow 跑在 GitHub Actions 上。&lt;/li&gt;
&lt;li&gt;程序本身&lt;strong&gt;不附带浏览器和代理引擎&lt;/strong&gt;，需要你自己提供 &lt;code&gt;fingerprint-chromium&lt;/code&gt; 和 Xray——或者用界面里的一键下载。&lt;/li&gt;
&lt;li&gt;Windows 上的真实测试已经覆盖了档案隔离、Cookie、取消、正常关闭、浏览器/Xray 崩溃、管理器被强杀和残留日志清理；&lt;strong&gt;Windows 端的指纹实测&lt;/strong&gt;和远端上游转发仍是待办。&lt;/li&gt;
&lt;li&gt;强制终止无法保证 Cookie/状态一定落盘，所以正常停止路径仍然是 CDP 关闭。&lt;/li&gt;
&lt;li&gt;代理隧道走 UDP 的协议（Shadowsocks、SOCKS5）如果叠加 HTTP 系统代理会丢掉 UDP，这个组合会在连接层报错，而不是静默走去直连。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;怎么用起来&lt;/h2&gt;
&lt;p&gt;从源码跑（需要 &lt;code&gt;rustup&lt;/code&gt;，它会自动安装 &lt;code&gt;rust-toolchain.toml&lt;/code&gt; 里钉住的编译器）：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;FP_BROWSER_CHROMIUM_BIN=/path/chrome FP_BROWSER_XRAY_BIN=/path/xray cargo run -p app
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Linux 需要 &lt;code&gt;libfontconfig1-dev&lt;/code&gt;、&lt;code&gt;libfreetype-dev&lt;/code&gt;、&lt;code&gt;libxcb1-dev&lt;/code&gt;、&lt;code&gt;libxkbcommon-dev&lt;/code&gt;、&lt;code&gt;libxkbcommon-x11-dev&lt;/code&gt;——但&lt;strong&gt;只有运行时才需要显示器&lt;/strong&gt;，构建本身不用。&lt;/p&gt;
&lt;p&gt;懒得编译的话，直接去 &lt;a href=&quot;https://github.com/denislov/fingerprint-browser/releases&quot;&gt;Releases&lt;/a&gt; 下载：Windows 用 &lt;code&gt;-setup.exe&lt;/code&gt;，Debian/Ubuntu 用 &lt;code&gt;.deb&lt;/code&gt;，其他 Linux 用 &lt;code&gt;tar.gz&lt;/code&gt;。第一次打开如果还没有内核，空列表会明确告诉你，并带一个按钮直接去内核页下载。&lt;/p&gt;
&lt;h2&gt;最后&lt;/h2&gt;
&lt;p&gt;这个项目的定位从来不是「大而全」，而是&lt;strong&gt;把一件小事做扎实&lt;/strong&gt;：让每个档案的环境可复现，让每个「代理生效了」的说法可验证，让程序在你不点按钮的时候什么都不做。&lt;/p&gt;
&lt;p&gt;如果你也在意这些，欢迎去看一眼、提 issue，或者直接读代码——仓库里的 &lt;code&gt;docs/&lt;/code&gt; 目录写得比这篇博客细得多，包括架构、领域模型、生命周期、指纹矩阵和每一版的实现计划。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;仓库：&lt;a href=&quot;https://github.com/denislov/fingerprint-browser&quot;&gt;https://github.com/denislov/fingerprint-browser&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;协议：MIT&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;用一句项目文档里的话收尾吧：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;把 Profile 配置编译为稳定、可复现的浏览器运行环境，并可靠管理其生命周期。&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded><category>折腾</category><category>指纹浏览器</category><category>Rust</category><category>开源</category><category>GPUI</category><category>Xray</category><category>隐私</category></item><item><title>Pi 1.0 正式发布：一个更硬核、更极简、真正可扩展的 AI Agent 底座</title><link>https://blog.990915.xyz/posts/pi-10%E5%8F%91%E5%B8%83/</link><guid isPermaLink="true">https://blog.990915.xyz/posts/pi-10%E5%8F%91%E5%B8%83/</guid><description>Earendil 正式发布 Pi 1.0——一个 hardened、minimal、extensible 的 AI Agent 底座。本文梳理 Codemode、虚拟模型扩展、延迟工具加载、缓存预热等新特性，也介绍同时发布的实验性项目 Pi Durable 与安装方式。</description><pubDate>Fri, 02 Oct 2026 11:11:50 GMT</pubDate><content:encoded>&lt;p&gt;今天，Earendil 正式发布了 &lt;strong&gt;Pi 1.0&lt;/strong&gt;。
&lt;img src=&quot;https://img.990915.xyz/2026/10/02/1790910710130-403cc51b-4eb2-406c-aad7-9979715c90ae.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;这不是又一个“功能堆砌”的 Agent 更新，而是一个经过长时间打磨、真正走向稳定的 &lt;strong&gt;minimal agent harness&lt;/strong&gt;。官方原话很有意思：它是“hardened, minimal, extensible”——既要硬核可靠，又要保持极简，还要足够可扩展，让每个人都能把它变成自己的工具。&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;h2&gt;为什么说 Pi 特别？&lt;/h2&gt;
&lt;p&gt;Pi 从一开始就坚持一件事：&lt;strong&gt;极简&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;在 Agent 工具几乎每周都在变的今天，很多新特性来得快、去得也快。Pi 的态度是：等它真正证明自己有用，再考虑加进来，并且会仔细权衡“功能价值”和“增加的复杂度”。这种克制，让它在保持轻量的同时，已经成了很多人日常写代码的主力 Agent。&lt;/p&gt;
&lt;p&gt;目前全球每周有数十万人在用 Pi，社区也贡献了大量反馈和 PR。经过几个月的打磨，1.0 终于到来。&lt;/p&gt;
&lt;h2&gt;Pi 1.0 带来了什么？&lt;/h2&gt;
&lt;p&gt;这次更新没有铺天盖地堆功能，而是把几个经过验证的能力正式收了进来：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Codemode&lt;/strong&gt;：原生支持 MCP，以及非 LLM 模型（比如 Jev 和图像模型）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;虚拟模型扩展支持&lt;/strong&gt;：可以自己定义路由逻辑（例如用 Claude 规划、GPT 实现，Jev 决定何时切换）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;延迟工具加载&lt;/strong&gt;（Deferred tool loading）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Anthropic 模型的缓存预热&lt;/strong&gt;（Cache warming）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;对话中途的系统消息&lt;/strong&gt;：可以在会话过程中动态调整 prompt 和工具&lt;/li&gt;
&lt;li&gt;全新 TUI 主题&lt;/li&gt;
&lt;li&gt;默认全屏模式&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;官方还特意强调：这些功能都是“扔到墙上能粘住的”。那些没粘住的，比粘住的多得多。用上这些新能力后，Pi 感觉明显更强了，但整体依然简洁，依然是那个 Pi。&lt;/p&gt;
&lt;h3&gt;同时发布的还有实验性项目：Pi Durable&lt;/h3&gt;
&lt;p&gt;Earendil 发现，有些人想把 Pi 的极简哲学和“可被人类掌控的 AI”能力，带到编码终端之外——更长的对话、更持久的任务、不同的使用界面。&lt;/p&gt;
&lt;p&gt;他们没有强行把 Pi 改造成“什么都想做”的东西，而是单独做了一个实验性包 &lt;strong&gt;Pi Durable&lt;/strong&gt;。它继承了 Pi 的极简和超高可塑性（supermalleability），但把这些原则延伸到了更长运行的 Agent 应用场景。&lt;/p&gt;
&lt;p&gt;简单说：Pi 负责“轻量、可依赖、可扩展的日常 Agent 底座”，Pi Durable 则探索“更持久的 Agent 应用构建方式”。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://img.990915.xyz/2026/10/02/1790910747646-352df18b-1d6e-4e28-9261-4e0e7e82271a.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;安装方式&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Pi 1.0&lt;/strong&gt;（已可用）：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl -fsSL https://pi.dev/install.sh | sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Windows：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;powershell -c &quot;irm https://pi.dev/install.ps1 | iex&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Pi Durable&lt;/strong&gt;（实验性）：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install @earendil-works/pi-durable @earendil-works/pi-ai @earendil-works/chord
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;两者都是 &lt;strong&gt;MIT 开源&lt;/strong&gt;。文档在 &lt;a href=&quot;https://pi.dev&quot;&gt;pi.dev&lt;/a&gt;，代码在 &lt;a href=&quot;https://github.com/earendil-works/pi&quot;&gt;github.com/earendil-works/pi&lt;/a&gt;。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;一点感想&lt;/h2&gt;
&lt;p&gt;在 Agent 工具越来越花哨、越来越重的今天，Pi 1.0 选择继续走“少即是多”的路，并且把稳定性、可扩展性和“人类能真正掌控”放在首位，这本身就挺有态度的。&lt;/p&gt;
&lt;p&gt;如果你喜欢轻量、可控、可深度定制的 Agent 工具，值得去试试。&lt;/p&gt;
&lt;p&gt;安装地址再贴一次：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl -fsSL https://pi.dev/install.sh | sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;欢迎去社区反馈和贡献。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://img.990915.xyz/2026/10/02/1790910770565-e30114bc-f9ca-472b-942d-1b72ca1fb67e.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
</content:encoded><category>AI</category><category>Pi</category><category>AI Agent</category><category>MCP</category><category>开源</category></item><item><title>Troubleshooting apt update: DNS Failure for Tencent Cloud&apos;s Private Mirror</title><link>https://blog.990915.xyz/en/posts/apt-update-tencent-private-dns-en/</link><guid isPermaLink="true">https://blog.990915.xyz/en/posts/apt-update-tencent-private-dns-en/</guid><description>apt update failed for exactly one repository, the private Tencent Cloud mirror mirrors.tencentyun.com, while all others worked. mihomo TUN mode was sending DNS queries to public resolvers instead of the VPC DNS servers, and an explicit nameserver-policy fixed it.</description><pubDate>Thu, 01 Oct 2026 16:19:05 GMT</pubDate><content:encoded>&lt;h2&gt;Symptoms&lt;/h2&gt;
&lt;p&gt;I ran &lt;code&gt;apt update&lt;/code&gt; on my VPS and got a puzzling result: &lt;strong&gt;only one repository failed; every other repository worked fine.&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Err:1 http://mirrors.tencentyun.com/ubuntu jammy InRelease
  Could not resolve &apos;mirrors.tencentyun.com&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Switching to a public mirror such as &lt;code&gt;archive.ubuntu.com&lt;/code&gt; or &lt;code&gt;mirrors.aliyun.com&lt;/code&gt; worked. Pinging other hosts worked too. In other words, the network connection was fine—&lt;strong&gt;the only thing that failed was DNS resolution for this private mirror&apos;s domain.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;h2&gt;Root Cause&lt;/h2&gt;
&lt;p&gt;The machine was running mihomo with &lt;strong&gt;TUN mode&lt;/strong&gt; enabled. In this setup, mihomo intercepted the machine&apos;s DNS requests on port &lt;code&gt;53&lt;/code&gt;. The DNS servers listed in &lt;code&gt;/etc/resolv.conf&lt;/code&gt; were not actually handling those queries; instead, they were sent to the &lt;strong&gt;upstream DNS servers&lt;/strong&gt; configured in mihomo. Mine were all public resolvers, including DoH services and &lt;code&gt;1.1.1.1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;That was the problem: &lt;code&gt;mirrors.tencentyun.com&lt;/code&gt; is &lt;strong&gt;a mirror domain intended for Tencent Cloud&apos;s private network&lt;/strong&gt;. It needs to be resolved through the DNS servers inside the VPC:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;183.60.83.19 / 183.60.82.98
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Asking &lt;code&gt;1.1.1.1&lt;/code&gt; to resolve a domain that exists only on a private network was never going to work. The public resolver did not know about it, so the lookup failed.&lt;/p&gt;
&lt;h2&gt;First Wrong Turn: &lt;code&gt;fake-ip-filter&lt;/code&gt; Did Not Help&lt;/h2&gt;
&lt;p&gt;My first thought was: &quot;If fake IPs are involved, shouldn&apos;t excluding this domain fix it?&quot; So I added it to &lt;code&gt;fake-ip-filter&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dns:
  fake-ip-filter:
    - &apos;mirrors.tencentyun.com&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;It did not help.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The reason is straightforward: &lt;code&gt;fake-ip-filter&lt;/code&gt; only controls &lt;strong&gt;whether a domain receives a fake IP address&lt;/strong&gt;. It determines &lt;strong&gt;what kind of address is returned&lt;/strong&gt;, not &lt;strong&gt;which upstream DNS server performs the lookup&lt;/strong&gt;. Whether the query goes to &lt;code&gt;1.1.1.1&lt;/code&gt; or another resolver has nothing to do with this setting.&lt;/p&gt;
&lt;h2&gt;The Fix: Explicitly Select the Upstream with &lt;code&gt;nameserver-policy&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;What needed to change was &lt;strong&gt;who resolved this domain&lt;/strong&gt;. I added a &lt;code&gt;nameserver-policy&lt;/code&gt; entry to send its queries to the VPC DNS servers:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dns:
  nameserver-policy:
    &apos;+.mirrors.tencentyun.com&apos;: [&apos;183.60.83.19&apos;, &apos;183.60.82.98&apos;]
    # Add other private-network domains here as needed.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After hot-reloading the configuration, I checked the result:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ dig +short mirrors.tencentyun.com
169.254.0.3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;169.254.0.3&lt;/code&gt; was the fake IP that mihomo returned to the application. The actual DNS lookup had already been handled by the VPC DNS servers, and the TUN layer mapped the connection to the real address when it was established. The fake IP did not prevent the service from working.&lt;/p&gt;
&lt;p&gt;I ran &lt;code&gt;apt update&lt;/code&gt; again, and &lt;strong&gt;it worked immediately&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;Lessons Learned&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;DNS servers supplied by DHCP can effectively be bypassed when TUN DNS interception is enabled.&lt;/strong&gt; In my setup, mihomo took over all DNS requests on port &lt;code&gt;53&lt;/code&gt;. Simply putting the VPC DNS servers in &lt;code&gt;/etc/resolv.conf&lt;/code&gt; did not help.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Private-network domains need an explicit DNS resolution policy.&lt;/strong&gt; Whether it is Tencent Cloud&apos;s &lt;code&gt;mirrors.tencentyun.com&lt;/code&gt;, a corporate intranet domain, or a private service, a domain known only to private DNS servers needs a &lt;code&gt;nameserver-policy&lt;/code&gt; entry pointing to those servers. Otherwise, the query goes to a public resolver and fails.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Keep the roles of &lt;code&gt;fake-ip-filter&lt;/code&gt; and &lt;code&gt;nameserver-policy&lt;/code&gt; separate:&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;fake-ip-filter&lt;/code&gt; decides &lt;strong&gt;whether to return a real IP or a fake IP&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nameserver-policy&lt;/code&gt; decides &lt;strong&gt;which upstream DNS server resolves the domain&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;When DNS resolution itself is failing, it is usually &lt;strong&gt;the latter&lt;/strong&gt; that needs changing.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;One misplaced setting cost me half a day of troubleshooting. Writing this down so my future self does not fall into the same trap again.&lt;/p&gt;
</content:encoded><category>折腾</category><category>mihomo</category><category>Clash</category><category>DNS</category><category>腾讯云</category><category>Linux</category></item><item><title>从零搭建 Caddy + Xray：VLESS REALITY + XHTTP + 特殊出口落地 + 订阅流量</title><link>https://blog.990915.xyz/posts/caddy-xray-vless-reality-xhttp-%E8%90%BD%E5%9C%B0%E8%8A%82%E7%82%B9%E4%B8%8E%E8%AE%A2%E9%98%85%E6%B5%81%E9%87%8F%E6%95%99%E7%A8%8B/</link><guid isPermaLink="true">https://blog.990915.xyz/posts/caddy-xray-vless-reality-xhttp-%E8%90%BD%E5%9C%B0%E8%8A%82%E7%82%B9%E4%B8%8E%E8%AE%A2%E9%98%85%E6%B5%81%E9%87%8F%E6%95%99%E7%A8%8B/</guid><description>只开一个 443 端口，Caddy 的 layer4 加 TLS 分流把 Xray 的 VLESS REALITY、XHTTP、落地出口与订阅服务收在同一入口：xcaddy 编译模块、Unix socket 反代、SQLite 用户库与流量统计，另附部署脚本与排错清单。</description><pubDate>Thu, 01 Oct 2026 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;这套架构我已经稳定跑了一段时间：&lt;strong&gt;只对外开一个 443 端口&lt;/strong&gt;，由 Caddy 负责 TLS 和路径分流，Xray 全部监听 Unix domain socket（不暴露任何公网端口），同一个入口同时承载 REALITY、XHTTP、&quot;特殊出口落地节点&quot;、博客静态站和订阅服务。&lt;/p&gt;
&lt;p&gt;客户端拿到一条订阅链接，就能自动看到 &lt;strong&gt;流量、到期时间、剩余额度&lt;/strong&gt;，还能按需在普通节点和落地节点之间切换。&lt;/p&gt;
&lt;p&gt;这篇文章把整套东西掰开揉碎讲一遍。&lt;strong&gt;所有 IP、域名、UUID、密钥、Token、账号密码我都换成了占位符&lt;/strong&gt;，你照着替换成自己的即可。&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;h2&gt;一、先说架构：数据包到底怎么走&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;                          客户端
                            │
              TLS :443（REALITY / XHTTP / 普通浏览器）
                            │
                            ▼
                  Caddy layer4  tcp/:443
                            │  PROXY protocol v2（转发到 Unix socket）
                            ▼
              Xray REALITY 入站（@xray-reality.sock）
                ├── 是 REALITY 客户端 ──► 直接代理出站
                └── 不是 ──► fallback（带 PROXY v2）
                            │
                            ▼
              Caddy HTTP 服务（@caddy-http.sock，在这里终止 TLS）
                ├── /xhttp/*        ──► Xray XHTTP 入站（普通节点）
                ├── /xhttp-exit-a/* ──► Xray XHTTP 入站 ──► socks 出站 A（落地）
                ├── /xhttp-exit-b/* ──► Xray XHTTP 入站 ──► socks 出站 B（落地）
                ├── /sub/*          ──► 订阅服务 127.0.0.1:8080
                └── 其它            ──► 静态站点（博客）
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;关键点一句话总结：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Caddy 的 &lt;code&gt;layer4&lt;/code&gt; 模块&lt;/strong&gt;接管 443 的裸 TCP，把它转交给 Xray 的 REALITY 入站；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;REALITY 的 fallback 指向 Caddy 自己的 HTTP 服务&lt;/strong&gt;（俗称&quot;偷自己&quot;），这样普通 TLS 访问者看到的就是一个真实网站；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;XHTTP 入站全部监听 Unix socket&lt;/strong&gt;，由 Caddy 按 HTTP 路径反代进去；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;落地节点不是新域名、新证书&lt;/strong&gt;，只是同一个域名 + 不同 path，靠 Xray 的 routing 按入站 tag 分到不同的 socks 出站；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;订阅服务&lt;/strong&gt;用 SQLite 存用户，通过 Xray 的 gRPC API 动态增删用户、轮询流量，并在订阅响应头里回传用量。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;二、为什么这么设计&lt;/h2&gt;
&lt;h3&gt;1. 只开一个端口&lt;/h3&gt;
&lt;p&gt;只需要放行 443（和 SSH）。证书用 Cloudflare DNS-01 签发，连 80 端口都不用开，也不依赖 Let&apos;s Encrypt 的 HTTP 挑战。&lt;/p&gt;
&lt;h3&gt;2. 为什么用 Caddy 的 layer4，而不是 Nginx&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;REALITY 需要处理裸 TCP&lt;/td&gt;
&lt;td&gt;Xray 直接监听 443&lt;/td&gt;
&lt;td&gt;layer4 把裸 TCP 交给 Xray&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;XHTTP 需要按路径分流&lt;/td&gt;
&lt;td&gt;另开端口 / 用 Nginx stream&lt;/td&gt;
&lt;td&gt;Caddy HTTP 反代到 Unix socket&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;证书自动续期&lt;/td&gt;
&lt;td&gt;certbot + 定时任务&lt;/td&gt;
&lt;td&gt;Caddy 内置 ACME + DNS-01&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;静态站&lt;/td&gt;
&lt;td&gt;再起一个 web 服务&lt;/td&gt;
&lt;td&gt;Caddy &lt;code&gt;file_server&lt;/code&gt; 顺手托管&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Caddy 的 &lt;code&gt;layer4&lt;/code&gt; + HTTP 两种能力在一个进程里，省掉了一层。&lt;/p&gt;
&lt;h3&gt;3. 为什么 REALITY 的 fallback 要指向&quot;自己&quot;&lt;/h3&gt;
&lt;p&gt;REALITY 的伪装原理是：真客户端完成握手，假客户端被&quot;转交&quot;给一个真实的 TLS 站点。如果那个站点是别人的网站，你就在蹭别人的证书；而把它设成 &lt;strong&gt;Caddy 托管的自己的站点&lt;/strong&gt;，就变成了真正的&quot;偷自己&quot;——证书、域名、内容全部自洽，抗主动探测能力最好。&lt;/p&gt;
&lt;h3&gt;4. 为什么落地节点复用同一个入口&lt;/h3&gt;
&lt;p&gt;自建落地（或买的 socks5 落地）的 IP 通常不想直接暴露给客户端。做法是：&lt;strong&gt;落地节点也当作一个 XHTTP 入站挂在入口上&lt;/strong&gt;，客户端连的还是入口域名:443，只是 path 不同。入口上的 Xray 收到之后，按入站 tag 走 routing，转给对应的 socks 出站。&lt;/p&gt;
&lt;p&gt;这样带来几个好处：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;客户端只需要一个域名、一份证书；&lt;/li&gt;
&lt;li&gt;落地 IP 完全不暴露；&lt;/li&gt;
&lt;li&gt;出口切换 = 切换节点，本质上只是换 path；&lt;/li&gt;
&lt;li&gt;可以做用户白名单：只有名单里的用户订阅里才会出现落地节点。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;5. 订阅统一管理&lt;/h3&gt;
&lt;p&gt;订阅服务是唯一&quot;知道全部用户&quot;的地方。它通过 Xray 的 API 在运行时把用户加进各个入站，不用重启 Xray；同时按用户邮箱聚合流量。&lt;/p&gt;
&lt;h2&gt;三、前置准备&lt;/h2&gt;
&lt;p&gt;一台 VPS（下文称 &lt;strong&gt;入口机&lt;/strong&gt;），以及：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一个域名，例如 &lt;code&gt;node.example.com&lt;/code&gt;，DNS 托管在 Cloudflare；&lt;/li&gt;
&lt;li&gt;Cloudflare API Token（需要 &lt;code&gt;Zone:DNS:Edit&lt;/code&gt; 权限）；&lt;/li&gt;
&lt;li&gt;入口机的 443 端口可从公网访问；&lt;/li&gt;
&lt;li&gt;一个 socks5 落地（下文用 &lt;code&gt;198.51.100.20:1080&lt;/code&gt; 举例，带用户名密码认证）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;需要安装的东西：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 1) Xray
bash -c &quot;$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)&quot; @ install

# 2) Go（编译订阅服务用，要求较新的版本）
#    从 https://go.dev/dl/ 下载对应架构的包即可

# 3) xcaddy（用来编译带 layer4 + cloudflare DNS 模块的 Caddy）
go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest

# 编译 Caddy（关键：必须带 caddy-l4 和 caddy-dns/cloudflare 两个模块）
~/go/bin/xcaddy build \
  --with github.com/caddy-dns/cloudflare \
  --with github.com/mholt/caddy-l4
# 产物是当前目录的 ./caddy
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ 注意：官方预编译的 Caddy &lt;strong&gt;不包含&lt;/strong&gt; &lt;code&gt;layer4&lt;/code&gt; 和 &lt;code&gt;cloudflare&lt;/code&gt; DNS 模块，必须自己用 xcaddy 编译。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;四、目录结构&lt;/h2&gt;
&lt;p&gt;把所有东西放到一个目录里，方便打包、同步、备份：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/etc/goodnet/
├── bin/
│   ├── caddy              # xcaddy 编译产物
│   ├── xray               # Xray 主程序
│   ├── sub                # 订阅服务（Go 编译产物）
│   └── geoip.dat geoip.metadb geosite.dat   # 分流数据
├── Caddyfile              # Caddy 配置
├── xray.json              # Xray 主配置
├── xray_conf/             # Xray 入站配置（按文件拆分）
│   ├── VLESS-REALITY-5443.json
│   ├── VLESS-XHTTP-2023.json
│   └── VLESS-XHTTP-LANDING.json
├── sub/
│   ├── *.go               # 订阅服务源码
│   ├── config.json        # 订阅服务配置
│   └── data/users.db      # SQLite 用户库（运行数据，永远保留）
├── caddy.service
├── xray.service
├── sub.service
├── deploy.sh              # 一键部署
└── landing.sh             # 落地节点管理（一条命令改 4 个文件）
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Xray 支持 &lt;code&gt;-confdir&lt;/code&gt; 参数：主配置放在 &lt;code&gt;xray.json&lt;/code&gt;，各个入站拆成 &lt;code&gt;xray_conf/*.json&lt;/code&gt;，启动时自动合并。这样落地节点可以独立成文件，脚本改起来不会互相打架。&lt;/p&gt;
&lt;p&gt;下面开始逐个文件讲。&lt;/p&gt;
&lt;h2&gt;五、Caddy：唯一对外的入口&lt;/h2&gt;
&lt;h3&gt;1. Caddyfile&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;{
	# 证书与 ACME 数据落盘，重启不重签
	storage file_system /home/tls
	email admin@example.com

	# DNS-01 挑战：证书签发只依赖 DNS，不占 80 端口
	acme_dns cloudflare {env.CLOUDFLARE_API_TOKEN}

	log log0 {
		output file /var/log/caddy/access.log
		format json
	}

	# 关键：这个 HTTP 服务监听的是 Unix socket，不监听公网端口
	# listener_wrappers 先解开 PROXY protocol，再做 TLS 终止
	servers unix/@caddy-http.sock {
		name http-entry
		listener_wrappers {
			proxy_protocol
			tls
		}
		trusted_proxies cloudflare {
			interval 12h
			timeout 15s
		}
	}

	# layer4：接管 443 裸 TCP，转给 Xray REALITY，并附上 PROXY v2
	layer4 {
		tcp/:443 {
			route {
				proxy {
					upstream unix/@xray-reality.sock
					proxy_protocol v2
				}
			}
		}
	}
}

node.example.com {
	log log0

	# 站点绑定在 Unix socket 上（REALITY fallback 会连它）
	bind unix/@caddy-http.sock

	# 订阅服务
	handle /sub/* {
		reverse_proxy 127.0.0.1:8080
	}

	# 落地节点 A：注意放在通用 XHTTP 规则之前
	handle /xhttp-exit-a/* {
		reverse_proxy unix/@xray-exit-a.sock {
			transport http {
				versions 2
			}
			flush_interval -1
		}
	}

	# 落地节点 B
	handle /xhttp-exit-b/* {
		reverse_proxy unix/@xray-exit-b.sock {
			transport http {
				versions 2
			}
			flush_interval -1
		}
	}

	# 普通 XHTTP 节点（通用路径，放最后）
	handle /xhttp/* {
		reverse_proxy unix/@xray-xhttp.sock {
			transport http {
				versions 2
			}
			flush_interval -1
		}
	}

	# 兜底：静态站点
	handle {
		encode zstd gzip

		header {
			Strict-Transport-Security &quot;max-age=31536000; includeSubDomains; preload&quot;
			X-Content-Type-Options &quot;nosniff&quot;
			Referrer-Policy &quot;strict-origin-when-cross-origin&quot;
			X-Frame-Options &quot;SAMEORIGIN&quot;
		}

		@assets path /css/* /js/*
		@immutable path /uploads/* /images/* /fonts/*
		@documents not path /css/* /js/* /uploads/* /images/* /fonts/*

		header @documents Cache-Control &quot;public, max-age=0, must-revalidate&quot;
		header @assets Cache-Control &quot;public, max-age=3600&quot;
		header @immutable Cache-Control &quot;public, max-age=2592000&quot;

		root * /var/www/site
		file_server
	}

	handle_errors {
		@notfound expression {http.error.status_code} == 404
		rewrite @notfound /404.html
		root * /var/www/site
		file_server
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. 几个必须理解的细节&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;servers unix/@caddy-http.sock&lt;/code&gt;&lt;/strong&gt;：这是 Caddy 的全局 &lt;code&gt;servers&lt;/code&gt; 选项，作用是把默认服务器改名并指定监听地址。这里让它监听一个抽象 Unix socket（Linux abstract namespace，&lt;code&gt;@&lt;/code&gt; 开头）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;listener_wrappers { proxy_protocol; tls }&lt;/code&gt;&lt;/strong&gt;：顺序很重要——先 &lt;code&gt;proxy_protocol&lt;/code&gt; 把 Xray fallback 发来的 PROXY v2 头剥掉，拿到真实客户端 IP，再做 &lt;code&gt;tls&lt;/code&gt; 终止。如果顺序反了，TLS 会先看到 PROXY 头的二进制而握手失败。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;layer4&lt;/code&gt; 块&lt;/strong&gt;：这是 &lt;code&gt;caddy-l4&lt;/code&gt; 模块提供的。它把 443 的原始 TCP 直接 &lt;code&gt;proxy&lt;/code&gt; 到 &lt;code&gt;@xray-reality.sock&lt;/code&gt;，并声明 &lt;code&gt;proxy_protocol v2&lt;/code&gt;。也就是说，&lt;strong&gt;443 上的第一跳不是 HTTP，而是裸 TCP 转发&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;handle&lt;/code&gt; 的顺序&lt;/strong&gt;：Caddy 的 &lt;code&gt;handle&lt;/code&gt; 是&quot;第一个匹配就执行&quot;。所以具体 path（&lt;code&gt;/xhttp-exit-a/*&lt;/code&gt;）必须写在通用 path（&lt;code&gt;/xhttp/*&lt;/code&gt;）前面。&lt;code&gt;/xhttp/*&lt;/code&gt; 不会匹配 &lt;code&gt;/xhttp-exit-a/...&lt;/code&gt;，因为 &lt;code&gt;-&lt;/code&gt; 不是 &lt;code&gt;/&lt;/code&gt;，但把具体规则放前面是更稳妥的写法。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;flush_interval -1&lt;/code&gt;&lt;/strong&gt;：XHTTP 是长连接 + 流式传输，必须禁用 Caddy 的响应缓冲，否则延迟爆炸、甚至卡死。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;versions 2&lt;/code&gt;&lt;/strong&gt;：XHTTP 走 HTTP/2 更能抗流量分析。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;如果你发现客户端连不上，可以先确认 Caddy 里既有 &lt;code&gt;/xhttp/*&lt;/code&gt; 也有 &lt;code&gt;/xhttp&lt;/code&gt;（不带 &lt;code&gt;/*&lt;/code&gt;）的 handle——不同版本的 XHTTP 对 path 的拼接方式略有差异，两个都加上最保险。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;3. Cloudflare Token 怎么给&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;caddy.service&lt;/code&gt; 里通过环境变量注入：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Environment=CLOUDFLARE_API_TOKEN=&amp;lt;CLOUDFLARE_API_TOKEN&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;更安全的做法是&lt;strong&gt;不要&lt;/strong&gt;把 Token 写在 unit 文件里（unit 文件常被 &lt;code&gt;systemctl cat&lt;/code&gt; 看到），而是用 &lt;code&gt;EnvironmentFile=/etc/goodnet/caddy.env&lt;/code&gt;，并把该文件 &lt;code&gt;chmod 600&lt;/code&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;六、Xray REALITY 入站&lt;/h2&gt;
&lt;h3&gt;1. 先生成密钥&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# 生成 X25519 密钥对
xray x25519
# Private key: &amp;lt;REALITY_PRIVATE_KEY&amp;gt;
# Public key:  &amp;lt;REALITY_PUBLIC_KEY&amp;gt;

# 生成一个 shortId（16 位十六进制）
openssl rand -hex 8
# 0123456789abcdef
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;把私钥填进服务端，公钥下发给客户端。&lt;/p&gt;
&lt;h3&gt;2. &lt;code&gt;xray_conf/VLESS-REALITY-5443.json&lt;/code&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;inbounds&quot;: [
    {
      &quot;tag&quot;: &quot;reality-main&quot;,
      &quot;listen&quot;: &quot;@xray-reality.sock&quot;,
      &quot;protocol&quot;: &quot;vless&quot;,
      &quot;settings&quot;: {
        &quot;clients&quot;: [],
        &quot;decryption&quot;: &quot;none&quot;,
        &quot;fallbacks&quot;: [
          {
            &quot;dest&quot;: &quot;@caddy-http.sock&quot;
          }
        ]
      },
      &quot;streamSettings&quot;: {
        &quot;network&quot;: &quot;raw&quot;,
        &quot;security&quot;: &quot;reality&quot;,
        &quot;realitySettings&quot;: {
          &quot;show&quot;: false,
          &quot;target&quot;: &quot;@caddy-http.sock&quot;,
          &quot;xver&quot;: 2,
          &quot;serverNames&quot;: [
            &quot;node.example.com&quot;
          ],
          &quot;publicKey&quot;: &quot;&amp;lt;REALITY_PUBLIC_KEY&amp;gt;&quot;,
          &quot;privateKey&quot;: &quot;&amp;lt;REALITY_PRIVATE_KEY&amp;gt;&quot;,
          &quot;shortIds&quot;: [
            &quot;0123456789abcdef&quot;
          ]
        },
        &quot;sockopt&quot;: {
          &quot;tcpFastOpen&quot;: true,
          &quot;tcpcongestion&quot;: &quot;bbr&quot;,
          &quot;tcpMptcp&quot;: true,
          &quot;tcpNoDelay&quot;: true
        },
        &quot;rawSettings&quot;: {
          &quot;acceptProxyProtocol&quot;: true
        }
      },
      &quot;sniffing&quot;: {
        &quot;enabled&quot;: true,
        &quot;destOverride&quot;: [
          &quot;http&quot;,
          &quot;tls&quot;
        ],
        &quot;routeOnly&quot;: true
      }
    }
  ]
}
&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;code&gt;listen: &quot;@xray-reality.sock&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;监听抽象 Unix socket，公网不可直接访问&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fallbacks.dest: &quot;@caddy-http.sock&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;非 REALITY 客户端转交给 Caddy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;realitySettings.target&lt;/code&gt; / &lt;code&gt;xver&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;fallback 目标与 PROXY 协议版本（必须与 Caddy 的 &lt;code&gt;listener_wrappers&lt;/code&gt; 对上）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;serverNames&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;允许的 SNI，必须包含真实域名&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;acceptProxyProtocol: true&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;接受来自 Caddy layer4 的 PROXY v2 头&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;routeOnly: true&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;嗅探结果只用于路由，不改写目标，避免影响 REALITY&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;客户端的 &lt;code&gt;flow&lt;/code&gt;（&lt;code&gt;xtls-rprx-vision&lt;/code&gt;）不写在这里&lt;/strong&gt;，因为用户是运行时由订阅服务通过 API 加进来的。这里 &lt;code&gt;clients&lt;/code&gt; 留空（或只放一个调试用账号），完全交给订阅服务管理。&lt;/p&gt;
&lt;h2&gt;七、Xray XHTTP 入站&lt;/h2&gt;
&lt;h3&gt;&lt;code&gt;xray_conf/VLESS-XHTTP-2023.json&lt;/code&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;inbounds&quot;: [
    {
      &quot;listen&quot;: &quot;@xray-xhttp.sock&quot;,
      &quot;protocol&quot;: &quot;vless&quot;,
      &quot;tag&quot;: &quot;xhttp-main&quot;,
      &quot;settings&quot;: {
        &quot;clients&quot;: [],
        &quot;decryption&quot;: &quot;none&quot;
      },
      &quot;streamSettings&quot;: {
        &quot;network&quot;: &quot;xhttp&quot;,
        &quot;xhttpSettings&quot;: {
          &quot;host&quot;: &quot;&quot;,
          &quot;path&quot;: &quot;/xhttp&quot;,
          &quot;mode&quot;: &quot;auto&quot;,
          &quot;extra&quot;: {
            &quot;noSSEHeader&quot;: true,
            &quot;scMaxEachPostBytes&quot;: 1000000,
            &quot;xPaddingBytes&quot;: &quot;100-1000&quot;
          }
        }
      },
      &quot;sniffing&quot;: {
        &quot;enabled&quot;: true,
        &quot;destOverride&quot;: [
          &quot;http&quot;,
          &quot;tls&quot;,
          &quot;quic&quot;
        ]
      }
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;参数说明：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;mode: auto&lt;/code&gt;：服务端自动适配，客户端可以用 stream-up / packet-up；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;noSSEHeader&lt;/code&gt;：去掉 SSE 响应头，更接近普通 HTTP；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;scMaxEachPostBytes&lt;/code&gt;：单个 POST 体上限；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;xPaddingBytes&lt;/code&gt;：给数据包加随机填充，弱化长度特征。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;XHTTP 的入站也是 VLESS + &lt;code&gt;decryption: none&lt;/code&gt;，用户同样由订阅服务运行时注入。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;在较新的 Xray 上，&lt;code&gt;xray run -test&lt;/code&gt; 会对&quot;没有 flow 的 VLESS&quot;给出 deprecation 警告（提示迁移到带 Flow/Seed 的新特性）。这只是警告，不影响运行；跟进新版时再评估即可。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;八、Xray 主配置：API、统计与路由&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;xray.json&lt;/code&gt; 是整个系统的&quot;大脑&quot;，负责 API、流量统计和分流规则。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;log&quot;: {
    &quot;access&quot;: &quot;/var/log/xray/access.log&quot;,
    &quot;error&quot;: &quot;/var/log/xray/error.log&quot;,
    &quot;loglevel&quot;: &quot;warning&quot;
  },
  &quot;dns&quot;: {},
  &quot;api&quot;: {
    &quot;tag&quot;: &quot;api&quot;,
    &quot;services&quot;: [
      &quot;HandlerService&quot;,
      &quot;LoggerService&quot;,
      &quot;StatsService&quot;
    ]
  },
  &quot;stats&quot;: {},
  &quot;policy&quot;: {
    &quot;levels&quot;: {
      &quot;0&quot;: {
        &quot;handshake&quot;: 7,
        &quot;connIdle&quot;: 676,
        &quot;uplinkOnly&quot;: 7,
        &quot;downlinkOnly&quot;: 8,
        &quot;statsUserUplink&quot;: true,
        &quot;statsUserDownlink&quot;: true
      }
    },
    &quot;system&quot;: {
      &quot;statsInboundUplink&quot;: true,
      &quot;statsInboundDownlink&quot;: true,
      &quot;statsOutboundUplink&quot;: true,
      &quot;statsOutboundDownlink&quot;: true
    }
  },
  &quot;routing&quot;: {
    &quot;domainStrategy&quot;: &quot;IPIfNonMatch&quot;,
    &quot;rules&quot;: [
      {
        &quot;type&quot;: &quot;field&quot;,
        &quot;inboundTag&quot;: [&quot;api&quot;],
        &quot;outboundTag&quot;: &quot;api&quot;
      },
      {
        &quot;type&quot;: &quot;field&quot;,
        &quot;protocol&quot;: [&quot;bittorrent&quot;],
        &quot;marktag&quot;: &quot;ban_bt&quot;,
        &quot;outboundTag&quot;: &quot;block&quot;
      },
      {
        &quot;type&quot;: &quot;field&quot;,
        &quot;inboundTag&quot;: [&quot;xhttp-exit-a&quot;],
        &quot;outboundTag&quot;: &quot;landing-exit-a&quot;
      },
      {
        &quot;type&quot;: &quot;field&quot;,
        &quot;inboundTag&quot;: [&quot;xhttp-exit-b&quot;],
        &quot;outboundTag&quot;: &quot;landing-exit-b&quot;
      },
      {
        &quot;type&quot;: &quot;field&quot;,
        &quot;ip&quot;: [&quot;geoip:cn&quot;],
        &quot;marktag&quot;: &quot;ban_geoip_cn&quot;,
        &quot;outboundTag&quot;: &quot;block&quot;
      },
      {
        &quot;type&quot;: &quot;field&quot;,
        &quot;domain&quot;: [&quot;geosite:openai&quot;],
        &quot;marktag&quot;: &quot;fix_openai&quot;,
        &quot;outboundTag&quot;: &quot;direct&quot;
      },
      {
        &quot;type&quot;: &quot;field&quot;,
        &quot;ip&quot;: [&quot;geoip:private&quot;],
        &quot;outboundTag&quot;: &quot;block&quot;
      }
    ]
  },
  &quot;inbounds&quot;: [
    {
      &quot;tag&quot;: &quot;api&quot;,
      &quot;port&quot;: 6765,
      &quot;listen&quot;: &quot;127.0.0.1&quot;,
      &quot;protocol&quot;: &quot;dokodemo-door&quot;,
      &quot;settings&quot;: {
        &quot;address&quot;: &quot;127.0.0.1&quot;
      }
    }
  ],
  &quot;outbounds&quot;: [
    { &quot;tag&quot;: &quot;direct&quot;, &quot;protocol&quot;: &quot;freedom&quot; },
    { &quot;tag&quot;: &quot;block&quot;, &quot;protocol&quot;: &quot;blackhole&quot; },
    {
      &quot;tag&quot;: &quot;landing-exit-a&quot;,
      &quot;protocol&quot;: &quot;socks&quot;,
      &quot;settings&quot;: {
        &quot;servers&quot;: [
          {
            &quot;address&quot;: &quot;198.51.100.20&quot;,
            &quot;port&quot;: 1080,
            &quot;users&quot;: [
              { &quot;user&quot;: &quot;&amp;lt;SOCKS_USER&amp;gt;&quot;, &quot;pass&quot;: &quot;&amp;lt;SOCKS_PASS&amp;gt;&quot; }
            ]
          }
        ]
      }
    },
    {
      &quot;tag&quot;: &quot;landing-exit-b&quot;,
      &quot;protocol&quot;: &quot;socks&quot;,
      &quot;settings&quot;: {
        &quot;servers&quot;: [
          {
            &quot;address&quot;: &quot;198.51.100.21&quot;,
            &quot;port&quot;: 1080,
            &quot;users&quot;: [
              { &quot;user&quot;: &quot;&amp;lt;SOCKS_USER&amp;gt;&quot;, &quot;pass&quot;: &quot;&amp;lt;SOCKS_PASS&amp;gt;&quot; }
            ]
          }
        ]
      }
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;1. API 与 &lt;code&gt;api&lt;/code&gt; 出站&lt;/h3&gt;
&lt;p&gt;启用了 &lt;code&gt;HandlerService&lt;/code&gt; 之后，Xray 会注册一个 tag 为 &lt;code&gt;api&lt;/code&gt; 的内部出站。所以路由规则里写 &lt;code&gt;&quot;outboundTag&quot;: &quot;api&quot;&lt;/code&gt; 是合法的（不需要显式定义这个出站），dokodemo-door 入站 + 这条规则就是标准的本地管理接口接法。它只监听 &lt;code&gt;127.0.0.1:6765&lt;/code&gt;，公网访问不到。&lt;/p&gt;
&lt;h3&gt;2. 统计与配额&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&quot;stats&quot;: {}&lt;/code&gt;：打开流量统计；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;policy.levels.&quot;0&quot;.statsUserUplink/Downlink&lt;/code&gt;：&lt;strong&gt;按用户分别累计上下行&lt;/strong&gt;——这是订阅流量显示的基础；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;policy.system.statsInbound/Outbound...&lt;/code&gt;：按入站/出站累计。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3. 路由规则&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;protocol: bittorrent&lt;/code&gt; → &lt;code&gt;block&lt;/code&gt;：封 BT；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;inboundTag: xhttp-exit-*&lt;/code&gt; → 对应 &lt;code&gt;landing-*&lt;/code&gt; 出站：&lt;strong&gt;落地节点的核心&lt;/strong&gt;，按入站 tag 分流；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;geoip:cn&lt;/code&gt; → &lt;code&gt;block&lt;/code&gt;（按需，也可以改 &lt;code&gt;direct&lt;/code&gt;）；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;geosite:openai&lt;/code&gt; → &lt;code&gt;direct&lt;/code&gt;：某些场景下 AI 域名走直连；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;geoip:private&lt;/code&gt; → &lt;code&gt;block&lt;/code&gt;：防内网探测。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;domainStrategy: IPIfNonMatch&lt;/code&gt; 表示&quot;域名匹配不上时再解析成 IP 去匹配 IP 规则&quot;。&lt;/p&gt;
&lt;h2&gt;九、特殊出口落地节点&lt;/h2&gt;
&lt;h3&gt;1. 思路&lt;/h3&gt;
&lt;p&gt;每加一个落地，需要同时改 &lt;strong&gt;4 个地方&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;code&gt;xray_conf/VLESS-XHTTP-LANDING.json&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;新增一个 XHTTP 入站（tag = &lt;code&gt;xhttp-exit-a&lt;/code&gt;，path = &lt;code&gt;/xhttp-exit-a&lt;/code&gt;）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;xray.json&lt;/code&gt; outbounds&lt;/td&gt;
&lt;td&gt;新增 socks 出站（tag = &lt;code&gt;landing-exit-a&lt;/code&gt;）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;xray.json&lt;/code&gt; routing&lt;/td&gt;
&lt;td&gt;新增 &lt;code&gt;inboundTag → outboundTag&lt;/code&gt; 规则&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Caddyfile&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;新增 &lt;code&gt;handle /xhttp-exit-a/*&lt;/code&gt; 反代到对应 Unix socket&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sub/config.json&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;landing.sh&lt;/code&gt;，&lt;strong&gt;一条命令改 5 个文件、自动跑 &lt;code&gt;xray -test&lt;/code&gt; 校验，失败自动回滚&lt;/strong&gt;。&lt;/p&gt;
&lt;h3&gt;2. &lt;code&gt;xray_conf/VLESS-XHTTP-LANDING.json&lt;/code&gt; 示例&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;inbounds&quot;: [
    {
      &quot;listen&quot;: &quot;@xray-exit-a.sock&quot;,
      &quot;protocol&quot;: &quot;vless&quot;,
      &quot;tag&quot;: &quot;xhttp-exit-a&quot;,
      &quot;settings&quot;: { &quot;clients&quot;: [], &quot;decryption&quot;: &quot;none&quot; },
      &quot;streamSettings&quot;: {
        &quot;network&quot;: &quot;xhttp&quot;,
        &quot;xhttpSettings&quot;: {
          &quot;host&quot;: &quot;&quot;,
          &quot;path&quot;: &quot;/xhttp-exit-a&quot;,
          &quot;mode&quot;: &quot;auto&quot;,
          &quot;extra&quot;: {
            &quot;noSSEHeader&quot;: true,
            &quot;scMaxEachPostBytes&quot;: 1000000,
            &quot;xPaddingBytes&quot;: &quot;100-1000&quot;
          }
        }
      },
      &quot;sniffing&quot;: { &quot;enabled&quot;: true, &quot;destOverride&quot;: [&quot;http&quot;, &quot;tls&quot;, &quot;quic&quot;] }
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注意落地入站的 &lt;code&gt;clients&lt;/code&gt; 永远是空的——它上面有哪些用户，完全由订阅服务的白名单 + Reconcile 决定。&lt;/p&gt;
&lt;h3&gt;3. &lt;code&gt;landing.sh&lt;/code&gt; 用法&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# 查看所有落地节点、path、出站、订阅显示名，以及白名单
./landing.sh list

# 新增：slug 会派生出 tag/path/socket/outbound 四处命名
./landing.sh add exit-a \
  --server 198.51.100.20 --port 1080 \
  --user &amp;lt;SOCKS_USER&amp;gt; --pass &amp;lt;SOCKS_PASS&amp;gt; \
  --name 落地-A

# 删除
./landing.sh remove exit-a

# 用户白名单（只有名单里的用户，订阅里才会出现落地节点）
./landing.sh allow alice
./landing.sh deny  alice

# 改完统一生效
./deploy.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;slug&lt;/code&gt; 的派生规则（保证四处一致）：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;slug        exit-a
inbound tag xhttp-exit-a
path        /xhttp-exit-a
unix socket @xray-exit-a.sock
socks 出站  landing-exit-a
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;add&lt;/code&gt; / &lt;code&gt;remove&lt;/code&gt; 内部会先快照 4 个文件，改完后调用 &lt;code&gt;xray run -test&lt;/code&gt;；只要校验失败就&lt;strong&gt;整体回滚&lt;/strong&gt;，绝不会把坏配置留在磁盘上。&lt;/p&gt;
&lt;h2&gt;十、订阅服务：用户、流量、白名单&lt;/h2&gt;
&lt;p&gt;订阅服务是一个纯 Go 的小程序（&lt;code&gt;sub/&lt;/code&gt;），职责：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;用 SQLite 存用户（UUID、订阅 token、到期时间、流量上限、已用流量）；&lt;/li&gt;
&lt;li&gt;通过 &lt;code&gt;xray api adu&lt;/code&gt; 在运行时把用户加进各个入站（不用重启 Xray）；&lt;/li&gt;
&lt;li&gt;定期 &lt;code&gt;statsquery&lt;/code&gt; 拉取每个用户的流量并累加；&lt;/li&gt;
&lt;li&gt;对外提供订阅接口，返回 base64（通用）或 Clash YAML，并在响应头里回传流量信息。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;1. &lt;code&gt;sub/config.json&lt;/code&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;listen&quot;: &quot;127.0.0.1:8080&quot;,
  &quot;xray_api&quot;: &quot;127.0.0.1:6765&quot;,
  &quot;xray_bin&quot;: &quot;/etc/goodnet/bin/xray&quot;,
  &quot;xray_conf_dir&quot;: &quot;/etc/goodnet/xray_conf&quot;,
  &quot;db_path&quot;: &quot;data/users.db&quot;,
  &quot;admin_token&quot;: &quot;&amp;lt;ADMIN_TOKEN&amp;gt;&quot;,
  &quot;public_host&quot;: &quot;node.example.com&quot;,
  &quot;public_port&quot;: 443,
  &quot;base_url&quot;: &quot;https://node.example.com/sub&quot;,
  &quot;inbounds&quot;: {
    &quot;reality&quot;: &quot;reality-main&quot;,
    &quot;xhttp&quot;: &quot;xhttp-main&quot;
  },
  &quot;reality&quot;: {
    &quot;public_key&quot;: &quot;&amp;lt;REALITY_PUBLIC_KEY&amp;gt;&quot;,
    &quot;short_id&quot;: &quot;0123456789abcdef&quot;,
    &quot;fingerprint&quot;: &quot;chrome&quot;,
    &quot;server_names&quot;: [&quot;node.example.com&quot;]
  },
  &quot;xhttp&quot;: {
    &quot;path&quot;: &quot;/xhttp&quot;,
    &quot;mode&quot;: &quot;auto&quot;
  },
  &quot;landing&quot;: {
    &quot;users&quot;: [&quot;alice&quot;],
    &quot;nodes&quot;: [
      { &quot;name&quot;: &quot;落地-A&quot;, &quot;tag&quot;: &quot;xhttp-exit-a&quot;, &quot;path&quot;: &quot;/xhttp-exit-a&quot;, &quot;host&quot;: &quot;node.example.com&quot;, &quot;mode&quot;: &quot;auto&quot; },
      { &quot;name&quot;: &quot;落地-B&quot;, &quot;tag&quot;: &quot;xhttp-exit-b&quot;, &quot;path&quot;: &quot;/xhttp-exit-b&quot;, &quot;host&quot;: &quot;node.example.com&quot;, &quot;mode&quot;: &quot;auto&quot; }
    ]
  },
  &quot;keep_emails&quot;: [&quot;debug&quot;],
  &quot;traffic_poll_seconds&quot;: 60
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;要点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;inbounds.reality&lt;/code&gt; / &lt;code&gt;inbounds.xhttp&lt;/code&gt; 是&lt;strong&gt;逻辑名 → Xray 入站 tag&lt;/strong&gt; 的映射；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;reality.public_key&lt;/code&gt; 会由 &lt;code&gt;sub validate&lt;/code&gt; 用 &lt;code&gt;xray x25519 -i &amp;lt;私钥&amp;gt;&lt;/code&gt; &lt;strong&gt;反推校验&lt;/strong&gt;，防止公私钥不匹配这种低级错误；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;landing.users&lt;/code&gt; 是落地白名单，空数组表示谁都不能用落地；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;keep_emails&lt;/code&gt; 里的邮箱（比如调试账号 &lt;code&gt;debug&lt;/code&gt;）在 Reconcile 时不会被清理；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;traffic_poll_seconds&lt;/code&gt; 是流量轮询间隔。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2. 用户管理命令&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# 新增用户：30 天后到期、限 100 GiB
./bin/sub user-add -config sub/config.json \
  -name alice -days 30 -limit-gb 100
# 输出会带 UUID 和订阅地址

# 指定到期日
./bin/sub user-add -config sub/config.json -name bob -expire 2027-01-01

# 列出用户（含状态、已用流量、订阅 URL）
./bin/sub user-list -config sub/config.json

# 查某个用户的订阅地址
./bin/sub sub-url -config sub/config.json -name alice

# 删除用户
./bin/sub user-del -config sub/config.json -name alice

# 校验 config.json 与 xray_conf 是否一致
./bin/sub validate -config sub/config.json
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. 流量是怎么统计和展示的&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Xray 侧：&lt;code&gt;policy.levels.&quot;0&quot;.statsUserUplink/Downlink = true&lt;/code&gt; + &lt;code&gt;&quot;stats&quot;: {}&lt;/code&gt;；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;统计项名字形如 &lt;code&gt;user&amp;gt;&amp;gt;&amp;gt;alice&amp;gt;&amp;gt;&amp;gt;traffic&amp;gt;&amp;gt;&amp;gt;uplink&lt;/code&gt;；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;订阅服务每隔 &lt;code&gt;traffic_poll_seconds&lt;/code&gt; 秒执行一次：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;xray api statsquery --server=127.0.0.1:6765 -pattern &quot;user&amp;gt;&amp;gt;&amp;gt;&quot; -reset
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;-reset&lt;/code&gt; 表示&lt;strong&gt;取完清零&lt;/strong&gt;，程序把增量累加进 SQLite（&lt;code&gt;upload&lt;/code&gt; / &lt;code&gt;download&lt;/code&gt;）；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;订阅接口响应头：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Subscription-Userinfo: upload=1234567; download=7654321; total=107374182400; expire=1798761600
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;绝大多数客户端（v2rayN、v2rayNG、Clash/Mihomo、Happ 等）就是靠这个头显示&lt;strong&gt;已用流量 / 总量 / 到期时间&lt;/strong&gt;的。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;4. 运行时增删用户（Reconcile）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;新增用户时，程序调用 Xray 的 AlterInbound，把 client 加进 &lt;code&gt;reality-main&lt;/code&gt; 和 &lt;code&gt;xhttp-main&lt;/code&gt;；只有白名单用户才会被加进 &lt;code&gt;xhttp-exit-*&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;程序启动时会做一次全量 Reconcile：把数据库里&quot;活跃用户&quot;补齐到各入站，同时清理掉不再存在（且不在 &lt;code&gt;keep_emails&lt;/code&gt;）的孤儿用户；&lt;/li&gt;
&lt;li&gt;因此&lt;strong&gt;不要手改 &lt;code&gt;xray_conf&lt;/code&gt; 里的 &lt;code&gt;clients&lt;/code&gt;&lt;/strong&gt;，那只是初始状态。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对应到命令，就是 &lt;code&gt;sub run&lt;/code&gt; 里调用的 &lt;code&gt;xray api adu&lt;/code&gt;（AddUser）和 &lt;code&gt;xray api rmu&lt;/code&gt;（RemoveUser）。&lt;code&gt;adu&lt;/code&gt; 需要一份带 tag 的临时 inbound 描述，tag 是匹配依据，端口字段只是配置解析要求，会被忽略。&lt;/p&gt;
&lt;h3&gt;5. 订阅输出格式&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;GET /sub/&amp;lt;token&amp;gt;&lt;/code&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;默认返回 &lt;strong&gt;base64&lt;/strong&gt; 编码的通用订阅（v2rayN / v2rayNG / Shadowrocket 等）；&lt;/li&gt;
&lt;li&gt;带 &lt;code&gt;?target=clash&lt;/code&gt; 或 User-Agent 含 &lt;code&gt;clash&lt;/code&gt; / &lt;code&gt;mihomo&lt;/code&gt; 时，返回 &lt;strong&gt;Clash/Mihomo YAML&lt;/strong&gt;，其中落地节点会被放进一个 &lt;code&gt;落地节点&lt;/code&gt; 策略组，普通节点放另一个组；&lt;/li&gt;
&lt;li&gt;每个用户的节点是动态生成的：REALITY 节点、普通 XHTTP 节点，白名单用户额外加落地 XHTTP 节点。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;6. 管理 API（需带 token）&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;TOKEN=&apos;&amp;lt;ADMIN_TOKEN&amp;gt;&apos;
BASE=&apos;http://127.0.0.1:8080&apos;

curl -H &quot;X-Admin-Token: $TOKEN&quot; $BASE/admin/users
curl -H &quot;X-Admin-Token: $TOKEN&quot; -X POST $BASE/admin/users \
  -d &apos;{&quot;name&quot;:&quot;carol&quot;,&quot;days&quot;:30,&quot;traffic_limit_gb&quot;:50}&apos;
curl -H &quot;X-Admin-Token: $TOKEN&quot; -X DELETE $BASE/admin/users/3
curl -H &quot;X-Admin-Token: $TOKEN&quot; -X POST $BASE/admin/users/3/rotate-token
curl -H &quot;X-Admin-Token: $TOKEN&quot; -X POST $BASE/admin/reconcile
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;十一、systemd 与一键部署&lt;/h2&gt;
&lt;h3&gt;1. Xray 单元&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;[Unit]
Description=Xray Service
After=network.target nss-lookup.target

[Service]
User=root
ExecStart=/etc/goodnet/bin/xray run -config /etc/goodnet/xray.json -confdir /etc/goodnet/xray_conf
Restart=on-failure
RestartPreventExitStatus=23
LimitNPROC=10000
LimitNOFILE=1000000
RuntimeDirectory=xray
RuntimeDirectoryMode=0755

[Install]
WantedBy=multi-user.target
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;-confdir&lt;/code&gt; 就是拆分配置的关键。&lt;/p&gt;
&lt;h3&gt;2. 订阅服务单元&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;[Unit]
Description=Goodnet Subscription Service
After=network.target xray.service
Wants=xray.service

[Service]
User=root
ExecStart=/etc/goodnet/bin/sub run -config /etc/goodnet/sub/config.json
Restart=on-failure
RestartSec=3
LimitNOFILE=1000000

[Install]
WantedBy=multi-user.target
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. 部署脚本 &lt;code&gt;deploy.sh&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;它做这几件事：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;用 &lt;code&gt;rsync&lt;/code&gt; 把仓库同步到 &lt;code&gt;/etc/goodnet&lt;/code&gt;（&lt;strong&gt;排除 &lt;code&gt;sub/data/&lt;/code&gt;，用户库永不覆盖&lt;/strong&gt;）；&lt;/li&gt;
&lt;li&gt;安装三个 systemd 单元并 &lt;code&gt;daemon-reload&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;校验&lt;/strong&gt;：&lt;code&gt;xray run -test&lt;/code&gt;、&lt;code&gt;caddy validate&lt;/code&gt;、&lt;code&gt;sub validate&lt;/code&gt;，任一失败立即中止——&lt;strong&gt;绝不用坏配置重启&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;计算配置指纹（所有配置文件的 sha256），只有变化或服务未运行时才重启；&lt;/li&gt;
&lt;li&gt;按 &lt;code&gt;caddy → xray → sub&lt;/code&gt; 顺序重启。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;常用参数：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;./deploy.sh              # 同步 + 校验 + 按需重启
./deploy.sh --force      # 强制重启
./deploy.sh --no-restart # 只同步校验
./deploy.sh -n           # dry-run
./deploy.sh --blog       # 顺带编译博客（pnpm build）
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;典型工作流：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;./landing.sh add exit-c --server 198.51.100.22 --port 1080 --user &amp;lt;U&amp;gt; --pass &amp;lt;P&amp;gt; --name 落地-C
./deploy.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;十二、客户端&lt;/h2&gt;
&lt;h3&gt;1. 通用订阅&lt;/h3&gt;
&lt;p&gt;把 &lt;code&gt;sub-url&lt;/code&gt; 输出的链接导入客户端即可，客户端会自动解析出所有节点，并读取流量信息。&lt;/p&gt;
&lt;h3&gt;2. 手动配置时各个字段对应关系&lt;/h3&gt;
&lt;p&gt;REALITY 节点：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;地址:   node.example.com
端口:   443
UUID:   &amp;lt;用户 UUID&amp;gt;
流控:   xtls-rprx-vision
传输:   tcp
安全:   reality
SNI:    node.example.com
Fingerprint: chrome
PublicKey:   &amp;lt;REALITY_PUBLIC_KEY&amp;gt;
ShortId:     0123456789abcdef
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;XHTTP 节点：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;地址:   node.example.com
端口:   443
UUID:   &amp;lt;用户 UUID&amp;gt;
传输:   xhttp
安全:   tls
SNI:    node.example.com
Host:   node.example.com
Path:   /xhttp
mode:   auto
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;落地节点：和 XHTTP 节点完全一样，只是 &lt;code&gt;Path&lt;/code&gt; 换成 &lt;code&gt;/xhttp-exit-a&lt;/code&gt;。&lt;/p&gt;
&lt;h3&gt;3. Clash / Mihomo&lt;/h3&gt;
&lt;p&gt;订阅 URL 加 &lt;code&gt;?target=clash&lt;/code&gt;，或让客户端 UA 包含 &lt;code&gt;clash&lt;/code&gt; / &lt;code&gt;mihomo&lt;/code&gt;，就会返回完整 YAML（含 &lt;code&gt;规则&lt;/code&gt;、&lt;code&gt;rule-providers&lt;/code&gt;、TUN、DNS 等）。落地节点会出现在 &lt;code&gt;落地节点&lt;/code&gt; 策略组里。&lt;/p&gt;
&lt;h2&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;443 完全不通&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ss -ltnp | grep 443&lt;/code&gt; 看的是 Caddy 还是别人；&lt;code&gt;systemctl status caddy&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;普通浏览器访问域名报证书错误&lt;/td&gt;
&lt;td&gt;REALITY fallback 的 &lt;code&gt;target&lt;/code&gt; 是否等于 Caddy 的 HTTP socket；&lt;code&gt;xver&lt;/code&gt; 是否为 2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;REALITY 能连、XHTTP 连不上&lt;/td&gt;
&lt;td&gt;Caddy 里 &lt;code&gt;/xhttp&lt;/code&gt; 与 &lt;code&gt;/xhttp/*&lt;/code&gt; 两个 handle 是否齐全；&lt;code&gt;flush_interval&lt;/code&gt; 是否 &lt;code&gt;-1&lt;/code&gt;；&lt;code&gt;versions 2&lt;/code&gt; 是否加了&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;一改就全挂&lt;/td&gt;
&lt;td&gt;别跳过 &lt;code&gt;deploy.sh&lt;/code&gt; 的校验；手改配置后先 &lt;code&gt;xray run -test&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;订阅有节点但连不上&lt;/td&gt;
&lt;td&gt;用 &lt;code&gt;bin/sub user-list&lt;/code&gt; 看用户是否 active；到 Xray 上 &lt;code&gt;xray api inbounduser --server=127.0.0.1:6765 -tag=reality-main&lt;/code&gt; 看用户是否真在里面&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;流量一直显示 0&lt;/td&gt;
&lt;td&gt;检查 &lt;code&gt;&quot;stats&quot;: {}&lt;/code&gt;、&lt;code&gt;policy.levels.&quot;0&quot;.statsUserUplink/Downlink&lt;/code&gt;、以及客户端 email 是否等于用户名&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;落地节点不出现&lt;/td&gt;
&lt;td&gt;该用户是否在 &lt;code&gt;landing.users&lt;/code&gt; 白名单；&lt;code&gt;landing.nodes&lt;/code&gt; 是否配了 &lt;code&gt;path&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;删了用户还在&lt;/td&gt;
&lt;td&gt;Reconcile 会清理，但 &lt;code&gt;keep_emails&lt;/code&gt; 里的不会被清；或手动 &lt;code&gt;POST /admin/reconcile&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;常用诊断命令：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;systemctl status caddy xray sub
journalctl -u xray -n 100 --no-pager
tail -f /var/log/xray/error.log
tail -f /var/log/caddy/access.log      # JSON 格式，含真实客户端 IP
ss -lx | grep uds                       # 看 Unix socket 是否都在
xray api statsquery --server=127.0.0.1:6765 -pattern &quot;&quot; -reset
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;十四、安全清单（也是我脱敏的原因）&lt;/h2&gt;
&lt;p&gt;这篇教程里出现的所有内容都是占位符。真正落地时请注意：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;不要把真实 IP、域名、UUID、REALITY 私钥、shortId、Cloudflare Token、订阅 token、落地 socks 密码贴到任何公开地方&lt;/strong&gt;，包括博客、GitHub、群聊截图；&lt;/li&gt;
&lt;li&gt;REALITY 私钥只存在服务端配置里，&lt;strong&gt;下发给客户端的永远只有公钥&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sub/config.json&lt;/code&gt;（含 &lt;code&gt;admin_token&lt;/code&gt;）和 &lt;code&gt;caddy.service&lt;/code&gt;（含 CF Token）都要 &lt;code&gt;chmod 600&lt;/code&gt;；更推荐把 Token 放独立的 &lt;code&gt;EnvironmentFile&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;管理 API 只监听 &lt;code&gt;127.0.0.1&lt;/code&gt;，不要暴露到公网；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sub/data/users.db&lt;/code&gt; 是唯一存量的用户数据，&lt;code&gt;deploy.sh&lt;/code&gt; 要排除它，备份时别漏；&lt;/li&gt;
&lt;li&gt;定期轮换：订阅 token（&lt;code&gt;rotate-token&lt;/code&gt;）、落地 socks 密码、Cloudflare Token；&lt;/li&gt;
&lt;li&gt;出口的 &lt;code&gt;geoip:cn&lt;/code&gt; 规则按自己的合规与使用场景决定，别盲目照抄。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;小结&lt;/h2&gt;
&lt;p&gt;整套系统的分工非常清晰：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Caddy&lt;/strong&gt;：唯一入口，TLS + 路径分流 + 静态站；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Xray&lt;/strong&gt;：REALITY / XHTTP / 落地分流 + 流量统计；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;sub&lt;/strong&gt;：用户、订阅、配额、流量显示；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;landing.sh / deploy.sh&lt;/strong&gt;：把&quot;配置一致性&quot;和&quot;部署安全&quot;用脚本固化下来。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;最值得借鉴的其实是最后一点：&lt;strong&gt;能用脚本保证一致性的地方，就不要靠人肉记忆&lt;/strong&gt;。落地节点要在 5 个文件里保持命名一致，&lt;code&gt;landing.sh&lt;/code&gt; 一条命令搞定还能自动校验回滚；配置上线前必须过 &lt;code&gt;deploy.sh&lt;/code&gt; 的三重校验，永远不带着坏配置重启。&lt;/p&gt;
&lt;p&gt;需要的人照着上面的顺序搭一遍即可。记住把所有占位符换成自己的，然后——&lt;strong&gt;别把真的贴出来&lt;/strong&gt;。&lt;/p&gt;
</content:encoded><category>折腾</category><category>Xray</category><category>Caddy</category><category>REALITY</category><category>XHTTP</category><category>VLESS</category><category>订阅</category></item><item><title>踩坑记录：apt update 只有腾讯云内网源报 DNS 失败</title><link>https://blog.990915.xyz/posts/%E8%B8%A9%E5%9D%91%E8%AE%B0%E5%BD%95apt-update-%E5%8F%AA%E6%9C%89%E8%85%BE%E8%AE%AF%E4%BA%91%E5%86%85%E7%BD%91%E6%BA%90%E6%8A%A5-dns-%E5%A4%B1%E8%B4%A5/</link><guid isPermaLink="true">https://blog.990915.xyz/posts/%E8%B8%A9%E5%9D%91%E8%AE%B0%E5%BD%95apt-update-%E5%8F%AA%E6%9C%89%E8%85%BE%E8%AE%AF%E4%BA%91%E5%86%85%E7%BD%91%E6%BA%90%E6%8A%A5-dns-%E5%A4%B1%E8%B4%A5/</guid><description>腾讯云小鸡上 apt update 只有 mirrors.tencentyun.com 报解析失败，其他源全正常。根因是 mihomo 的 TUN 模式接管了 53 端口查询，上游只有公网 DoH，内网域名必须用 nameserver-policy 指回 VPC DNS。</description><pubDate>Wed, 30 Sep 2026 01:17:07 GMT</pubDate><content:encoded>&lt;h2&gt;症状&lt;/h2&gt;
&lt;p&gt;小鸡上随手跑了个 &lt;code&gt;apt update&lt;/code&gt;，结果很诡异：&lt;strong&gt;只有一个源报错，其他源全正常。&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Err:1 http://mirrors.tencentyun.com/ubuntu jammy InRelease
  Could not resolve &apos;mirrors.tencentyun.com&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;换成 &lt;code&gt;archive.ubuntu.com&lt;/code&gt;、&lt;code&gt;mirrors.aliyun.com&lt;/code&gt; 之类的公网源，或者去 ping 别的东西，一切正常。也就是说网络是通的，&lt;strong&gt;只有这一个内网镜像域名解析不了&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;h2&gt;根因&lt;/h2&gt;
&lt;p&gt;本机跑着 mihomo，开了 &lt;strong&gt;TUN 模式&lt;/strong&gt;。TUN 一开，它会接管本机所有的 &lt;code&gt;:53&lt;/code&gt; 请求——你写在 &lt;code&gt;/etc/resolv.conf&lt;/code&gt; 里的 DNS 根本不会被用到，实际查询统一交给 mihomo 配置里的&lt;strong&gt;上游 DNS&lt;/strong&gt;，而我的上游全是公网 DNS（DoH、&lt;code&gt;1.1.1.1&lt;/code&gt;）。&lt;/p&gt;
&lt;p&gt;问题就出在这里：&lt;code&gt;mirrors.tencentyun.com&lt;/code&gt; 是&lt;strong&gt;腾讯云内网专属的镜像域名&lt;/strong&gt;，它只能由 VPC 内部 DNS 解析：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;183.60.83.19 / 183.60.82.98
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;拿 &lt;code&gt;1.1.1.1&lt;/code&gt; 去问一个只在内网存在的域名，结果可想而知——公网 DNS 根本不认识它，直接解析失败。&lt;/p&gt;
&lt;h2&gt;踩的第一个坑：fake-ip-filter 不管用&lt;/h2&gt;
&lt;p&gt;第一反应是「既然走了 fake-ip，把这个域名排除掉不就行了」，于是往 &lt;code&gt;fake-ip-filter&lt;/code&gt; 里加：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dns:
  fake-ip-filter:
    - &apos;mirrors.tencentyun.com&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;不管用。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;原因很简单：&lt;code&gt;fake-ip-filter&lt;/code&gt; 只决定「这个域名要不要返回假 IP」，它管的是&lt;strong&gt;返回什么地址&lt;/strong&gt;，压根不决定&lt;strong&gt;用哪个上游 DNS 去查&lt;/strong&gt;。域名该发给 &lt;code&gt;1.1.1.1&lt;/code&gt; 还是发给别的上游，跟这个开关没半点关系。&lt;/p&gt;
&lt;h2&gt;正解：nameserver-policy 显式指定上游&lt;/h2&gt;
&lt;p&gt;真正要改的是「谁来解析这个域名」。补上 &lt;code&gt;nameserver-policy&lt;/code&gt;，把它指回 VPC DNS：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dns:
  nameserver-policy:
    &apos;+.mirrors.tencentyun.com&apos;: [&apos;183.60.83.19&apos;, &apos;183.60.82.98&apos;]
    # 其它内网域名同理，按需追加
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;热重载之后验证一下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ dig +short mirrors.tencentyun.com
169.254.0.3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;169.254.0.3&lt;/code&gt; 是 mihomo 发给应用的 fake-ip（真实解析已经在 VPC DNS 那边完成，连接时由 TUN 层还原成真实地址），不影响使用。&lt;/p&gt;
&lt;p&gt;再跑一次 &lt;code&gt;apt update&lt;/code&gt;，&lt;strong&gt;秒恢复&lt;/strong&gt;。&lt;/p&gt;
&lt;h2&gt;教训&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;TUN 模式下 DHCP 下发的内网 DNS 形同虚设。&lt;/strong&gt; 系统所有 &lt;code&gt;:53&lt;/code&gt; 都被 mihomo 接管了，你把 VPC DNS 写在 &lt;code&gt;resolv.conf&lt;/code&gt; 里也白搭。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;内网域名必须显式配解析策略。&lt;/strong&gt; 不管是腾讯云的 &lt;code&gt;mirrors.tencentyun.com&lt;/code&gt;，还是企业内网、私有服务的域名，只要它只有内网 DNS 认识，就得用 &lt;code&gt;nameserver-policy&lt;/code&gt; 把上游指回内网 DNS，否则一律按公网查，必然失败。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;分清 &lt;code&gt;fake-ip-filter&lt;/code&gt; 和 &lt;code&gt;nameserver-policy&lt;/code&gt; 的分工：&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;fake-ip-filter&lt;/code&gt; —— 决定「返回真 IP 还是假 IP」；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nameserver-policy&lt;/code&gt; —— 决定「用哪个上游 DNS 去解析」。&lt;/li&gt;
&lt;li&gt;DNS 解析不通的问题，要改的通常是&lt;strong&gt;后者&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一个小配置项的错位，折腾了大半天。记下来，给后来的自己踩坑用。&lt;/p&gt;
</content:encoded><category>折腾</category><category>mihomo</category><category>Clash</category><category>DNS</category><category>腾讯云</category><category>Linux</category></item><item><title>这几个GitHub项目真给劲儿！AI能打工赚钱，还能帮你筛新闻</title><link>https://blog.990915.xyz/posts/%E8%BF%99%E5%87%A0%E4%B8%AAgithub%E9%A1%B9%E7%9B%AE%E7%9C%9F%E7%BB%99%E5%8A%B2%E5%84%BFai%E8%83%BD%E6%89%93%E5%B7%A5%E8%B5%9A%E9%92%B1%E8%BF%98%E8%83%BD%E5%B8%AE%E4%BD%A0%E7%AD%9B%E6%96%B0%E9%97%BB/</link><guid isPermaLink="true">https://blog.990915.xyz/posts/%E8%BF%99%E5%87%A0%E4%B8%AAgithub%E9%A1%B9%E7%9B%AE%E7%9C%9F%E7%BB%99%E5%8A%B2%E5%84%BFai%E8%83%BD%E6%89%93%E5%B7%A5%E8%B5%9A%E9%92%B1%E8%BF%98%E8%83%BD%E5%B8%AE%E4%BD%A0%E7%AD%9B%E6%96%B0%E9%97%BB/</guid><description>老王整理的 GitHub 项目合集：20K+ Star 的 awesome-openclaw-skills 技能清单、让 AI 拿 10 美元本金接单赚钱的 ClawWork、Cookie 只存本地的 Agent-Reach，以及按四种频率汇总新闻的 ClawFeed。</description><pubDate>Mon, 02 Mar 2026 17:56:40 GMT</pubDate><content:encoded>&lt;p&gt;老王最近在GitHub上冲浪，发现了几个有意思的项目，&lt;strong&gt;从AI打工仔到知识管理再到信息筛选&lt;/strong&gt;，覆盖面还挺广。&lt;/p&gt;
&lt;p&gt;废话不多说，直接上干货。&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;h3&gt;一、技能太多不会选？这个清单帮你搞定&lt;/h3&gt;
&lt;p&gt;如果你刚接触OpenClaw（俗称&quot;小龙虾&quot;），最大的困惑就是：&lt;strong&gt;技能这么多，到底该装哪个？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://socialify.git.ci/VoltAgent/awesome-openclaw-skills/image?description=1&amp;amp;font=Inter&amp;amp;language=1&amp;amp;name=1&amp;amp;owner=1&amp;amp;pattern=Plus&amp;amp;stargazers=1&amp;amp;theme=Auto&quot; alt=&quot;awesome-openclaw-skills&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;VoltAgent/awesome-openclaw-skills&lt;/strong&gt; 这个仓库解决了这个痛点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;20K+ Stars&lt;/strong&gt;，已经成了新手必收藏的&quot;技能地图&quot;&lt;/li&gt;
&lt;li&gt;按场景分类：日程管理、写作整理、开发辅助、桌面自动化、信息检索…&lt;/li&gt;
&lt;li&gt;配合 &lt;strong&gt;ClawHub&lt;/strong&gt; 使用：awesome找方向 → ClawHub安装&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;使用流程：&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;先问自己：我想让AI帮我干什么？（只选1-2个场景）&lt;/li&gt;
&lt;li&gt;去awesome清单找对应分类，挑2-3个候选&lt;/li&gt;
&lt;li&gt;做&quot;30秒体检&quot;：要不要API Key？会不会读写文件？&lt;/li&gt;
&lt;li&gt;去ClawHub用CLI安装：&lt;code&gt;clawhub install &amp;lt;skill-slug&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;安全提醒&lt;/strong&gt;：awesome是目录不是安全背书，安装前看仔细权限要求。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;二、4个最近很火的GitHub项目&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;1. ClawWork - AI打工赚钱 🆕&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;港大开源的项目，让AI自己出去接单子赚钱。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每个AI只有&lt;strong&gt;10美元启动资金&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;调用LLM要扣费，必须干活才能活下去&lt;/li&gt;
&lt;li&gt;涵盖&lt;strong&gt;220个真实职业任务&lt;/strong&gt;，44个经济领域&lt;/li&gt;
&lt;li&gt;顶级AI每小时可赚&lt;strong&gt;1500美元以上&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://socialify.git.ci/HKUDS/ClawWork/image?description=1&amp;amp;font=Inter&amp;amp;language=1&amp;amp;name=1&amp;amp;owner=1&amp;amp;pattern=Plus&amp;amp;stargazers=1&amp;amp;theme=Auto&quot; alt=&quot;ClawWork&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Agent-Reach - 给AI装上互联网能力&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;让Agent能访问各种平台：YouTube、Twitter、Reddit、GitHub、B站、小红书…&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;完全免费&lt;/strong&gt;，Cookie只存本地不上传&lt;/li&gt;
&lt;li&gt;底层工具精选：读网页用Jana Reader，搜内容用Exa AI&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;3. obsidian-skills ⭐ 10K+&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在Obsidian里直接用Claude！&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;正确处理双链、callouts语法，不会把笔记格式搞乱&lt;/li&gt;
&lt;li&gt;AI可以直接在知识库里工作，原地内联编辑&lt;/li&gt;
&lt;li&gt;零外部依赖，完全本地友好&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;4. ClawFeed - AI新闻摘要&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;口号是&quot;Stop scrolling, Start knowing&quot;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;从Twitter、RSS、HackerNews、Reddit、GitHub Trending抓取&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;4小时/每日/每周/每月&lt;/strong&gt;四种频率&lt;/li&gt;
&lt;li&gt;Source Packs功能可以把精选信息源打包分享&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;三、总结&lt;/h3&gt;
&lt;p&gt;AI正在从&quot;帮你干活&quot;变成&quot;自己干活&quot;。&lt;/p&gt;
&lt;p&gt;与其焦虑，不如先挑几个顺手的工具用起来。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;你用过哪个项目？评论区聊聊 🚀&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- 正文内容 --&amp;gt;&lt;/p&gt;
</content:encoded><category>AI</category><category>OpenClaw</category><category>AI Agent</category><category>GitHub</category><category>开源</category></item><item><title>3个OpenClaw变体的自动化Bot开源项目</title><link>https://blog.990915.xyz/posts/3%E4%B8%AAopenclaw%E5%8F%98%E4%BD%93%E7%9A%84%E8%87%AA%E5%8A%A8%E5%8C%96bot%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE/</link><guid isPermaLink="true">https://blog.990915.xyz/posts/3%E4%B8%AAopenclaw%E5%8F%98%E4%BD%93%E7%9A%84%E8%87%AA%E5%8A%A8%E5%8C%96bot%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE/</guid><description>GitHub 上三款 OpenClaw 变体的自动化 Bot 项目：19k Star 的 Python 版 nanobot、4.5k Star 的 Rust 版 zeroclaw，与 8.6k Star、接入 Anthropic Agents SDK 的容器化 nanoclaw。</description><pubDate>Fri, 20 Feb 2026 02:41:10 GMT</pubDate><content:encoded>&lt;p&gt;最近在 GitHub 上发现了一波 类似OpenClaw的 自动化工具，关注度挺高的，今天分享出来。这些项目能让你的 Bot 变得超级智能，自动回复、消息管理、任务调度，统统不在话下。&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;h2&gt;01 轻量级 Python Bot 框架&lt;/h2&gt;
&lt;p&gt;这个叫 &lt;strong&gt;nanobot&lt;/strong&gt; 的开源项目是 OpenClaw 的 Python 轻量版，只有 19k+ 的 Star，人气相当高。它让你可以在 Channel等channel上实现聊天机器人功能，支持消息自动回复、群管理这些常用操作。&lt;/p&gt;
&lt;p&gt;说白了就是一个&lt;strong&gt;极简化的 OpenClaw Bot 框架&lt;/strong&gt;（简单到暂时不堪大用的情况），代码结构清晰，依赖少，安装和部署都特别省心。对于想要快速搭建 Bot 机器人的开发者来说，这玩意儿部署快，也容易根据自己的想法扩展。它基于 Python 实现，生态丰富，你可以轻松接入各种 AI 能力。&lt;/p&gt;
&lt;p&gt;适合想要在 各类Channels 上做自动化、客服机器人或者群管理工具的开发者。安装也很简单，直接 pip install 就能跑起来。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://socialify.git.ci/HKUDS/nanobot/image?description=1&amp;amp;font=Inter&amp;amp;language=1&amp;amp;name=1&amp;amp;owner=1&amp;amp;pattern=Plus&amp;amp;stargazers=1&amp;amp;theme=Auto&quot; alt=&quot;nanobot 项目在 GitHub 上的卡片&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;开源地址：https://github.com/HKUDS/nanobot
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;02 Rust 重写的 Channel Bot 方案&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;zeroclaw&lt;/strong&gt; 是用 Rust 重写的 Bot 自动化工具，4.5k+ Star。Rust 的性能优势在这里体现得淋漓尽致——&lt;strong&gt;内存安全、运行效率高&lt;/strong&gt;，特别适合需要长期运行的后端服务。&lt;/p&gt;
&lt;p&gt;这个项目口号是&quot;claw done right&quot;，定位很明确，就是要做一个更现代、更高效的 WhatsBot 解决方案。如果你之前被 Python 版本的资源占用困扰过，Rust 版绝对值得一试。它的架构设计也更模块化，扩展性很强。&lt;/p&gt;
&lt;p&gt;对于追求性能和稳定性的开发者，这个项目应该很对胃口。Rust 的生态现在也越来越成熟，部署起来其实没想象中那么复杂。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://socialify.git.ci/zeroclaw-labs/zeroclaw/image?description=1&amp;amp;font=Inter&amp;amp;language=1&amp;amp;name=1&amp;amp;owner=1&amp;amp;pattern=Plus&amp;amp;stargazers=1&amp;amp;theme=Auto&quot; alt=&quot;zeroclaw 项目在 GitHub 上的卡片&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;开源地址：https://github.com/zeroclaw-labs/zeroclaw
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;03 容器化 + AI Agent 的新一代 Bot&lt;/h2&gt;
&lt;p&gt;重点来了，这个 &lt;strong&gt;nanoclaw&lt;/strong&gt; 是目前功能最全的版本，8.6k+ Star。它是一个轻量级的 OpenClaw 替代方案，用 TypeScript 编写，专门为&lt;strong&gt;容器化部署&lt;/strong&gt;设计，安全性直接拉满。&lt;/p&gt;
&lt;p&gt;它最骚的地方在于支持&lt;strong&gt;内存管理&lt;/strong&gt;和&lt;strong&gt;定时任务&lt;/strong&gt;，你可以让它记住之前的对话上下文，还能定时执行自动化操作。更离谱的是，它直接接入了 &lt;strong&gt;Anthropic 的 Agents SDK&lt;/strong&gt;，意味着你可以把 Claude AI 能力无缝集成到 Agent 里。&lt;/p&gt;
&lt;p&gt;想象一下，你的 Channel 账号背后跑着一个 AI Agent，能理解对话内容、自动处理任务，这不妥妥的私人助理吗？&lt;/p&gt;
&lt;p&gt;安装使用也很方便，直接用 Docker 跑就行（不过，适用于macos，windows和linux我感觉都差点意思）：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;开源地址：https://github.com/qwibitai/nanoclaw
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果你在做 Channel 相关的 AI 应用，或者想要一个带记忆功能的智能助手，这个项目值得认真看一眼。它把容器安全、AI 能力、自动化任务这几个热门点都整合在一起了，属于那种「哇塞还能这样」的项目。&lt;/p&gt;
</content:encoded><category>AI</category><category>OpenClaw</category><category>Bot</category><category>Rust</category><category>开源</category></item><item><title>1panel备份恢复空间不够用怎么办</title><link>https://blog.990915.xyz/posts/1panel%E5%A4%87%E4%BB%BD%E6%81%A2%E5%A4%8D%E7%A9%BA%E9%97%B4%E4%B8%8D%E5%A4%9F%E7%94%A8%E6%80%8E%E4%B9%88%E5%8A%9E/</link><guid isPermaLink="true">https://blog.990915.xyz/posts/1panel%E5%A4%87%E4%BB%BD%E6%81%A2%E5%A4%8D%E7%A9%BA%E9%97%B4%E4%B8%8D%E5%A4%9F%E7%94%A8%E6%80%8E%E4%B9%88%E5%8A%9E/</guid><description>1Panel 快照有 12G，要恢复到 40G 的小鸡上，恢复时反复复制文件导致空间死活不够。本文用 tar 只抽出 1panel_data.tar.gz，再从快照里删掉它并重新 gzip，让快照瘦身到能恢复，附完整命令。</description><pubDate>Mon, 09 Feb 2026 17:17:14 GMT</pubDate><content:encoded>&lt;h2&gt;先说说背景&lt;/h2&gt;
&lt;p&gt;之间的小鸡有70G,1panel搭建了不少程序网站,导致最后生成的备份快照有点大(12G左右).&lt;/p&gt;
&lt;p&gt;大空间的小鸡到期了,所以需要把快照恢复到一台更小的40G空间的小鸡上.&lt;/p&gt;
&lt;p&gt;问题出现了,也不知道1panel快照的恢复流程是啥样的,看目录似乎有checkout fallback机制,文件复制过去复制过来,导致空间死活不够.&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;p&gt;所以想着,能不能不备份的快照弄小一点,反正恢复过后,所有程序都需要重建.&lt;/p&gt;
&lt;p&gt;因此,就需要对快照这个压缩文件做文章.我发现1panel的快照文件中数据文件是单独压缩的.&lt;/p&gt;
&lt;p&gt;所以只需要将1panel_data.tar.gz这个文件提取出来就行.&lt;/p&gt;
&lt;h2&gt;步骤&lt;/h2&gt;
&lt;h3&gt;第一步,把1panel_data.tar.gz提取出来&lt;/h3&gt;
&lt;p&gt;直接上命令,用tar命令只把1panel_data.tar.gz解压出来.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;tar xvzf 快照文件.tar.gz ./1panel/1panel_data.tar.gz
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如何不确定1panel_data.tar.gz的路径,可以使用以下命令查看压缩包的结构&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;tar tvzf 快照文件.tar.gz
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;第二步,把1panel_data.tar.gz从快照文件中删掉.&lt;/h3&gt;
&lt;p&gt;首先需要把tar.gz转化为tar文件&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gunzip 快照文件.tar.gz
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后当前目录下就有&lt;code&gt;快照文件.tar&lt;/code&gt;了,接着删除&lt;code&gt;快照文件.tar&lt;/code&gt;中的&lt;code&gt;1panel_data.tar.gz&lt;/code&gt;就行&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;tar --delete -vf 快照文件.tar file_to_delete.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;第三步,把&lt;code&gt;快照文件.tar&lt;/code&gt;打包回去&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;gzip 快照文件.tar
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;最后&lt;/h2&gt;
&lt;p&gt;把快照文件.tar.gz放入1panel的快照目录就行,默认在&lt;code&gt;/opt/1panel/backup/system_snapshot/&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;不过也可以从web自己手动选.&lt;/p&gt;
&lt;p&gt;大功告成.
&amp;lt;!-- 正文内容 --&amp;gt;&lt;/p&gt;
</content:encoded><category>折腾</category><category>1Panel</category><category>备份</category><category>服务器</category><category>Linux</category></item><item><title>简单说说Antigravity的食用方式</title><link>https://blog.990915.xyz/posts/%E7%AE%80%E5%8D%95%E8%AF%B4%E8%AF%B4antigravity%E7%9A%84%E9%A3%9F%E7%94%A8%E6%96%B9%E5%BC%8F/</link><guid isPermaLink="true">https://blog.990915.xyz/posts/%E7%AE%80%E5%8D%95%E8%AF%B4%E8%AF%B4antigravity%E7%9A%84%E9%A3%9F%E7%94%A8%E6%96%B9%E5%BC%8F/</guid><description>Google 推出的 AI IDE Antigravity 使用记录，梳理它 VS Code 手感、Gemini 3 驱动代理与三类工作面的定位，并给出用 Clash 的 TUN 模式加进程规则解决登录卡住与断联的配置方法，最后对比 Fast 模式与计划模式的适用场景。</description><pubDate>Thu, 05 Feb 2026 11:24:35 GMT</pubDate><content:encoded>&lt;p&gt;Google推出的AI IDE Antigravity模型挺好用的,有自家的Gemini系列,也有A社的Sonnot,Opus​。用量给的也不错,对于我用来写写科研小代码完全足够​。&lt;/p&gt;
&lt;p&gt;唯一不太友好的就是,大多数朋友,可能在登录界面就卡着进不去了,同时使用的时候也经常断联,影响体验​。&lt;/p&gt;
&lt;p&gt;所以在这里分享一下,我是怎么使用Antigravity的,以及我为什么觉得这个AIIDE还不错​。&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;h2&gt;Antigravity是什么&lt;/h2&gt;
&lt;p&gt;Antigravity = VS Code 的操作手感 + Gemini 3 驱动的 AI 代理 + 三大工作“表面”（编辑器 / 终端 / 浏览器） + 持久化大脑（项目记忆）。​&lt;/p&gt;
&lt;p&gt;它和「在 VS Code 里装一个 Copilot 插件」的区别在于：&lt;/p&gt;
&lt;p&gt;它是整套 IDE 就是围绕 AI 代理设计的（Agent-First），而不是给传统编辑器硬塞个聊天窗口；
它能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;读写所有文件（编辑器 Surface）&lt;/li&gt;
&lt;li&gt;跑命令、装依赖、跑测试（终端 Surface）&lt;/li&gt;
&lt;li&gt;打开一个嵌入式浏览器，看 UI、点按钮、填表单做端到端测试（浏览器 Surface）&lt;/li&gt;
&lt;li&gt;项目里有一个「大脑目录」：​。gemini/antigravity/brain/，用来记住你的项目偏好、架构决策等。(AI查的资料,我平时使用并没有看到这个文件目录)&lt;/li&gt;
&lt;li&gt;所以从定位上，你可以把它当成一个：
​「会写代码、会开终端、会点浏览器、还有记忆的 AI 搭档」​。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;安装:第一口怎么吃&lt;/h2&gt;
&lt;p&gt;安装需要科学的上网环境,这个需要大家自己解决​。(tips:也可以点击阅读原文去找找看有什么发现)&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://xn--antigravity-5d3f.google/&quot;&gt;下载官网&lt;/a&gt;
&lt;img src=&quot;https://blog.990915.xyz/uploads/2026/02/05/antigravity_web.webp&quot; alt=&quot;Google Antigravity 官网首页&quot; /&gt;&lt;/p&gt;
&lt;p&gt;安装完成后启动,界面跟vscode差不多​。有引导界面初始化一些配置​。&lt;/p&gt;
&lt;p&gt;然后使用Google账号登录,当前处于 Public Preview 阶段通常是免费的，后续可能会有订阅收费,类似于其他AI IDE一样.&lt;/p&gt;
&lt;h2&gt;关键:怎么登录&lt;/h2&gt;
&lt;p&gt;如果你完成了上面一步的下载安装,那么我假定你有科学的上网工具.
假定你使用clash类的,可以通过开启tun模式,配合rules来接管Antigravity的流量.&lt;/p&gt;
&lt;p&gt;只需要在&lt;code&gt;rules&lt;/code&gt;里面加上下面两行:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;- PROCESS-NAME,Antigravity.exe,节点名称
- PROCESS-NAME,language_server_windows_x64.exe,节点名称
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;怎么用&lt;/h2&gt;
&lt;p&gt;看模型还能使用Image模型,可以直接生成图片
&lt;img src=&quot;https://blog.990915.xyz/uploads/2026/02/05/antigravity_model_quote.png&quot; alt=&quot;Antigravity 内置的图片生成模型&quot; /&gt;&lt;/p&gt;
&lt;p&gt;这个额度监控面板是用下面这个插件
&lt;img src=&quot;https://blog.990915.xyz/uploads/2026/02/05/image-2.webp&quot; alt=&quot;额度监控插件 Antigravity Cockpit 的页面&quot; /&gt;&lt;/p&gt;
&lt;p&gt;对话支持两种模型,Fast
&lt;img src=&quot;https://blog.990915.xyz/uploads/2026/02/05/image-3.png&quot; alt=&quot;对话中选择 Fast 模型的界面&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;用法1:Fast Mode（快速改动）&lt;/h3&gt;
&lt;p&gt;适用于：小修小改、样式调优、局部逻辑变更。
IDE可以直接在打开的文件中选择需要的上下文.&lt;/p&gt;
&lt;p&gt;使用Edit能直接有个浮窗输入Prompt,使用Chat可以把选择的部分加入右侧聊天框.
&lt;img src=&quot;https://blog.990915.xyz/uploads/2026/02/05/image-4.png&quot; alt=&quot;使用 Edit 浮窗输入 Prompt 的界面&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;用法2:计划模式（Planning Mode）&lt;/h3&gt;
&lt;p&gt;适用于：新功能、重构、架构类改动。&lt;/p&gt;
&lt;p&gt;通常情况下,这个模式会生成Plan让你审阅,这个审阅部分我觉得做得挺好的.&lt;/p&gt;
&lt;p&gt;你可以在审阅里面各个部分添加批注:
&lt;img src=&quot;https://blog.990915.xyz/uploads/2026/02/05/image-5.png&quot; alt=&quot;在计划模式中为 Plan 添加批注的界面&quot; /&gt;&lt;/p&gt;
&lt;p&gt;当你批注完成后,点击右上角Review,可以直接提交,或者带Prompt提交.&lt;/p&gt;
&lt;h2&gt;结语&lt;/h2&gt;
&lt;p&gt;上面就是我平时使用觉得不错的地方,可能用得不是特别深入.
&amp;lt;!-- 正文内容 --&amp;gt;&lt;/p&gt;
</content:encoded><category>AI</category><category>Antigravity</category><category>AI Agent</category><category>Clash</category></item><item><title>简单说说R语言做复杂中介</title><link>https://blog.990915.xyz/posts/%E7%AE%80%E5%8D%95%E8%AF%B4%E8%AF%B4r%E8%AF%AD%E8%A8%80%E5%81%9A%E5%A4%8D%E6%9D%82%E4%B8%AD%E4%BB%8B/</link><guid isPermaLink="true">https://blog.990915.xyz/posts/%E7%AE%80%E5%8D%95%E8%AF%B4%E8%AF%B4r%E8%AF%AD%E8%A8%80%E5%81%9A%E5%A4%8D%E6%9D%82%E4%B8%AD%E4%BB%8B/</guid><description>从期刊论文里的复杂中介模型讲起，先回顾简单中介、平行中介、链式中介与有调节的中介，再拆解复杂中介的四步流程，重点说明如何用取最小值、取补集把 QCA 组态结果换算成隶属度并作为回归自变量，附 R 代码示例。</description><pubDate>Thu, 16 Jan 2025 11:53:37 GMT</pubDate><content:encoded>&lt;p&gt;前段时间（好像也挺长时间了），某期刊上的一篇文章引发了比较大的讨论，至少我是刷到了不少视频和文章讲这篇文章。这篇文章将组态分析和回归分析结合了起来，就是这文章名字听着着实唬人，我个人观点，在回归分析里面，就是一个简单、标准的中介。&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;h2&gt;简单中介&lt;/h2&gt;
&lt;p&gt;首先说说简单中介，相对于下面的复杂中介，那么其他的中介，都可以称为简单中介了，比如平行中介，链式中介，有调节的中介。这里放几个画的图&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.990915.xyz/uploads/2025/01/3926808253.png&quot; alt=&quot;标准的一个中介&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.990915.xyz/uploads/2025/01/2246753855.png&quot; alt=&quot;平行中介&quot; /&gt;&lt;img src=&quot;https://blog.990915.xyz/uploads/2025/01/1865646757.png&quot; alt=&quot;链式中介&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.990915.xyz/uploads/2025/01/4183752993.png&quot; alt=&quot;调节中介&quot; /&gt;&lt;/p&gt;
&lt;p&gt;这些中介模型相信大家都比较熟悉了，就不多阐述了。&lt;/p&gt;
&lt;h2&gt;复杂中介&lt;/h2&gt;
&lt;p&gt;通过对原文的一个阅读，可知复杂中介模型是一种融合了组态视角和多种分析方法的研究工具，旨在解决传统线性中介模型在面对复杂系统问题时的局限性。原文阐述的步骤如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;检验 $X_{i} \to m$ 因果链&lt;/strong&gt;：通过完整的QCA分析，探究前因条件 $x_{i}$ 与中介变量 $m$ 的必要和充分两类复杂因果关系，发现驱动 $m$ 的不同组态 $X_{i}$ 。若未发现，则停止分析。此步骤基于整体论视角，利用QCA方法挖掘变量间的复杂关系，突破了传统线性分析的局限，能更好地应对复杂系统中多变量相互依赖的情况。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;赋值组态 $X_{i}$&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;计算案例在组态包含的所有相关条件中的集合隶属度。对于出现的条件，直接使用案例在该条件集合中的隶属度（通过QCA分析中的校准步骤得到）；对于不出现的条件，使用非集运算计算案例在非条件集合中的隶属度（公式为 $\sim x_{j}=1 - x_{j}$ ）。&lt;/li&gt;
&lt;li&gt;计算案例在组态 $X_{i}$ 中的集合隶属度，公式为 $mX_{i}=min(x_{1},\cdots,x_{j})$ ，即案例在组态中的隶属度是其在所有相关条件集合中隶属度的最小值。通过这一系列运算，将QCA结果转换为回归分析的自变量，为后续混合分析做准备。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;检验 $x \to y$ 因果链&lt;/strong&gt;：通过回归分析，检验驱动 $m$ 的不同组态 $X$ （自变量）与因变量 $y$ 的平均效应关系（$y = cX_{i}+e_{1}$ ），分析自变量 $X_{i}$ 对因变量的总效应 $c$ 。此步骤基于还原论视角，分析近似独立子系统层面的简单关系，与前一步骤的整体论分析形成互补，共同构建起复杂中介模型的分析框架。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;检验 $m \to y$ 因果链&lt;/strong&gt;：通过回归分析，检验控制自变量（组态 $X$ ）时，中介变量 $m$ 与因变量 $y$ 的平均效应关系（$y = c&apos;X_{i}+bm + e_{3}$ ）。若系数 $b$ 显著，则说明 $m$ 显著影响 $y$ ，表明组态 $X_{i}$ 通过 $m$ 影响 $y$ 的间接效应存在，即 $X_{i} \to m \to y$ 的复杂中介效应存在。进一步可通过观察系数 $c&apos;$ 判断是否存在直接效应。同时，为避免组态相关导致的多重共线性问题，可将不同组态视为自变量，依次进行独立的回归分析。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;同样的，也放个图：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.990915.xyz/uploads/2025/01/2362477708.jpeg&quot; alt=&quot;复杂中介&quot; /&gt;&lt;/p&gt;
&lt;p&gt;这里面的关键步骤就是组态的结果如何变成一个自变量，也就是第二步，赋值组态$X_i$，因为qca组态分析已经有很多资料了，大家可以自行查询一下，而回归，或者说中介，大家也十分熟悉了。&lt;/p&gt;
&lt;p&gt;我们先来了解一下组态的结果是什么类型的、组态的结果有一个条件集合，如下面的&lt;code&gt;x1*x3*x4&lt;/code&gt;是一个集合，并且每个样本在每个指标下面都有个隶属度。画一个表格来帮助理解一下：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ID&lt;/th&gt;
&lt;th&gt;x1&lt;/th&gt;
&lt;th&gt;x2&lt;/th&gt;
&lt;th&gt;x3&lt;/th&gt;
&lt;th&gt;x4&lt;/th&gt;
&lt;th&gt;x5&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;0.2&lt;/td&gt;
&lt;td&gt;0.3&lt;/td&gt;
&lt;td&gt;0.9&lt;/td&gt;
&lt;td&gt;0.3&lt;/td&gt;
&lt;td&gt;0.5&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;上面就是样本1对于每个指标的隶属度
在计算样本对于条件组态的隶属度之前，我们需要了解组态集合之间的运算关系：
OR关系(*)：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;取最小值原则&lt;/li&gt;
&lt;li&gt;隶属度 = MIN(条件A的隶属度, 条件B的隶属度)&lt;/li&gt;
&lt;li&gt;例如:如果A=0.8, B=0.6,则A*B=0.6&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;AND关系(+):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;取最大值原则&lt;/li&gt;
&lt;li&gt;隶属度 = MAX(条件A的隶属度, 条件B的隶属度)&lt;/li&gt;
&lt;li&gt;例如:如果A=0.8, B=0.6,则A+B=0.8&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;NOT关系(~):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;取补集&lt;/li&gt;
&lt;li&gt;隶属度 = 1 - 原隶属度&lt;/li&gt;
&lt;li&gt;例如:如果A=0.8,则~A=0.2
现在样本1对于条件组态&lt;code&gt;x1*x3*x4&lt;/code&gt;的隶属度计算就是在x1,x2,x4中区最小值，因为组态&lt;code&gt;x1*x3*x4&lt;/code&gt;里面的逻辑计算都是OR关系，即取最小值。&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ID&lt;/th&gt;
&lt;th&gt;x1&lt;/th&gt;
&lt;th&gt;x2&lt;/th&gt;
&lt;th&gt;x3&lt;/th&gt;
&lt;th&gt;x4&lt;/th&gt;
&lt;th&gt;x5&lt;/th&gt;
&lt;th&gt;x1*x3*x4&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;0.2&lt;/td&gt;
&lt;td&gt;0.3&lt;/td&gt;
&lt;td&gt;0.9&lt;/td&gt;
&lt;td&gt;0.3&lt;/td&gt;
&lt;td&gt;0.5&lt;/td&gt;
&lt;td&gt;0.2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;假设现在样本1对组态&lt;code&gt;x1*~x2*~x3*x6 &lt;/code&gt;又该怎么计算嘞，一步步来。我们将组态翻译一下：
&lt;code&gt;(x1正常取)*(x2取补集)*(x3取补集)*(x6正常取)=(x1)*(1-x2)*(1-x3)*(x6)&lt;/code&gt;，那么，现在就跟刚才的情况一样了。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ID&lt;/th&gt;
&lt;th&gt;x1&lt;/th&gt;
&lt;th&gt;x2&lt;/th&gt;
&lt;th&gt;x3&lt;/th&gt;
&lt;th&gt;x4&lt;/th&gt;
&lt;th&gt;x5&lt;/th&gt;
&lt;th&gt;x1*x3*x4&lt;/th&gt;
&lt;th&gt;x1*~x2*~x3*x5&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;0.2&lt;/td&gt;
&lt;td&gt;0.3&lt;/td&gt;
&lt;td&gt;0.4&lt;/td&gt;
&lt;td&gt;0.3&lt;/td&gt;
&lt;td&gt;0.5&lt;/td&gt;
&lt;td&gt;(0.2)*(0.3)*(0.3)=0.2&lt;/td&gt;
&lt;td&gt;(0.2)*(1-0.9)*(1-0.4)*(0.5)=0.1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;依照这个计算方法，现在每个样本对于每个条件组态都有一个值，那么现在条件组态就可以作为一个自变量了。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;--- COMPLEX SOLUTION ---
frequency cutoff: 1
consistency cutoff: 0.872534
          raw       unique        
          coverage    coverage   consistency 
          ----------  ----------  ----------  
x1*x3*x4      0.642248    0.0403785   0.906484  
x1*~x2*~x3*x5   0.195991    0.0159534   0.962952
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;用R语言完成这一步的代码也很简单，就不多解释了。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;data &amp;lt;- data %&amp;gt;% 
  mutate(
    X1=pmin(x1,x3,x4),
    X2=pmin(x1,1-x2,1-x3,x5),
  )

fit &amp;lt;- lm(y~X7+x1+x2,data=data)
summary(fit)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;将QCA和回归分析结合的复杂中介模型，感觉非常有趣！这种方法不仅能处理传统线性中介模型的局限性，还能更好地分析复杂系统中的中介效应。具体来说，先用QCA检验前因条件和中介变量的因果关系，然后通过赋值组态将其转换为回归分析的自变量，最后用回归分析检验中介效应。整个过程就像搭积木一样，把整体论和还原论的视角巧妙地结合在一起。总的来说，这种分析方式为研究复杂系统中的中介效应提供了新的思路，不得不说，这些大佬真聪明！&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- 正文内容 --&amp;gt;&lt;/p&gt;
</content:encoded><category>科研</category><category>R语言</category><category>中介效应</category><category>QCA</category><category>组态分析</category></item><item><title>用R帮助你完成毕业论文实证的常规流程</title><link>https://blog.990915.xyz/posts/%E7%94%A8r%E5%B8%AE%E5%8A%A9%E4%BD%A0%E5%AE%8C%E6%88%90%E6%AF%95%E4%B8%9A%E8%AE%BA%E6%96%87%E5%AE%9E%E8%AF%81%E7%9A%84%E5%B8%B8%E8%A7%84%E6%B5%81%E7%A8%8B/</link><guid isPermaLink="true">https://blog.990915.xyz/posts/%E7%94%A8r%E5%B8%AE%E5%8A%A9%E4%BD%A0%E5%AE%8C%E6%88%90%E6%AF%95%E4%B8%9A%E8%AE%BA%E6%96%87%E5%AE%9E%E8%AF%81%E7%9A%84%E5%B8%B8%E8%A7%84%E6%B5%81%E7%A8%8B/</guid><description>以问卷类毕业论文的实证流程为主线，介绍 R 语言与 bruceR 包在描述性统计、探索性因子分析、验证性因子分析、路径检验、中介与调节效应中的用法，并给出 CFA 拟合指标与双因子模型检验共同方法偏差的实践建议。</description><pubDate>Wed, 15 Jan 2025 19:09:22 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://blog.990915.xyz/uploads/2025/01/3360827428.webp&quot; alt=&quot;R 语言用于统计计算与数据可视化的示意图&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;R语言介绍&lt;/h2&gt;
&lt;p&gt;R语言是一种专门用于统计计算和图形展示的编程语言。它由Ross Ihaka和Robert Gentleman于1993年开发，广泛应用于数据分析、统计建模和数据可视化领域。R语言的特点包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;开源免费&lt;/strong&gt;：R语言是开源的，用户可以免费使用和修改。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;强大的统计功能&lt;/strong&gt;：R语言内置了大量的统计函数和包，支持从基础统计到高级机器学习算法的实现。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;丰富的图形功能&lt;/strong&gt;：R语言提供了强大的图形系统（如 &lt;code&gt;ggplot2&lt;/code&gt;），可以生成高质量的统计图表。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;活跃的社区支持&lt;/strong&gt;：R语言拥有庞大的用户社区，用户可以轻松找到相关的教程、文档和扩展包。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;h2&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;：对数据进行初步分析，如计算均值、标准差、频率分布等。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;假设检验&lt;/strong&gt;：根据研究问题提出假设，并进行统计检验（如t检验、卡方检验等）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;回归分析&lt;/strong&gt;：探索变量之间的关系，如线性回归、逻辑回归等。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;模型评估&lt;/strong&gt;：对统计模型的拟合效果进行评估，如R²、AIC等指标。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;结果可视化&lt;/strong&gt;：通过图表展示分析结果，如散点图、箱线图等。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;描述性统计分析&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;bruceR&lt;/code&gt;是一个R语言包，提供了许多便捷的统计分析函数，其中 &lt;code&gt;Describe&lt;/code&gt;函数可以快速生成描述性统计结果。以下是使用步骤：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;安装并加载 &lt;code&gt;bruceR&lt;/code&gt;包&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;install.packages(&quot;bruceR&quot;)
library(bruceR)
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;加载数据&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;data &amp;lt;- read.csv(&quot;your_data.csv&quot;)  # 替换为你的数据文件路径
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;使用 &lt;code&gt;Describe&lt;/code&gt;函数&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Describe(data)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;该函数会输出每个变量的描述性统计信息，包括均值、标准差、最小值、最大值等。
&lt;code&gt;Describe&lt;/code&gt;函数的常用参数包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;digits&lt;/strong&gt;：控制输出结果的小数位数。例如，&lt;code&gt;digits = 2&lt;/code&gt;表示保留两位小数。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;na.rm&lt;/strong&gt;：是否忽略缺失值，默认为 &lt;code&gt;TRUE&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;trim&lt;/strong&gt;：用于计算截尾均值，默认为 &lt;code&gt;0&lt;/code&gt;（不截尾）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;check&lt;/strong&gt;：是否检查数据的有效性，默认为 &lt;code&gt;TRUE&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Describe(data, digits = 2)  # 保留两位小数
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;探索性因子分析&lt;/h2&gt;
&lt;p&gt;探索性因子分析一般用来检验题项与因子之间的对应关系，但假若使用经典量表，一般也不报告这部分分析的内容，而是使用验证性因子分析CFA。共同方法偏差的分析一般也可以报告这部分的结果。&lt;/p&gt;
&lt;p&gt;探索性因子分析（EFA）用于检验题项与因子之间的对应关系。以下是使用 &lt;code&gt;bruceR&lt;/code&gt;包的 &lt;code&gt;EFA&lt;/code&gt;函数的步骤：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;安装并加载 &lt;code&gt;bruceR&lt;/code&gt;包&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;install.packages(&quot;bruceR&quot;)
library(bruceR)
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;加载数据&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;data &amp;lt;- read.csv(&quot;your_data.csv&quot;)  # 替换为你的数据文件路径
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;使用 &lt;code&gt;EFA&lt;/code&gt;函数&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;EFA(data, nfactors = 3)  # nfactors指定因子数量
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;该函数会输出因子载荷矩阵、特征值、解释方差等结果。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;验证性因子分析&lt;/h2&gt;
&lt;p&gt;当使用经典量表的时候，这时需要验证量表的有效性，我的理解是这时候经典量表是否适合你的研究模型，或者理解为本地化是否成功。
具体的一些检验指标的概念，大家可以去spssau上面搜索了解，这个平台的帮助手册我觉得十分不错。&lt;/p&gt;
&lt;p&gt;如何开始嘞，这时一般需要跑几个cfa模型，常见的有以你模型为结构标准的基准模型，一因子，二因子，我看见的也有继续做三因子，四因子的，这里做到多少个因子，我的看法是比你基准模型的因子少就行，或者只做到二因子。因为国人常用一个更骚的方法，叫biafactor,双因子模型，似乎也叫ulmc，就是在基准模型上面加一个全局的方法因子来检验共同方法偏差的存在。&lt;/p&gt;
&lt;p&gt;首先，我们来看基准模型可以报告哪些指标。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 生成CFA结果的辅助函数
generate_cfa_result &amp;lt;- function(label, fit) {
   #显示总体结果
   # summary(bifactorfit,fit.measures=&quot;TRUE&quot;)
   #显示所有拟合指数
   # fitMeasures(bifactorfit,fit.measures=&quot;all&quot;,baseline.model=NULL)
  tibble(
    ID = label,
    Chisq = fitMeasures(fit, &quot;chisq&quot;),
    df = fitMeasures(fit, &quot;df&quot;),
    `Chisq/df` = Chisq / df,
    NFI = fitMeasures(fit, &quot;nfi&quot;),
    CFI = fitMeasures(fit, &quot;cfi&quot;),
    IFI = fitMeasures(fit, &quot;ifi&quot;),
    TLI = fitMeasures(fit, &quot;tli&quot;),
    GFI = fitMeasures(fit, &quot;gfi&quot;),
    RMSEA = fitMeasures(fit, &quot;rmsea&quot;),
    SRMR = fitMeasures(fit, &apos;srmr&apos;),
  )
}
&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;Chisq/df&lt;/strong&gt;: 严格[1, 3],宽松[1, 5]&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CFI&lt;/strong&gt;：比较拟合指数，&amp;gt;0.9表示良好拟合。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TLI&lt;/strong&gt;：Tucker-Lewis指数，&amp;gt;0.9表示良好拟合。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RMSEA&lt;/strong&gt;：近似误差均方根，&amp;lt;0.08表示良好拟合。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SRMR&lt;/strong&gt;：标准化残差均方根，&amp;lt;0.08表示良好拟合。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以下是使用 &lt;code&gt;lavaan&lt;/code&gt;包进行验证性因子分析（CFA）的示例：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;安装并加载 &lt;code&gt;lavaan&lt;/code&gt;包&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;install.packages(&quot;lavaan&quot;)
library(lavaan)
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;定义模型&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;model &amp;lt;- &apos;
  # 定义因子
  f1 =~ x1 + x2 + x3  # 自变量1
  f2 =~ x4 + x5 + x6  # 自变量2
  f3 =~ x7 + x8 + x9  # 中介变量
  f4 =~ x10 + x11 + x12  # 调节变量
  f5 =~ x13 + x14 + x15  # 因变量
&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;拟合模型&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;fit &amp;lt;- cfa(model, data = data)
generate_cfa_result(&quot;基准模型&quot;, fit)
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;基准模型里面还有些可以报告的内容，如alpha,ave（区别效度会用到ave平方根）,omega（组合信度？）等等，这些拟合指标可以通过semTools中函数，&lt;code&gt;reliability(fit)&lt;/code&gt;。输出结果类似于这样&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;f1        f2        f3        f4
alpha  0.8852175 0.8853690 0.9030259 0.8903863
omega  0.8983741 0.8981945 0.9177765 0.9044974
omega2 0.8983741 0.8981945 0.9177765 0.9044974
omega3 0.8981426 0.8981986 0.9177723 0.9046049
avevar 0.7521083 0.7515437 0.7934002 0.7649806
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;只不过这个函数不再受支持了，官方文档建议使用compRelSEM，大家可以自行研究一下。
然后，其他一因子，二因子，三因子就是把所有题项想当然划分成两个因子，三个因子，这样模型的拟合肯定不好，不好就对了，才显得你基准模型的优秀不是。&lt;/p&gt;
&lt;p&gt;将基准模型改为二因子模型：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;model_1factor &amp;lt;- &apos;
f1 =~ x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + x14 + x15
&apos;
model_2factor &amp;lt;- &apos;
  f1 =~ x1 + x2 + x3 + x4 + x5 + x6 +x7 + x8  # 因子1
  f2 =~ x9 + x10 + x11 + x12 + x13 + x14 + x15 # 因子2
&apos;
# 三因子同理了

fit_1factor &amp;lt;- cfa(model_1factor, data = data)
fit_2factor &amp;lt;- cfa(model_2factor, data = data)

generate_cfa_result(&quot;一因子&quot;, fit_1factor)
generate_cfa_result(&quot;二因子&quot;, fit_2factor)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;双因子模型的具体内容可以参考我的另外一篇文章，这个模型因为在基准模型上面加了一个全局方法因子，可能导致两种结果，一种是相较于基准模型变好了，另外一种是变坏了，变坏了可以突出你基准模型的优秀，可变好了怎么办嘞。其实，只要不好太多就行，依然表示你基准模型的优秀，但在这里好多少是多，我倒是没看见具体的标准。一般你基准模型的拟合指标过了，这个仅做参考吧，有谁知道可能评论区说说。&lt;/p&gt;
&lt;p&gt;将基准模型改为双因子模型：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;model_bifactor &amp;lt;- &apos;
   f1 =~ x1 + x2 + x3  # 自变量1
   f2 =~ x4 + x5 + x6  # 自变量2
   f3 =~ x7 + x8 + x9  # 中介变量
   f4 =~ x10 + x11 + x12  # 调节变量
   f5 =~ x13 + x14 + x15  # 因变量
   g =~ x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + x14 + x15  # 全局方法因子
&apos;
fit_bifactor &amp;lt;- cfa(model_bifactor, data = data,orthogonal=TRUE)
# 进行CFA，必须加上orthogonal=TRUE，如果不加需要在model里面自己写正交关系
generate_cfa_result(&quot;biafactor&quot;,fit_bifactor)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;路径检验&lt;/h2&gt;
&lt;p&gt;路径检验，就是在验证性因子分析模型的基础上加入回归关系。仅仅是自变量到因变量的回归，别想太多，这里不要设计中介调节啥的。看你的概念模型里面，因子之间的箭头指向（因子之间，不涉及题项），一个箭头就是一个路径（主效应关系一般解释完了）。&lt;/p&gt;
&lt;p&gt;在基准模型上添加回归关系路径：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;model_path &amp;lt;- &apos;
  f1 =~ x1 + x2 + x3  # 自变量1
  f2 =~ x4 + x5 + x6  # 自变量2
  f3 =~ x7 + x8 + x9  # 中介变量
  f4 =~ x10 + x11 + x12  # 调节变量
  f5 =~ x13 + x14 + x15  # 因变量

  # 添加回归关系
  f5 ~ f1 + f2 + f3 + f4
  f3 ~ f1 + f2
&apos;
fit_path &amp;lt;- cfa(model_path, data = data)
generate_cfa_result(&quot;路径检验&quot;,fit_path)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;路径检验的结果我们可能需要报告R^2,内生变量（有箭头指向自己的变量）都可以报告一个R^2，可以通过命令 &lt;code&gt;R2 = lavInspect(fit_path, &quot;rsquare&quot;)&lt;/code&gt;获取R^2&lt;/p&gt;
&lt;h2&gt;中介效应&lt;/h2&gt;
&lt;p&gt;中介效应的分析就更加简单了，bruceR提供了十分友好的PROCESS函数。大家可以看官方文档，比较容易理解的。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PROCESS(
  data,
  y = &quot;&quot;,
  x = &quot;&quot;,
  meds = c(),
  mods = c(),
  covs = c(),
  clusters = c(),
  hlm.re.m = &quot;&quot;,
  hlm.re.y = &quot;&quot;,
  hlm.type = c(&quot;1-1-1&quot;, &quot;2-1-1&quot;, &quot;2-2-1&quot;),
  med.type = c(&quot;parallel&quot;, &quot;serial&quot;),
  mod.type = c(&quot;2-way&quot;, &quot;3-way&quot;),
  mod.path = c(&quot;x-y&quot;, &quot;x-m&quot;, &quot;m-y&quot;, &quot;all&quot;),
  cov.path = c(&quot;y&quot;, &quot;m&quot;, &quot;both&quot;),
  mod1.val = NULL,
  mod2.val = NULL,
  ci = c(&quot;boot&quot;, &quot;bc.boot&quot;, &quot;bca.boot&quot;, &quot;mcmc&quot;),
  nsim = 100,
  seed = NULL,
  center = TRUE,
  std = FALSE,
  digits = 3,
  file = NULL
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;bruceR&lt;/code&gt;包的 &lt;code&gt;PROCESS&lt;/code&gt;函数是一个强大的工具，用于分析中介效应和调节效应。以下是使用 &lt;code&gt;PROCESS&lt;/code&gt;函数进行中介效应检验的示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 安装并加载bruceR包
install.packages(&quot;bruceR&quot;)
library(bruceR)

# 定义变量
y &amp;lt;- &quot;f5&quot;  # 因变量
x &amp;lt;- &quot;f1&quot;  # 自变量
meds &amp;lt;- c(&quot;f3&quot;)  # 中介变量

# 使用PROCESS函数进行中介效应检验
PROCESS(data, y = y, x = x, meds = meds, ci = &quot;boot&quot;, nsim = 1000)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;该函数会输出中介效应的估计值、置信区间以及显著性检验结果。我就不给输出结果了，结果挺易读，友好，大家自己动手跑就挺好。&lt;/p&gt;
&lt;h3&gt;平行中介&lt;/h3&gt;
&lt;p&gt;平行中介是指多个中介变量同时作用于自变量和因变量之间的关系。以下是使用 &lt;code&gt;PROCESS&lt;/code&gt;函数进行平行中介检验的示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 定义变量
y &amp;lt;- &quot;f5&quot;  # 因变量
x &amp;lt;- &quot;f1&quot;  # 自变量
meds &amp;lt;- c(&quot;f3&quot;, &quot;f4&quot;)  # 中介变量

# 使用PROCESS函数进行平行中介检验
PROCESS(data, y = y, x = x, meds = meds, med.type = &quot;parallel&quot;，ci = &quot;boot&quot;, nsim = 1000)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;链式中介&lt;/h3&gt;
&lt;p&gt;链式中介是指中介变量之间存在顺序关系。以下是使用 &lt;code&gt;PROCESS&lt;/code&gt;函数进行链式中介检验的示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 定义变量
y &amp;lt;- &quot;f5&quot;  # 因变量
x &amp;lt;- &quot;f1&quot;  # 自变量
meds &amp;lt;- c(&quot;f2&quot;, &quot;f3&quot;)  # 中介变量

# 使用PROCESS函数进行链式中介检验
PROCESS(data, y = y, x = x, meds = meds, med.type = &quot;serial&quot;, ci = &quot;boot&quot;, nsim = 1000)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;调节效应&lt;/h2&gt;
&lt;p&gt;也是通过 &lt;code&gt;bruceR::PROCESS&lt;/code&gt;函数。不得不说，这个函数真好用。
调节效应是指一个变量影响自变量和因变量之间的关系。以下是使用 &lt;code&gt;PROCESS&lt;/code&gt;函数进行调节效应检验的示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 定义变量
y &amp;lt;- &quot;f5&quot;  # 因变量
x &amp;lt;- &quot;f1&quot;  # 自变量
mods &amp;lt;- c(&quot;f4&quot;)  # 调节变量

# 使用PROCESS函数进行调节效应检验
PROCESS(data, y = y, x = x, mods = mods, ci = &quot;boot&quot;, nsim = 1000)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;有调节的中介&lt;/h3&gt;
&lt;p&gt;有调节的中介效应是指调节变量影响中介效应的强度或方向。以下是使用 &lt;code&gt;PROCESS&lt;/code&gt;函数进行有调节的中介效应检验的示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 定义变量
y &amp;lt;- &quot;f5&quot;  # 因变量
x &amp;lt;- &quot;f1&quot;  # 自变量
meds &amp;lt;- c(&quot;f3&quot;)  # 中介变量
mods &amp;lt;- c(&quot;f4&quot;)  # 调节变量

# 使用PROCESS函数进行有调节的中介效应检验
# 当同时有调节和中介的时候，需要指定调节变量指向的路径，x-y就是主效应的路径
# x-m就是自变量到中介变量的路径,m-y就是中介变量到因变量的路径。假设调节前面两条，那就组合
# x-y和x-m
# mod.path = c(&quot;x-y&quot;, &quot;x-m&quot;, &quot;m-y&quot;, &quot;all&quot;),
PROCESS(data, y = y, x = x, meds = meds, mods = mods, mod.path = c(&quot;x-y&quot;, &quot;x-m&quot;),ci = &quot;boot&quot;, nsim = 1000)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;以上是问卷分析的一个常规流程， 用R语言挺方便的，大家可以尝试一下。&lt;/p&gt;
</content:encoded><category>科研</category><category>R语言</category><category>毕业论文</category><category>实证分析</category><category>结构方程模型</category></item><item><title>AI大模型有效的提示词技巧（一）</title><link>https://blog.990915.xyz/posts/ai%E5%A4%A7%E6%A8%A1%E5%9E%8B%E6%9C%89%E6%95%88%E7%9A%84%E6%8F%90%E7%A4%BA%E8%AF%8D%E6%8A%80%E5%B7%A7%E4%B8%80/</link><guid isPermaLink="true">https://blog.990915.xyz/posts/ai%E5%A4%A7%E6%A8%A1%E5%9E%8B%E6%9C%89%E6%95%88%E7%9A%84%E6%8F%90%E7%A4%BA%E8%AF%8D%E6%8A%80%E5%B7%A7%E4%B8%80/</guid><description>这篇长文整理了八条与大模型对话的实用提示词技巧：从省去客套话、指明目标受众、拆解复杂任务，到示例驱动的少样本提示、结构化分隔与「逐步思考」引导；每条都按价值、注意事项、举例和结论展开，小结里另给出八条甄别技巧价值的原则。</description><pubDate>Sun, 15 Sep 2024 23:04:58 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://blog.990915.xyz/uploads/2024/09/236826549.webp&quot; alt=&quot;骑车穿过林荫大道的插图&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;遇见的一些提示词技巧&lt;/h2&gt;
&lt;h3&gt;技巧1:与大模型交流无需使用礼貌用语，如“请”、“谢谢”等，直接表达需求即可&lt;/h3&gt;
&lt;p&gt;这条技巧有一定的价值,但需要谨慎考虑。&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;h4&gt;价值:&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;简洁性: 去掉礼貌用语可以使prompts更加简洁,直接表达核心需求。&lt;/li&gt;
&lt;li&gt;清晰性: 直接表达需求可以让AI更快理解任务的本质。&lt;/li&gt;
&lt;li&gt;效率: 在某些情况下,更简短的prompts可能会稍微提高处理速度。&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;需要注意的地方:&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;人性化交互: 虽然AI不需要礼貌用语也能正常工作,但使用礼貌用语可以让交互更自然,更接近人类对话。&lt;/li&gt;
&lt;li&gt;习惯培养: 保持礼貌可以培养良好的沟通习惯,这在与真人交流时很重要。&lt;/li&gt;
&lt;li&gt;复杂任务: 对于复杂任务,有时候礼貌用语可以作为语境的一部分,帮助AI更好地理解需求的重要性或紧急程度。&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;举例:&lt;/h4&gt;
&lt;p&gt;直接表达:
&quot;分析2023年第二季度销售报告,列出三个主要发现。&quot;&lt;/p&gt;
&lt;p&gt;带礼貌用语:
&quot;请分析2023年第二季度销售报告,并列出三个主要发现。谢谢!&quot;&lt;/p&gt;
&lt;p&gt;在这个例子中,两种方式都能得到相似的结果。直接表达更简洁,而带礼貌用语的版本可能让交互感觉更自然。&lt;/p&gt;
&lt;h4&gt;结论:&lt;/h4&gt;
&lt;p&gt;这条技巧在技术层面上是有价值的,特别是在追求极度简洁的场景中。但在日常使用中,我建议在直接表达需求和保持基本礼貌之间找到平衡。这样既可以获得清晰有效的回答,又能保持良好的交互体验。&lt;/p&gt;
&lt;h3&gt;技巧2:在提示中指明目标受众，比如说受众是某领域的专家&lt;/h3&gt;
&lt;p&gt;这条技巧确实非常有价值。指明目标受众可以显著提高AI回答的质量和相关性。&lt;/p&gt;
&lt;h4&gt;价值：&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;专业度匹配：指定受众可以让AI调整回答的专业程度，使用适当的术语和概念。&lt;/li&gt;
&lt;li&gt;内容相关性：AI可以根据目标受众的背景知识和兴趣定制内容。&lt;/li&gt;
&lt;li&gt;沟通风格调整：AI可以采用更适合特定受众的语气和表达方式。&lt;/li&gt;
&lt;li&gt;避免解释已知信息：对于专家受众，AI可以跳过基础解释，直接深入核心内容。&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;举例：&lt;/h4&gt;
&lt;p&gt;不指定受众：
&quot;解释DNA复制过程。&quot;&lt;/p&gt;
&lt;p&gt;指定受众（专家）：
&quot;为分子生物学研究生解释DNA复制过程中的复制叉动力学。&quot;&lt;/p&gt;
&lt;p&gt;指定受众（普通人）：
&quot;为高中生解释DNA复制的基本步骤，使用简单的类比。&quot;&lt;/p&gt;
&lt;p&gt;在这个例子中：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对专家的解释会涉及更深入的细节，如复制叉的具体机制、各种酶的作用等。&lt;/li&gt;
&lt;li&gt;对高中生的解释则会使用更基础的术语，可能会用&quot;复印机&quot;或&quot;拉链&quot;等类比来解释过程。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;另一个例子：&lt;/p&gt;
&lt;p&gt;不指定受众：
&quot;描述机器学习在金融中的应用。&quot;&lt;/p&gt;
&lt;p&gt;指定受众（金融专业人士）：
&quot;为对冲基金经理解释如何使用深度学习模型优化投资组合配置。&quot;&lt;/p&gt;
&lt;p&gt;在这个例子中，指定受众为金融专业人士后，AI的回答会更加聚焦于具体的金融应用，使用行业术语，并可能涉及到具体的模型和策略。&lt;/p&gt;
&lt;h4&gt;结论：&lt;/h4&gt;
&lt;p&gt;指明目标受众是一个非常有效的技巧，它能够显著提高AI回答的针对性和实用性。这种方法可以确保你获得的信息不仅准确，而且恰好符合你或你的目标受众的知识水平和需求。在准备演讲、撰写文章或者只是寻求特定深度的信息时，这个技巧尤其有用。&lt;/p&gt;
&lt;h3&gt;技巧3：把复杂任务拆解成一系列简单的提示，以进行交互式对话&lt;/h3&gt;
&lt;p&gt;这条技巧非常有价值，是提高AI交互效果的重要策略。&lt;/p&gt;
&lt;h4&gt;价值：&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;提高准确性：将复杂任务拆解可以让AI更专注于每个小步骤，减少错误和遗漏。&lt;/li&gt;
&lt;li&gt;增强控制力：你可以在每个步骤后检查和调整，确保过程朝着正确的方向发展。&lt;/li&gt;
&lt;li&gt;灵活性：允许根据中间结果调整后续步骤，使整个过程更加动态和适应性强。&lt;/li&gt;
&lt;li&gt;更好的理解：通过逐步推进，你可以更清晰地理解整个过程和AI的思考方式。&lt;/li&gt;
&lt;li&gt;避免上下文限制：防止单个复杂提示超出AI的处理能力或上下文限制。&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;举例：&lt;/h4&gt;
&lt;p&gt;假设你想创建一个综合的营销计划。&lt;/p&gt;
&lt;p&gt;复杂单一提示：
&quot;为一个新的科技创业公司制定完整的营销策略，包括市场分析、目标受众定位、营销渠道选择、预算分配和ROI预测。&quot;&lt;/p&gt;
&lt;p&gt;拆解成一系列简单提示：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&quot;让我们为一个新的科技创业公司制定营销策略。首先，请列出进行市场分析需要考虑的5个关键因素。&quot;&lt;/li&gt;
&lt;li&gt;&quot;好的，基于这些因素，请简要描述我们的目标市场。&quot;&lt;/li&gt;
&lt;li&gt;&quot;现在，让我们确定目标受众。请创建2-3个典型的客户角色。&quot;&lt;/li&gt;
&lt;li&gt;&quot;基于这些客户角色，推荐3-5个最有效的营销渠道。&quot;&lt;/li&gt;
&lt;li&gt;&quot;对于这些营销渠道，请提出一个初步的预算分配方案，假设总预算是10万美元。&quot;&lt;/li&gt;
&lt;li&gt;&quot;最后，请为每个渠道设定一个可衡量的ROI目标。&quot;&lt;/li&gt;
&lt;/ol&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;复杂单一提示：
&quot;写一个3000字的科幻短篇小说，包括人物描述、情节发展和结局。&quot;&lt;/p&gt;
&lt;p&gt;拆解成一系列简单提示：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&quot;让我们一起构思一个科幻短篇小说。首先，请提出3个可能的主要角色，每个角色都有独特的背景和特点。&quot;&lt;/li&gt;
&lt;li&gt;&quot;选择一个角色作为主角。详细描述这个角色的外貌、性格和动机。&quot;&lt;/li&gt;
&lt;li&gt;&quot;现在，让我们设定故事的背景。描述一个未来世界的场景，包括一些科技元素。&quot;&lt;/li&gt;
&lt;li&gt;&quot;基于这个背景，提出一个主角可能面临的主要冲突或挑战。&quot;&lt;/li&gt;
&lt;li&gt;&quot;列出3-5个可能的情节转折点。&quot;&lt;/li&gt;
&lt;li&gt;&quot;选择一个结局。详细描述主角如何解决（或未能解决）面临的挑战。&quot;&lt;/li&gt;
&lt;li&gt;&quot;现在，让我们把所有元素组合起来，写出小说的开头300字。&quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;结论：&lt;/h4&gt;
&lt;p&gt;将复杂任务拆解成一系列简单提示是一种非常有效的技巧。它不仅能提高最终结果的质量，还能让整个过程更加可控和富有洞察力。这种方法特别适用于需要深度思考、多个步骤或创造性输出的任务。通过这种交互式对话，你实际上是在与AI协作，共同完成一个复杂的项目。&lt;/p&gt;
&lt;h3&gt;技巧4：使用肯定的指令词，如“执行”，避免使用否定词汇，如“不要”&lt;/h3&gt;
&lt;p&gt;这条技巧确实有其价值，尤其是在明确指导AI行为时。&lt;/p&gt;
&lt;h4&gt;价值：&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;清晰性：肯定的指令通常更直接、更容易理解。&lt;/li&gt;
&lt;li&gt;减少歧义：否定指令可能导致混淆，特别是在复杂的场景中。&lt;/li&gt;
&lt;li&gt;积极导向：肯定的指令更容易引导AI朝着预期的方向行动。&lt;/li&gt;
&lt;li&gt;减少错误：避免使用否定词可以减少AI误解指令的可能性。&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;举例：&lt;/h4&gt;
&lt;p&gt;否定指令：
&quot;不要使用技术术语解释量子计算。&quot;&lt;/p&gt;
&lt;p&gt;肯定指令：
&quot;用简单的日常语言解释量子计算。&quot;&lt;/p&gt;
&lt;p&gt;在这个例子中，肯定的指令更清晰地表达了期望，直接指导AI使用简单语言。&lt;/p&gt;
&lt;p&gt;另一个例子：&lt;/p&gt;
&lt;p&gt;否定指令：
&quot;在写这篇文章时，不要使用被动语态。&quot;&lt;/p&gt;
&lt;p&gt;肯定指令：
&quot;在写这篇文章时，请使用主动语态。&quot;&lt;/p&gt;
&lt;p&gt;肯定的指令更直接地指出了所需的写作风格，减少了AI可能的困惑。&lt;/p&gt;
&lt;p&gt;然而，需要注意的是，这个技巧并非绝对。在某些情况下，使用否定指令可能是必要的，特别是当你需要明确排除某些选项时。例如：&lt;/p&gt;
&lt;p&gt;&quot;在推荐投资策略时，不要包括任何高风险的选项。&quot;&lt;/p&gt;
&lt;p&gt;在这种情况下，使用否定指令可能更有效地传达你的意图。&lt;/p&gt;
&lt;h4&gt;结论：&lt;/h4&gt;
&lt;p&gt;使用肯定的指令词通常是一个有效的技巧，可以提高指令的清晰度和执行效果。它有助于减少歧义，提高AI理解和执行指令的准确性。然而，这并不意味着完全排除否定指令的使用。关键是要根据具体情况选择最清晰、最有效的表达方式。在大多数情况下，努力将否定指令转化为肯定指令可以带来更好的结果，但也要保持灵活性，在必要时使用否定指令来精确表达你的需求。&lt;/p&gt;
&lt;h3&gt;技巧5：采用示例驱动的提示方式（使用少样本提示法）&lt;/h3&gt;
&lt;p&gt;这是一个非常有价值的技巧，通常被称为&quot;少样本学习&quot;（few-shot learning）或&quot;示例驱动的提示&quot;。这种方法可以显著提高AI的输出质量和准确性。&lt;/p&gt;
&lt;h4&gt;价值：&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;明确期望：通过提供具体例子，你可以清晰地展示你期望的输出格式和风格。&lt;/li&gt;
&lt;li&gt;提高准确性：示例可以帮助AI更准确地理解任务要求，减少误解。&lt;/li&gt;
&lt;li&gt;一致性：当需要多个类似输出时，示例可以确保结果的一致性。&lt;/li&gt;
&lt;li&gt;处理特殊需求：对于非标准或特殊的请求，示例可以快速引导AI理解你的独特需求。&lt;/li&gt;
&lt;li&gt;跨领域应用：这种方法特别适用于专业领域或需要特定格式的任务。&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;举例：&lt;/h4&gt;
&lt;p&gt;不使用示例：
&quot;为一家咖啡店创作三条广告语。&quot;&lt;/p&gt;
&lt;p&gt;使用示例驱动的提示：
&quot;为一家咖啡店创作三条广告语。请遵循以下格式和风格：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&apos;唤醒你的味蕾，从一杯完美的咖啡开始。&apos;&lt;/li&gt;
&lt;li&gt;&apos;我们不只提供咖啡，我们创造回忆。&apos;&lt;/li&gt;
&lt;li&gt;&apos;品质与热情的完美混合，就在每一杯中。&apos;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;现在，请创作三条新的广告语。&quot;&lt;/p&gt;
&lt;p&gt;在这个例子中，示例清晰地展示了所需的语言风格、长度和重点，使AI能够生成更符合期望的广告语。&lt;/p&gt;
&lt;p&gt;另一个例子：&lt;/p&gt;
&lt;p&gt;不使用示例：
&quot;总结这篇科学文章的主要发现。&quot;&lt;/p&gt;
&lt;p&gt;使用示例驱动的提示：
&quot;请总结这篇科学文章的主要发现，遵循以下格式：&lt;/p&gt;
&lt;p&gt;研究主题：[简短描述]
主要发现：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;[发现1]&lt;/li&gt;
&lt;li&gt;[发现2]&lt;/li&gt;
&lt;li&gt;[发现3]
方法：[简要说明使用的主要研究方法]
潜在影响：[描述这些发现可能带来的影响]&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;例如：
研究主题：全球变暖对北极熊栖息地的影响
主要发现：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;北极海冰面积在过去30年中减少了40%&lt;/li&gt;
&lt;li&gt;北极熊的觅食季节缩短了平均两周&lt;/li&gt;
&lt;li&gt;幼崽存活率降低了25%
方法：卫星图像分析和实地观察相结合
潜在影响：如果当前趋势持续，北极熊可能在50年内面临灭绝危险&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;现在，请使用这个格式来总结给定的科学文章。&quot;&lt;/p&gt;
&lt;p&gt;这个例子展示了如何使用详细的格式和具体的示例来指导AI生成结构化的科学文章摘要。&lt;/p&gt;
&lt;h4&gt;结论：&lt;/h4&gt;
&lt;p&gt;采用示例驱动的提示方式是一个强大的技巧，可以显著提高AI输出的质量和相关性。它特别适用于需要特定格式、风格或专业知识的任务。通过提供清晰的例子，你实际上是在&quot;训练&quot;AI理解你的具体需求，从而获得更精准、更符合预期的结果。这种方法不仅可以提高效率，还可以确保输出的一致性，特别是在需要批量生成内容或处理复杂任务时。然而，要注意示例的质量和代表性，因为它们将直接影响AI的输出。&lt;/p&gt;
&lt;h3&gt;技巧6：格式化提示时，先写上‘#指令#’，然后根据需要添加‘#示例#’或‘#问题#’。接着展示你的内容，用一行或多行空行分隔各个部分，包括指令、示例、问题、背景和输入数据&lt;/h3&gt;
&lt;p&gt;这条技巧有一些有趣的方面，但可能需要进一步澄清和讨论。&lt;/p&gt;
&lt;h4&gt;价值：&lt;/h4&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;h4&gt;需要注意的地方：&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&apos;#undefined#&apos; 标记：这些标记在你的描述中没有明确定义。通常，我们会使用更具描述性的标记，如 &apos;#指令#&apos;、&apos;#示例#&apos;、&apos;#问题#&apos; 等。&lt;/li&gt;
&lt;li&gt;复杂性：对于简单的提示，这种结构可能过于复杂。&lt;/li&gt;
&lt;li&gt;一致性：需要在不同的提示中保持一致的格式，以获得最佳效果。&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;举例：&lt;/h4&gt;
&lt;p&gt;让我们用一个更清晰的版本来展示这个技巧：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#指令#
创建一个简短的科幻故事，包含以下元素：时间旅行、人工智能、和道德困境。

#背景#
故事设定在2150年的地球，人类已经发明了时间机器。

#输入数据#
主角名字：Alex
主角职业：时间旅行研究员
故事长度：约300字

#示例#
这是一个类似故事的开头：
&quot;Alex凝视着闪烁的时间机器控制台，犹豫着是否要按下那个红色按钮。作为一名时间旅行研究员，他知道改变过去可能带来的可怕后果。但是当人工智能Zeta告诉他，通过改变一个小事件可以拯救数百万生命时，他陷入了深深的道德困境...&quot;

#问题#
请基于以上信息创作一个完整的短篇科幻故事。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个例子展示了如何使用描述性标记和空行来组织提示的不同部分。它清晰地分隔了指令、背景信息、输入数据、示例和最终问题。&lt;/p&gt;
&lt;h4&gt;结论：&lt;/h4&gt;
&lt;p&gt;这种格式化提示的方法确实有其优点，特别是在处理复杂的、多部分的提示时。它可以帮助组织思路，确保提供所有必要的信息。然而，对于简单的提示，这种方法可能显得过于繁琐。&lt;/p&gt;
&lt;p&gt;改进建议：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;使用清晰、描述性的标记，而不是 &apos;#undefined#&apos;。&lt;/li&gt;
&lt;li&gt;根据提示的复杂程度灵活使用这种结构。简单的提示可能不需要这么详细的格式。&lt;/li&gt;
&lt;li&gt;保持一致性，在相似类型的提示中使用相同的结构。&lt;/li&gt;
&lt;li&gt;考虑添加一个简短的总结或目标陈述在最开始，帮助AI快速理解整个提示的目的。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;总的来说，这种技巧的核心思想 - 即结构化和组织提示 - 是非常有价值的。但具体的实现方式可能需要根据实际需求和复杂度进行调整。&lt;/p&gt;
&lt;h3&gt;技巧7：使用这样的短语：“你的任务是”和“必须完成”&lt;/h3&gt;
&lt;p&gt;这个技巧确实有其价值，但同时也需要谨慎使用。&lt;/p&gt;
&lt;h4&gt;价值：&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;明确性：使用&quot;你的任务是&quot;和&quot;必须完成&quot;这样的短语可以清晰地表达期望和要求。&lt;/li&gt;
&lt;li&gt;重要性强调：这些短语可以突出任务的关键性和必要性。&lt;/li&gt;
&lt;li&gt;结构化指令：有助于将复杂的请求分解为明确的步骤或要求。&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;需要注意的地方：&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;语气：这些短语可能显得过于命令或强制，在某些情况下可能不适合。&lt;/li&gt;
&lt;li&gt;灵活性：过于严格的指令可能限制AI的创造性或灵活性。&lt;/li&gt;
&lt;li&gt;上下文适应：不是所有的任务都需要这么强烈的措辞。&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;举例：&lt;/h4&gt;
&lt;p&gt;例1 - 适当使用：
&quot;你的任务是分析这份财务报告。必须完成以下步骤：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;总结关键财务指标&lt;/li&gt;
&lt;li&gt;识别潜在的风险领域&lt;/li&gt;
&lt;li&gt;提出三个改善财务状况的建议&quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这个例子中，使用这些短语有助于明确任务的范围和重要性。&lt;/p&gt;
&lt;p&gt;例2 - 可能过于强硬：
&quot;你的任务是写一首诗。必须完成以下要求：使用押韵，包含至少三个隐喻，长度恰好为14行。&quot;&lt;/p&gt;
&lt;p&gt;在这种创意任务中，如此严格的措辞可能会限制AI的创造性发挥。&lt;/p&gt;
&lt;p&gt;改进版本：
&quot;请创作一首诗。考虑以下建议：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;尝试使用押韵&lt;/li&gt;
&lt;li&gt;可以包含一些隐喻&lt;/li&gt;
&lt;li&gt;大约14行左右的长度会很好&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这个版本保留了指导性，但给予了更多创作自由。&lt;/p&gt;
&lt;p&gt;例3 - 平衡使用：
&quot;你的任务是为一个新的智能手机应用创建营销策略。在制定策略时，请考虑以下几点：&lt;/p&gt;
&lt;ol&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;/ol&gt;
&lt;p&gt;必须完成的关键部分是目标受众分析和推广渠道选择。其他部分也请尽可能详细地阐述。&quot;&lt;/p&gt;
&lt;p&gt;这个例子展示了如何平衡使用强制性语言和提供灵活性。它明确了哪些部分是必须的，同时也给出了其他期望。&lt;/p&gt;
&lt;h4&gt;结论：&lt;/h4&gt;
&lt;p&gt;使用&quot;你的任务是&quot;和&quot;必须完成&quot;这样的短语可以增加指令的清晰度和重要性。然而，这种技巧需要根据具体情况灵活运用。它特别适用于需要精确执行、分步骤完成的任务，或者在强调某些关键要求时使用。&lt;/p&gt;
&lt;p&gt;对于更开放、创意性的任务，或者当你希望AI有更大发挥空间时，可以考虑使用更柔和的语言。最佳实践是根据任务的性质和上下文来调整语气，在明确性和灵活性之间找到平衡。记住，即使不使用这些特定短语，也可以通过清晰、具体的指示来有效地传达你的期望。&lt;/p&gt;
&lt;h3&gt;技巧8：使用引导性的词汇，比如“逐步思考”&lt;/h3&gt;
&lt;p&gt;这是一个非常有价值的技巧，特别是在处理复杂问题或需要详细解释的情况下。&lt;/p&gt;
&lt;h4&gt;价值：&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;促进结构化思维：鼓励AI以有序、逻辑的方式处理问题。&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;/ol&gt;
&lt;h4&gt;举例：&lt;/h4&gt;
&lt;p&gt;例1 - 数学问题：&lt;/p&gt;
&lt;p&gt;不使用引导：
&quot;计算 (3x + 2)(x - 4) 的展开式。&quot;&lt;/p&gt;
&lt;p&gt;使用引导：
&quot;请逐步思考并解释 (3x + 2)(x - 4) 的展开过程。每一步都要说明你在做什么以及为什么。&quot;&lt;/p&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;让我们一步步来：
(3x + 2)(x - 4) = 3x(x) + 3x(-4) + 2(x) + 2(-4)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;现在，让我们简化每一项：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;3x(x) = 3x²&lt;/li&gt;
&lt;li&gt;3x(-4) = -12x&lt;/li&gt;
&lt;li&gt;2(x) = 2x&lt;/li&gt;
&lt;li&gt;2(-4) = -8&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;把这些项加在一起：
3x² - 12x + 2x - 8&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;合并同类项：
3x² - 10x - 8&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;因此，(3x + 2)(x - 4) 的展开式是 3x² - 10x - 8。&lt;/p&gt;
&lt;p&gt;例2 - 决策分析：&lt;/p&gt;
&lt;p&gt;不使用引导：
&quot;我应该买电动车还是混合动力车？&quot;&lt;/p&gt;
&lt;p&gt;使用引导：
&quot;请逐步思考我是否应该买电动车还是混合动力车。考虑以下因素：初始成本、长期节省、环境影响、基础设施可用性和个人使用模式。&quot;&lt;/p&gt;
&lt;p&gt;回答可能会是：&lt;/p&gt;
&lt;ol&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;/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;/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;/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;/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;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;结论：
基于这些因素，如果你主要在城市中短途行驶，有家庭充电条件，并且重视环保，电动车可能是更好的选择。如果你经常长途旅行，或者居住在充电基础设施不完善的地区，混合动力车可能更适合。最终决定还需要根据个人具体情况和偏好来做。&lt;/p&gt;
&lt;p&gt;这个技巧的使用使得分析过程更加透明和全面，帮助用户做出更加明智的决定。&lt;/p&gt;
&lt;h4&gt;结论：&lt;/h4&gt;
&lt;p&gt;使用&quot;逐步思考&quot;这样的引导词确实是一个非常有效的技巧。它不仅可以提高AI回答的质量和深度，还能帮助用户更好地理解问题和解决过程。这种方法特别适用于复杂的问题、决策分析、数学计算、科学解释等需要详细推理的场景。然而，对于简单直接的问题，可能不需要这么详细的步骤。因此，关键是要根据问题的复杂性和用户的需求来灵活运用这个技巧。&lt;/p&gt;
&lt;h2&gt;小结&lt;/h2&gt;
&lt;h3&gt;prompt提示词的学习技巧：&lt;/h3&gt;
&lt;ol&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;明确任务重要性：适当使用&quot;你的任务是&quot;和&quot;必须完成&quot;等短语来强调关键要求。&lt;/li&gt;
&lt;li&gt;引导思考过程：使用&quot;逐步思考&quot;等引导性词汇，促进结构化和透明的问题解决过程。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;如何甄别有价值的技巧：&lt;/h3&gt;
&lt;ol&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;与AI模型的兼容性：确保技巧与您使用的特定AI模型兼容。&lt;/li&gt;
&lt;li&gt;平衡简单性和复杂性：好的技巧应该在简单易用和处理复杂任务之间取得平衡。&lt;/li&gt;
&lt;li&gt;持续学习：随着AI技术的发展，保持开放态度，不断学习和调整您的提示技巧。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;记住，最有价值的技巧通常是那些能够根据具体情况灵活应用，并能持续产生高质量输出的技巧。通过实践和反复试验，您将能够建立起一套适合自己需求的有效prompt策略。&lt;/p&gt;
</content:encoded><category>AI</category><category>提示词</category><category>大模型</category><category>Prompt</category><category>方法论</category></item></channel></rss>