<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <author>
    <name>青萍叙事</name>
  </author>
  <generator uri="https://hexo.io/">Hexo</generator>
  <id>https://blog.lusyoe.com/</id>
  <link href="https://blog.lusyoe.com/" rel="alternate"/>
  <link href="https://blog.lusyoe.com/rss/feed.xml" rel="self"/>
  <rights>All rights reserved 2026, 青萍叙事</rights>
  <subtitle>一个懂技术的产品汪~</subtitle>
  <title>青萍叙事</title>
  <updated>2026-07-21T13:59:50.000+08:00</updated>
  <entry>
    <author>
      <name>青萍叙事</name>
    </author>
    <category term="网站搭建" scheme="https://blog.lusyoe.com/categories/%E7%BD%91%E7%AB%99%E6%90%AD%E5%BB%BA/"/>
    <category term="安全" scheme="https://blog.lusyoe.com/tags/%E5%AE%89%E5%85%A8/"/>
    <category term="限流" scheme="https://blog.lusyoe.com/tags/%E9%99%90%E6%B5%81/"/>
    <content>
      <![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>早上打开手机，飞书弹出几十条告警，全是同一个接口：发送验证码。</p><p>一夜之间几万次请求，同一个路径，来自几十个不同的 IP。</p><p>防火墙不是早就部署了吗，怎么没拦住？<br><img src="https://img-cdn.lusyoe.cn/images/lusyoe/2026/07/21/t7y4qmcpmy.webp" alt="安全"></p><h1 id="和以前不一样"><a href="#和以前不一样" class="headerlink" title="和以前不一样"></a>和以前不一样</h1><p>打开日志仔细看，每条请求都长得”正常”。</p><p>正常的浏览器标识，正常的请求头，参数格式也对。</p><p>攻击者发的请求本身没有恶意内容，只是在疯狂调用注册页面的发送验证码接口。</p><p>防火墙的强项是识别恶意载荷，比如 SQL 注入、跨站脚本攻击这类带武器来的请求。</p><p>但这次每条请求都是”合法”的，防火墙自然不会拦。</p><p>防火墙看的是<strong>请求里有没有恶意内容</strong>，限流看的是<strong>这个来源短时间内发了多少请求</strong>。</p><p>一个防的是带刀的贼，一个防的是空手来堵门的。</p><p>两种威胁都要防，缺一不可。</p><p>注册验证码的发送走的是邮件，和短信比起来成本不算高，但一夜几万次请求也够让人头疼的。</p><h1 id="限流怎么做"><a href="#限流怎么做" class="headerlink" title="限流怎么做"></a>限流怎么做</h1><p>既然防火墙拦不住，就得从另一个维度来防。</p><p>思路很简单：给接口加一道限流，限制同一来源在短时间内的请求次数，超过阈值就直接拒绝，请求根本打不到后端。</p><p>但光按 IP 限制还不够，攻击者换个代理 IP 就能绕过。</p><p>更好的做法是多维度叠加，再加上前端的人机验证，用户先完成滑动拼图才能触发发送。</p><p>这样即使攻击者绕过了限流，也卡在人机验证这一步。</p><p>限流阈值要根据实际业务流量来定，先观察正常情况下的流量峰值，再设一个略高于峰值的阈值。</p><p>设太松等于没防，设太紧会误伤正常用户。</p><h1 id="一人企业的安全防线"><a href="#一人企业的安全防线" class="headerlink" title="一人企业的安全防线"></a>一人企业的安全防线</h1><p>这件事给我最大的感受是，安全不是一个点，而是一张网。</p><p>之前部署了防火墙，以为能挡住大部分攻击，确实也挡住了。</p><p>但防火墙挡的是带刀的贼，挡不住空手来堵门的。</p><p>限流、防火墙、监控，每一层都有自己的盲区。</p><p>只有叠在一起，才能形成真正的纵深防御。</p><p>做一人企业，没有人帮你盯着安全，也没有专门的运维团队兜底。</p><p>被攻击一次，损失的不只是钱，还有用户的信任。</p><p>把该加的防护提前加到位，远比出了事再补救划算。</p><p>你的网站接口有没有做过限流？</p><p>评论区聊聊你遇到过的安全问题。</p>]]>
    </content>
    <id>https://blog.lusyoe.com/article/rate-limiting-registration-abuse</id>
    <link href="https://blog.lusyoe.com/article/rate-limiting-registration-abuse"/>
    <published>2026-07-21T13:59:50.000+08:00</published>
    <summary>防火墙能挡住恶意代码，却挡不住正常接口的疯狂调用。本文记录网站注册验证码接口被刷的真实经历，以及通过限流构建防线的完整方案。</summary>
    <title>注册验证码被刷了一整夜，论接口限流的重要性</title>
    <updated>2026-07-21T13:59:50.000+08:00</updated>
  </entry>
  <entry>
    <author>
      <name>青萍叙事</name>
    </author>
    <category term="网站搭建" scheme="https://blog.lusyoe.com/categories/%E7%BD%91%E7%AB%99%E6%90%AD%E5%BB%BA/"/>
    <category term="安全" scheme="https://blog.lusyoe.com/tags/%E5%AE%89%E5%85%A8/"/>
    <category term="雷池WAF" scheme="https://blog.lusyoe.com/tags/%E9%9B%B7%E6%B1%A0WAF/"/>
    <category term="Hermes" scheme="https://blog.lusyoe.com/tags/Hermes/"/>
    <content>
      <![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>上一篇部署了雷池 WAF（Web 应用防火墙），大部分恶意请求在到达应用之前就被自动挡住了。</p><p>但 WAF 不是万能的。</p><p>攻击者会不断变异 payload（攻击载荷），用 WAF 没见过的新手法绕过检测。</p><p>雷池的语义分析引擎很强，但新型攻击和精心构造的变异请求仍然可能漏过。</p><p>我在网关日志里确实看到了一些 WAF 放行但明显有问题的请求。</p><p>光靠 WAF 被动防御不够，得有一道主动的监控层，把 WAF 漏掉的东西捞回来。</p><h1 id="从手动排查到自动化"><a href="#从手动排查到自动化" class="headerlink" title="从手动排查到自动化"></a>从手动排查到自动化</h1><p>最开始的做法很原始：每天打开网关日志，人工筛查可疑请求，发现漏网的就在雷池控制台手动加规则。</p><p>流量小的时候还能应付，但随着业务线增多，每天几千条请求里混着上百个不同 IP 的扫描，手动处理根本追不上。</p><p>试过几个方案都不理想，分两个维度看。</p><p>先说日志来源。</p><p>ELK 太重，小服务器跑不动，规则维护成本高。</p><p>阿里云 SLS 成本也不小，每次拉数据都很慢。</p><p>再说恶意分析。</p><p>纯 AI 分析把所有 IP 都丢给大模型，效果不错但太慢太贵。</p><p>最终想通了一件事：大部分攻击模式是重复的，规则能判定的就不该劳烦 AI。</p><p>方案定型为六个阶段的管道：网关日志采集 → 规则预分类 → AI 分析 → 写入雷池 WAF → 飞书报告 → 规则自学习。</p><p><img src="https://img-cdn.lusyoe.cn/images/lusyoe/2026/07/15/pipeline-flow.webp"></p><h1 id="日志采集：全量数据的源头"><a href="#日志采集：全量数据的源头" class="headerlink" title="日志采集：全量数据的源头"></a>日志采集：全量数据的源头</h1><p>管道的第一步是拿到全量请求日志。</p><p>没有用到 ELK 或阿里云 SLS，而是直接读取服务器本地的网关日志文件。</p><p>网关按小时轮转日志，格式是标准的 nginx combined 风格，每条记录包含客户端 IP、请求方法、路径、状态码、UA、Referer 等字段。</p><p>采集器通过 SSH 到网关节点读取日志文件，用正则逐行解析，按 IP 聚合访问路径、状态码、UA 等信息，输出结构化 JSON 供后续阶段使用。</p><p>相比 SLS 的条数限制和查询延迟，本地日志是全量的，每小时少则上千条多则数千条，一条都不漏。</p><h1 id="规则预分类：AI-的减负关键"><a href="#规则预分类：AI-的减负关键" class="headerlink" title="规则预分类：AI 的减负关键"></a>规则预分类：AI 的减负关键</h1><p>这是整套系统最重要的设计。</p><p>互联网上的扫描器套路高度固定，有人用 sqlmap 测注入，有人用 gobuster 暴力扫目录，有人直接访问 wp-admin 后台。</p><p>这些模式用规则就能精准识别，不需要 AI 来判断。</p><p>预分类器对每个 IP 给出三种判定。</p><p>规则明确判定正常的标记为 clean，直接跳过。</p><p>规则明确判定攻击的标记为 malicious，直接提交封禁。</p><p>规则无法判定的标记为 unknown，才交给 AI 做最终判断。</p><p>内置规则覆盖三大维度。</p><p>UA 维度识别扫描工具，zgrab、sqlmap、nikto 这些一听就不是正经浏览器。</p><p>路径维度识别敏感文件探测、CMS 后台扫描、Webshell 入口。</p><p>行为维度识别极短 UA、高 404 比例、CLI 工具探测后台路径等异常模式。</p><p>实际效果很显著。</p><p>1 小时内 104 个 IP，规则直接判定 61 个正常加 1 个恶意，只有 42 个交给 AI 分析，负载降低近 60%。</p><h1 id="AI-只处理模糊情况"><a href="#AI-只处理模糊情况" class="headerlink" title="AI 只处理模糊情况"></a>AI 只处理模糊情况</h1><p>WAF 漏过的、规则也判不了的灰地带，才轮到 AI 出场。</p><p>比如某个 IP 用正常浏览器 UA 访问了几个 404 页面，但也碰了一下 admin 路径，说不清是迷路的真实用户还是低调的扫描器，就丢给大模型判断。</p><p>调用 DeepSeek 把 IP 的访问路径、UA、状态码、归属地发给模型，让它给出判定。</p><p>AI 判定中内置了大量误报规避逻辑，避免把正常用户误杀。</p><p>这些逻辑是被误报教训过几次后逐步加上去的，不是一开始就有的。</p><h1 id="回写雷池-WAF：让防火墙越用越强"><a href="#回写雷池-WAF：让防火墙越用越强" class="headerlink" title="回写雷池 WAF：让防火墙越用越强"></a>回写雷池 WAF：让防火墙越用越强</h1><p>判定为恶意的 IP 和攻击模式，最终都通过雷池 OpenAPI 回写到 WAF 的自定义规则里。</p><p>这是整套系统的核心思路：WAF 漏掉的东西，找到之后再喂回给 WAF。</p><p>这样下次再遇到之前漏掉的恶意 IP 就直接在 WAF 层面拦截了。</p><p>回写前有多道安全检查，防止误封正常用户和业务流量。</p><p>每轮处理完自动生成安全报告，通过 lark-cli 推送到飞书群。</p><p>如果某次误封了，在雷池控制台删掉对应规则即可，也可以把 IP 写入白名单文件做预处理。</p><h1 id="规则自学习：越用越聪明"><a href="#规则自学习：越用越聪明" class="headerlink" title="规则自学习：越用越聪明"></a>规则自学习：越用越聪明</h1><p>本轮处理完成后，从 AI 的分析结果中提取新的攻击模式，通过雷池 OpenAPI 写入 WAF 规则库。</p><p>逻辑很简单：这轮 AI 判定某 IP 是攻击，就提取它的路径模式和 UA 特征，自动创建为雷池 WAF 的自定义规则。</p><p>下轮同样的攻击直接被 WAF 拦截，不再需要管道介入。</p><p>比如 AI 发现有人用变异 payload 探测某个接口，自动提取特征写入 WAF 规则。</p><p>下次再有类似请求，WAF 直接拦截，管道连看都不用看。</p><p>随着运行次数增加，WAF 的规则越来越丰富，漏过的攻击越来越少，整个系统越来越强。</p><h1 id="定时运行"><a href="#定时运行" class="headerlink" title="定时运行"></a>定时运行</h1><p>每小时通过 cron 执行一次完整的六阶段流程。</p><p>也支持单独运行某个阶段做调试，比如只采集日志看看数据量，或者只跑分类器看看判定分布。</p><p>整个管道用 Hermes Agent 编排，放在安全专用的 profile 下面，脚本之间通过 JSON 文件传递数据，互不耦合。</p><p>你的业务有没有做过主动安全防御？</p><p>评论区聊聊你的方案。</p>]]>
    </content>
    <id>https://blog.lusyoe.com/article/ai-driven-security-scan-pipeline</id>
    <link href="https://blog.lusyoe.com/article/ai-driven-security-scan-pipeline"/>
    <published>2026-07-14T23:23:08.000+08:00</published>
    <summary>雷池WAF能拦住大部分攻击，但新型攻击和变异手法仍可能漏过。本文记录用Hermes编排AI搭建第二道防线，从网关日志中找出WAF漏掉的攻击，分析后自动封禁，新攻击模式回写为雷池WAF规则，让防火墙越用越强。</summary>
    <title>通过Hermes搭建AI驱动的全自动安全封禁系统</title>
    <updated>2026-07-14T23:23:08.000+08:00</updated>
  </entry>
  <entry>
    <author>
      <name>青萍叙事</name>
    </author>
    <category term="网站搭建" scheme="https://blog.lusyoe.com/categories/%E7%BD%91%E7%AB%99%E6%90%AD%E5%BB%BA/"/>
    <category term="安全" scheme="https://blog.lusyoe.com/tags/%E5%AE%89%E5%85%A8/"/>
    <category term="雷池WAF" scheme="https://blog.lusyoe.com/tags/%E9%9B%B7%E6%B1%A0WAF/"/>
    <category term="APISIX" scheme="https://blog.lusyoe.com/tags/APISIX/"/>
    <content>
      <![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>上次博客评论区被植入恶意代码，虽然做了应急处理，封 IP、删评论、修复模板漏洞，但总觉得不够踏实。</p><p>攻击者换个 IP 就能再来，每次手动封太被动了。</p><p>我需要一个能自动拦截恶意请求的防火墙，在攻击到达应用之前就把它挡在外面。</p><p>调研了一圈，选了长亭科技的雷池 WAF（Web 应用防火墙），社区版免费，功能够用，还能和我现有的 APISIX 网关集成。</p><p>这篇文章记录完整的部署和集成过程。</p><h1 id="雷池是什么"><a href="#雷池是什么" class="headerlink" title="雷池是什么"></a>雷池是什么</h1><p>雷池（SafeLine）是长亭科技开源的 Web 应用防火墙，社区版完全免费。</p><p>它的核心是语义分析检测引擎，不是简单的正则匹配，而是真正理解 HTTP 请求的内容，误报率低，拦截准。</p><p>能防的东西很多：SQL 注入、XSS 跨站脚本攻击、代码执行、目录遍历、文件上传攻击，还有 CC 攻击防护和 Bot 机器人防护。</p><p>对我的一人企业场景来说，社区版的能力已经够用了。</p><h1 id="手动部署雷池"><a href="#手动部署雷池" class="headerlink" title="手动部署雷池"></a>手动部署雷池</h1><p>雷池推荐 Docker 部署，官方提供一键安装脚本，但如果你和我一样喜欢掌控每个配置细节，走手动部署更合适。</p><p>前提是服务器已经装好 Docker，版本不低于 20.10.14，Docker Compose 不低于 2.0.0。</p><p>创建安装目录：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">mkdir</span> -p <span class="string">&quot;/data/safeline&quot;</span></span><br><span class="line"><span class="built_in">cd</span> <span class="string">&quot;/data/safeline&quot;</span></span><br></pre></td></tr></table></figure><p>下载 Docker Compose 编排脚本：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wget <span class="string">&quot;https://waf-ce.chaitin.cn/release/latest/compose.yaml&quot;</span></span><br></pre></td></tr></table></figure><p>创建环境变量配置文件 <code>.env</code>，写入以下内容：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">SAFELINE_DIR=/data/safeline</span><br><span class="line">IMAGE_TAG=latest</span><br><span class="line">MGT_PORT=9443</span><br><span class="line">POSTGRES_PASSWORD=your_password  <span class="comment"># 自定义密码，数字加英文大小写</span></span><br><span class="line">SUBNET_PREFIX=172.22.222</span><br><span class="line">IMAGE_PREFIX=swr.cn-east-3.myhuaweicloud.com/chaitin-safeline</span><br><span class="line">ARCH_SUFFIX=</span><br><span class="line">RELEASE=</span><br><span class="line">REGION=</span><br><span class="line">MGT_PROXY=0</span><br></pre></td></tr></table></figure><p>几个要点。</p><p>ARM 架构的服务器需要把 <code>ARCH_SUFFIX</code> 改成 <code>-arm</code>。</p><p>海外服务器建议把 <code>IMAGE_PREFIX</code> 改成 <code>chaitin</code>，直接从 Docker Hub 拉镜像。</p><p>国内服务器保持默认的华为云镜像源就行。</p><p>启动雷池：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker compose up -d</span><br></pre></td></tr></table></figure><p>容器启动后，浏览器访问 <code>https://服务器IP:9443</code> 就能看到雷池控制台。</p><p>首次访问会提示证书不安全，点继续即可。</p><p>PS：由于我服务器并没有放开9443端口，需要通过APISIX网关来暴露雷池控制台了，配置参考如下：</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;uri&quot;</span><span class="punctuation">:</span> <span class="string">&quot;/*&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;name&quot;</span><span class="punctuation">:</span> <span class="string">&quot;waf&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;host&quot;</span><span class="punctuation">:</span> <span class="string">&quot;your-waf-domain&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;plugins&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">        <span class="attr">&quot;proxy-rewrite&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">            <span class="attr">&quot;headers&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">                <span class="attr">&quot;X-Forwarded-For&quot;</span><span class="punctuation">:</span> <span class="string">&quot;$remote_addr&quot;</span><span class="punctuation">,</span></span><br><span class="line">            <span class="punctuation">&#125;</span></span><br><span class="line">        <span class="punctuation">&#125;</span></span><br><span class="line">    <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;upstream&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">        <span class="attr">&quot;type&quot;</span><span class="punctuation">:</span> <span class="string">&quot;roundrobin&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;nodes&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">            <span class="attr">&quot;127.0.0.1:9443&quot;</span><span class="punctuation">:</span> <span class="number">1</span></span><br><span class="line">        <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;tls&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">            <span class="attr">&quot;verify&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">false</span></span></span><br><span class="line">        <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;scheme&quot;</span><span class="punctuation">:</span> <span class="string">&quot;https&quot;</span></span><br><span class="line">    <span class="punctuation">&#125;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><p>另外首次访问还需要执行命令： <code>docker exec safeline-mgt resetadmin</code> 获取管理员密码。</p><h1 id="切换检测引擎为-TCP-模式"><a href="#切换检测引擎为-TCP-模式" class="headerlink" title="切换检测引擎为 TCP 模式"></a>切换检测引擎为 TCP 模式</h1><p>到这里雷池已经能独立工作了，可以直接在控制台添加站点进行防护。</p><p>但我的架构里前面有一层 APISIX 网关，需要把雷池的检测引擎接入 APISIX，让所有请求先过雷池再转发到后端。</p><p>问题是雷池检测引擎默认用 Unix Socket 提供服务，只能在容器内部调用。</p><p>要和 APISIX 集成，得改成 TCP 模式。</p><p>进入检测引擎的配置目录：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> /data/safeline/resources/detector/</span><br></pre></td></tr></table></figure><p>编辑 <code>detector.yml</code>，添加两行配置：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">bind_addr:</span> <span class="number">0.0</span><span class="number">.0</span><span class="number">.0</span></span><br><span class="line"><span class="attr">listen_port:</span> <span class="number">8000</span></span><br></pre></td></tr></table></figure><p>然后回到雷池安装目录，编辑 <code>compose.yaml</code>，给 detector 容器加上端口映射：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">detect:</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="number">8000</span><span class="string">:8000</span></span><br></pre></td></tr></table></figure><p>重启雷池让配置生效：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> /data/safeline</span><br><span class="line">docker compose down</span><br><span class="line">docker compose up -d</span><br></pre></td></tr></table></figure><p>还有一步：雷池和 APISIX 默认都用 9443 端口，装在同一台机器上会冲突。</p><p>在 <code>.env</code> 文件里把 <code>MGT_PORT</code> 改成别的端口（比如 9444），再重启雷池就行。</p><p>需要注意的是，切换 TCP 模式后雷池控制台本身配置的站点防护会失效，需要同步把雷池的 NGINX 配置从 unix socket 改成 http 方式。<br>具体做法是拷贝 <code>safeline_unix.conf</code> 为 <code>safeline_http.conf</code>，在 <code>nginx.conf</code> 中切换 include，再把 upstream 地址指向检测引擎的 IP 加端口。</p><h1 id="在-APISIX-中接入雷池"><a href="#在-APISIX-中接入雷池" class="headerlink" title="在 APISIX 中接入雷池"></a>在 APISIX 中接入雷池</h1><p>由于我的网站平台是统一使用 APISIX 做的网关，APISIX 从 3.5.0 版本开始就内置了 <code>chaitin-waf</code> 插件，集成起来非常方便，只需要简单配置就可以给全站平台都加上安全防护啦。</p><p>配置 APISIX 指向雷池检测引擎的地址：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">curl http://127.0.0.1:9180/apisix/admin/plugin_metadata/chaitin-waf \</span><br><span class="line">  -H <span class="string">&#x27;X-API-KEY: your-key-here&#x27;</span> -X PUT -d <span class="string">&#x27;</span></span><br><span class="line"><span class="string">&#123;</span></span><br><span class="line"><span class="string">  &quot;nodes&quot;:[</span></span><br><span class="line"><span class="string">     &#123;</span></span><br><span class="line"><span class="string">       &quot;host&quot;: &quot;127.0.0.1&quot;,</span></span><br><span class="line"><span class="string">       &quot;port&quot;: 8000</span></span><br><span class="line"><span class="string">     &#125;</span></span><br><span class="line"><span class="string">  ]</span></span><br><span class="line"><span class="string">&#125;&#x27;</span></span><br></pre></td></tr></table></figure><p><code>host</code> 填雷池所在服务器的 IP，同一台机器就是 <code>127.0.0.1</code>。</p><p>然后创建一条路由，把流量经过雷池检测后转发到后端业务：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">curl http://127.0.0.1:9180/apisix/admin/routes/1 \</span><br><span class="line">  -H <span class="string">&#x27;X-API-KEY: your-key-here&#x27;</span> -X PUT -d <span class="string">&#x27;</span></span><br><span class="line"><span class="string">&#123;</span></span><br><span class="line"><span class="string">   &quot;uri&quot;: &quot;/*&quot;,</span></span><br><span class="line"><span class="string">   &quot;plugins&quot;: &#123;</span></span><br><span class="line"><span class="string">       &quot;chaitin-waf&quot;: &#123;</span></span><br><span class="line"><span class="string">       &quot;mode&quot;: &quot;block&quot;,</span></span><br><span class="line"><span class="string">       &quot;append_waf_resp_header&quot;: true</span></span><br><span class="line"><span class="string">       &#125;</span></span><br><span class="line"><span class="string">    &#125;,</span></span><br><span class="line"><span class="string">   &quot;upstream&quot;: &#123;</span></span><br><span class="line"><span class="string">       &quot;type&quot;: &quot;roundrobin&quot;,</span></span><br><span class="line"><span class="string">       &quot;nodes&quot;: &#123;</span></span><br><span class="line"><span class="string">           &quot;127.0.0.1:9080&quot;: 1</span></span><br><span class="line"><span class="string">       &#125;</span></span><br><span class="line"><span class="string">   &#125;</span></span><br><span class="line"><span class="string">&#125;&#x27;</span></span><br></pre></td></tr></table></figure><p><code>upstream</code> 里的地址换成你的实际业务服务器。</p><h1 id="测试防护效果"><a href="#测试防护效果" class="headerlink" title="测试防护效果"></a>测试防护效果</h1><p>配置完成后验证一下。</p><p>正常访问能返回页面：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">curl http://127.0.0.1:9080/</span><br></pre></td></tr></table></figure><p>模拟一个 SQL 注入攻击：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">curl http://127.0.0.1:9080/ -d <span class="string">&#x27;a=1 and 1=1&#x27;</span></span><br></pre></td></tr></table></figure><p>返回 HTTP 403，说明雷池成功拦截了：</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;code&quot;</span><span class="punctuation">:</span> <span class="number">403</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;success&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">false</span></span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;message&quot;</span><span class="punctuation">:</span> <span class="string">&quot;blocked by Chaitin SafeLine Web Application Firewall&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;event_id&quot;</span><span class="punctuation">:</span> <span class="string">&quot;18e0f220f7a94127acb21ad3c1b4ac47&quot;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><p>打开雷池控制台的日志中心，能看到完整的攻击记录，包括请求 IP、攻击类型和拦截时间。</p><p>从此以后，恶意请求在到达博客之前就被雷池自动挡住，不用再每次手动封 IP 了。</p><h1 id="定时报告"><a href="#定时报告" class="headerlink" title="定时报告"></a>定时报告</h1><p>最后还可以通过 hermes 调用 WAF OpenAPI 定时获取安全报告，如下是我的每小时安全报告：<br><img src="https://img-cdn.lusyoe.cn/images/lusyoe/2026/07/12/sugm18coih.webp"></p><p>看起来还不错吧，下一篇再来介绍如何通过 hermes 获取安全报告和自定义规则设置。</p><p>你的网站有没有做过安全防护？用的什么方案？评论区聊聊。</p>]]>
    </content>
    <id>https://blog.lusyoe.com/article/safeline-waf-apisix-deploy</id>
    <link href="https://blog.lusyoe.com/article/safeline-waf-apisix-deploy"/>
    <published>2026-07-12T15:21:19.000+08:00</published>
    <summary>博客被攻击后，被动封IP不是长久之计。本文记录手动部署长亭雷池WAF社区版，并与APISIX网关集成的完整过程，让恶意请求在到达应用之前就被自动拦截。</summary>
    <title>博客被攻击之后，我部署雷池防火墙给网站穿上防弹衣</title>
    <updated>2026-07-12T15:21:19.000+08:00</updated>
  </entry>
  <entry>
    <author>
      <name>青萍叙事</name>
    </author>
    <category term="网站搭建" scheme="https://blog.lusyoe.com/categories/%E7%BD%91%E7%AB%99%E6%90%AD%E5%BB%BA/"/>
    <category term="安全" scheme="https://blog.lusyoe.com/tags/%E5%AE%89%E5%85%A8/"/>
    <category term="Twikoo" scheme="https://blog.lusyoe.com/tags/Twikoo/"/>
    <category term="安知鱼" scheme="https://blog.lusyoe.com/tags/%E5%AE%89%E7%9F%A5%E9%B1%BC/"/>
    <content>
      <![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>今天访问自己的博客时突然发现，页面居然弹出了一个 <code>alert(1)</code> 对话框，再一查是多了一个不存在的异常请求地址：&#x2F;x。</p><p>第一反应是网站被黑了。<br>排查下来，确实是一次评论区的恶意代码注入攻击。</p><p>这篇文章记录完整的发现过程和修复方案，包括封禁攻击者 IP、删除恶意评论、修复主题漏洞三步。</p><h1 id="攻击是怎么发生的"><a href="#攻击是怎么发生的" class="headerlink" title="攻击是怎么发生的"></a>攻击是怎么发生的</h1><p>这种攻击叫 XSS（跨站脚本攻击），原理不复杂：攻击者把恶意代码注入到网页中，其他访客打开页面时代码自动执行。</p><p>这次的攻击路径是这样的：</p><p>攻击者在 Twikoo 评论区提交了一条评论，把昵称设成了 <code>&lt;img src=x onerror=alert(1)&gt;</code>。</p><p>安知鱼主题的<strong>最新评论</strong>侧边栏组件会调用 Twikoo 的 API 获取最近评论，然后把评论数据拼成 HTML 渲染到页面上。</p><p>问题出在拼接 HTML 的环节。<br>主题模板直接把用户昵称拼进了 <code>innerHTML</code>，没有做任何 HTML 转义，浏览器就把它当成了真正的 <code>&lt;img&gt;</code> 标签来渲染，加载失败后触发了弹窗。</p><p>因为 404 页面也带侧边栏最新评论，所以访问任何不存在的路径都会触发弹窗。</p><p>攻击者用 <code>alert(1)</code> 只是<strong>证明能打</strong>。<br>真正危险的攻击可以窃取用户 Cookie、劫持登录态、注入钓鱼页面，后果严重得多。</p><h1 id="第一步：全局封禁攻击者-IP"><a href="#第一步：全局封禁攻击者-IP" class="headerlink" title="第一步：全局封禁攻击者 IP"></a>第一步：全局封禁攻击者 IP</h1><p>发现攻击后，第一件事是切断攻击来源。</p><p>从 Twikoo 后台和 Nginx 访问日志中定位到攻击者的 IP 地址，然后直接在云服务器安全组里封禁。</p><p>在阿里云 ECS 的安全组规则里添加一条入站拒绝规则，把攻击者 IP 的所有流量拦在外面，一劳永逸。</p><p>封禁 IP 是应急措施，能争取处置时间，但不是长久之计。<br>攻击者可以换 IP 再来，所以还需要从应用层面加固。</p><h1 id="第二步：删除恶意评论，开启评论审核"><a href="#第二步：删除恶意评论，开启评论审核" class="headerlink" title="第二步：删除恶意评论，开启评论审核"></a>第二步：删除恶意评论，开启评论审核</h1><p>评论系统的加固分两个动作。</p><p>先从 Twikoo 后台手动删除昵称为 <code>&lt;img src=x onerror=alert(1)&gt;</code> 的那条恶意评论，清除已经注入的攻击载荷。</p><p>然后在 Twikoo 管理后台开启评论审核功能。<br>开启后，新提交的评论不会直接显示，需要管理员审核通过后才能展示。</p><p>这样即使有人再提交恶意内容，也不会直接暴露给其他访客。</p><p>评论审核的代价是降低了互动即时性，但对于个人博客来说，这个权衡是值得的。<br>安全优先。</p><h1 id="第三步：修复评论插件-Bug-并上线"><a href="#第三步：修复评论插件-Bug-并上线" class="headerlink" title="第三步：修复评论插件 Bug 并上线"></a>第三步：修复评论插件 Bug 并上线</h1><p>前面两步是治标，这一步才是治本。</p><p>漏洞的根因在安知鱼主题的两个模板文件里，侧边栏最新评论组件和中控台最新评论组件都有同样的问题。</p><p>两个文件的 <code>generateHtml</code> 函数把 Twikoo 返回的用户数据（昵称、头像、评论内容、链接）直接拼进了 <code>innerHTML</code>，没有做任何 HTML 转义，所以攻击者的昵称被浏览器当成了真正的 HTML 标签来执行。</p><p>修复方法是对所有来自用户的数据做 HTML 实体编码，把 <code>&lt;</code>、<code>&gt;</code>、<code>&quot;</code> 等特殊字符转义成浏览器不会解析的格式。<br>转义之后，<code>&lt;img src=x onerror=alert(1)&gt;</code> 这种恶意昵称只会被当成普通文字显示，不会被执行。</p><p>修复完成后构建验证通过，提交推送到线上。</p><h1 id="攻击复盘"><a href="#攻击复盘" class="headerlink" title="攻击复盘"></a>攻击复盘</h1><p>回顾这次事件，有几个教训值得记住。</p><p>这类攻击的入口往往是评论区、留言板这类用户可自由输入的地方。<br>任何把用户输入直接拼进 HTML 的操作都是潜在漏洞。</p><p>对所有来自用户的数据做 HTML 转义，是前端项目的基本安全底线。<br>浏览器自带的防护机制（CSP 等）只是辅助，最根本的还是开发者在代码层面做好输入过滤和输出转义。</p><p>如果你的博客也用安知鱼主题，建议检查一下评论区组件有没有同样的问题。</p><p>你的博客遇到过类似的安全问题吗？评论区聊聊你的经历和应对方式。</p>]]>
    </content>
    <id>https://blog.lusyoe.com/article/blog-comment-attack</id>
    <link href="https://blog.lusyoe.com/article/blog-comment-attack"/>
    <published>2026-07-11T01:44:39.000+08:00</published>
    <summary>个人博客评论区被攻击者植入恶意代码，访客打开页面就弹出诡异弹窗。本文完整记录攻击发现过程，以及封禁攻击者 IP、删除恶意评论开启审核、修复主题模板漏洞三步解决方案，帮你快速应对类似安全事件。</summary>
    <title>个人博客第一次被攻击，评论区被植入恶意代码全记录</title>
    <updated>2026-07-11T01:44:39.000+08:00</updated>
  </entry>
  <entry>
    <author>
      <name>青萍叙事</name>
    </author>
    <category term="产品" scheme="https://blog.lusyoe.com/categories/%E4%BA%A7%E5%93%81/"/>
    <category term="青萍AI图床" scheme="https://blog.lusyoe.com/tags/%E9%9D%92%E8%90%8DAI%E5%9B%BE%E5%BA%8A/"/>
    <category term="API" scheme="https://blog.lusyoe.com/tags/API/"/>
    <category term="AI生图" scheme="https://blog.lusyoe.com/tags/AI%E7%94%9F%E5%9B%BE/"/>
    <content>
      <![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>青萍AI图床除了基础的图片管理和 CDN 分发能力，还提供了 AI 生图接口，支持文生图和图生图两种方式。</p><p>接口采用 RESTful 风格，请求和响应均为 JSON 格式。认证方式为请求头携带 API Key。</p><h1 id="认证"><a href="#认证" class="headerlink" title="认证"></a>认证</h1><p>所有接口需要在请求头中携带 <code>X-API-KEY</code>：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">X-API-KEY: your-api-key-here</span><br></pre></td></tr></table></figure><p>API Key 在用户后台的 <strong>个人信息</strong> 页面获取。</p><h1 id="创建会话"><a href="#创建会话" class="headerlink" title="创建会话"></a>创建会话</h1><p>在生图之前，先创建一个会话。会话用来组织和管理生图任务，后续的文生图和图生图请求都挂载到同一个会话下。</p><p><strong>请求</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">POST /api/ai-chat/sessions</span><br></pre></td></tr></table></figure><p><strong>请求参数</strong></p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;title&quot;</span><span class="punctuation">:</span> <span class="string">&quot;测试api生成会话&quot;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><table><thead><tr><th>参数</th><th>类型</th><th>必填</th><th>说明</th></tr></thead><tbody><tr><td>title</td><td>string</td><td>是</td><td>会话标题，用于区分不同的生图任务</td></tr></tbody></table><p><strong>响应示例</strong></p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;session_id&quot;</span><span class="punctuation">:</span> <span class="string">&quot;session_81288c923af9&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;title&quot;</span><span class="punctuation">:</span> <span class="string">&quot;测试api生成会话&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;created_at&quot;</span><span class="punctuation">:</span> <span class="string">&quot;2026-07-08T20:00:00.000+08:00&quot;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><p><code>session_id</code> 是后续文生图和图生图请求的必填参数，需要保存下来。</p><h1 id="文生图"><a href="#文生图" class="headerlink" title="文生图"></a>文生图</h1><p>根据文本提示词生成图片。</p><p><strong>请求</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">POST /api/ai-chat/generate-text-to-image</span><br></pre></td></tr></table></figure><p><strong>请求参数</strong></p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;session_id&quot;</span><span class="punctuation">:</span> <span class="string">&quot;session_d6d8bc43b761&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;prompt&quot;</span><span class="punctuation">:</span> <span class="string">&quot;一只橘猫坐在窗台上，夕阳洒在它身上&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;image_size&quot;</span><span class="punctuation">:</span> <span class="string">&quot;auto&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;image_resolution&quot;</span><span class="punctuation">:</span> <span class="string">&quot;1K&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;image_count&quot;</span><span class="punctuation">:</span> <span class="number">1</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;model&quot;</span><span class="punctuation">:</span> <span class="string">&quot;nano-banana-2&quot;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><table><thead><tr><th>参数</th><th>类型</th><th>必填</th><th>说明</th></tr></thead><tbody><tr><td>session_id</td><td>string</td><td>是</td><td>创建会话时返回的会话 ID</td></tr><tr><td>prompt</td><td>string</td><td>是</td><td>图片描述提示词</td></tr><tr><td>image_size</td><td>string</td><td>否</td><td>图片比例：auto（自动）、1:1、16:9、9:16、4:3、3:4</td></tr><tr><td>image_resolution</td><td>string</td><td>否</td><td>输出分辨率：1K、2K、4K</td></tr><tr><td>image_count</td><td>integer</td><td>否</td><td>生成图片数量，默认 1，最大 4</td></tr><tr><td>model</td><td>string</td><td>是</td><td>生图模型：nano-banana、nano-banana-2、nano-banana-pro</td></tr></tbody></table><p><strong>响应示例</strong></p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;success&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;data&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;task_id&quot;</span><span class="punctuation">:</span> <span class="string">&quot;task_ai_22ea54346830&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;status&quot;</span><span class="punctuation">:</span> <span class="string">&quot;pending&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;image_count&quot;</span><span class="punctuation">:</span> <span class="number">1</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;message&quot;</span><span class="punctuation">:</span> <span class="string">&quot;图片生成任务已创建&quot;</span></span><br><span class="line">  <span class="punctuation">&#125;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><p>接口返回后不代表图片已生成完成，需要用 <code>task_id</code> 轮询获取最终结果。</p><p><strong>查询生成状态</strong></p><p>轮询 <code>GET /api/ai-chat/images/{task_id}</code> 获取生成进度和结果。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">GET /api/ai-chat/images/task_a1b2c3d4</span><br></pre></td></tr></table></figure><p><strong>生成中响应</strong></p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;success&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;data&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;task_id&quot;</span><span class="punctuation">:</span> <span class="string">&quot;task_ai_22ea54346830&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;status&quot;</span><span class="punctuation">:</span> <span class="string">&quot;processing&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;image_count&quot;</span><span class="punctuation">:</span> <span class="number">1</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;images&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;generation_type&quot;</span><span class="punctuation">:</span> <span class="string">&quot;text-to-image&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;prompt&quot;</span><span class="punctuation">:</span> <span class="string">&quot;生成一张真人配音员招募的海报&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;image_size&quot;</span><span class="punctuation">:</span> <span class="string">&quot;auto&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;source_image_url&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span></span><br><span class="line">  <span class="punctuation">&#125;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><p><strong>生成完成响应</strong></p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;success&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;data&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;task_id&quot;</span><span class="punctuation">:</span> <span class="string">&quot;task_ai_22ea54346830&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;status&quot;</span><span class="punctuation">:</span> <span class="string">&quot;completed&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;image_count&quot;</span><span class="punctuation">:</span> <span class="number">1</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;images&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">      <span class="punctuation">&#123;</span></span><br><span class="line">        <span class="attr">&quot;image_index&quot;</span><span class="punctuation">:</span> <span class="number">0</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;status&quot;</span><span class="punctuation">:</span> <span class="string">&quot;completed&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;image_id&quot;</span><span class="punctuation">:</span> <span class="number">6914253</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;cdn_image_url&quot;</span><span class="punctuation">:</span> <span class="string">&quot;https://img-cdn.lusyoe.cn/images/lusyoe/2026/07/08/muv540x7.jpg&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;oss_image_url&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;error_message&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span></span><br><span class="line">      <span class="punctuation">&#125;</span></span><br><span class="line">    <span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;generation_type&quot;</span><span class="punctuation">:</span> <span class="string">&quot;text-to-image&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;prompt&quot;</span><span class="punctuation">:</span> <span class="string">&quot;生成一张真人配音员招募的海报&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;image_size&quot;</span><span class="punctuation">:</span> <span class="string">&quot;auto&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;source_image_url&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;created_at&quot;</span><span class="punctuation">:</span> <span class="string">&quot;2026-07-08T20:07:49&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;updated_at&quot;</span><span class="punctuation">:</span> <span class="string">&quot;2026-07-08T20:08:24&quot;</span></span><br><span class="line">  <span class="punctuation">&#125;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><p>推荐轮询间隔为 3-5 秒，直到 <code>status</code> 变为 <code>completed</code> 或 <code>failed</code>。</p><h1 id="图生图"><a href="#图生图" class="headerlink" title="图生图"></a>图生图</h1><p>在文生图的基础上，传入一张或多张参考图片，让 AI 根据参考图的内容和风格生成新图。</p><p>适合的场景：给产品图换背景、根据线稿生成上色图、以某张图的风格生成新内容。</p><p><strong>请求</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">POST /api/ai-chat/generate-image-to-image</span><br></pre></td></tr></table></figure><p><strong>请求参数</strong></p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;session_id&quot;</span><span class="punctuation">:</span> <span class="string">&quot;session_d6d8bc43b761&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;prompt&quot;</span><span class="punctuation">:</span> <span class="string">&quot;将该产品放置在厨房环境中，使用自然的色彩和光线。确保产品保持真实比例，在场景中大小协调。产品需清晰可见并作为主要焦点，光影和反射效果真实自然。背景应与环境融合，但不能喧宾夺主，确保突出产品。&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;source_image_urls&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">    <span class="string">&quot;https://img-cdn.lusyoe.cn/images/lusyoe/2025/10/23/ej96myumf2.webp&quot;</span></span><br><span class="line">  <span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;image_size&quot;</span><span class="punctuation">:</span> <span class="string">&quot;1:1&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;image_resolution&quot;</span><span class="punctuation">:</span> <span class="string">&quot;1K&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;image_count&quot;</span><span class="punctuation">:</span> <span class="number">1</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;model&quot;</span><span class="punctuation">:</span> <span class="string">&quot;nano-banana-2&quot;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><table><thead><tr><th>参数</th><th>类型</th><th>必填</th><th>说明</th></tr></thead><tbody><tr><td>session_id</td><td>string</td><td>是</td><td>会话 ID</td></tr><tr><td>prompt</td><td>string</td><td>是</td><td>提示词，描述希望生成的画面</td></tr><tr><td>source_image_urls</td><td>array</td><td>是</td><td>参考图片的 CDN URL 列表，至少传一张</td></tr><tr><td>image_size</td><td>string</td><td>否</td><td>图片比例，同上</td></tr><tr><td>image_resolution</td><td>string</td><td>否</td><td>输出分辨率：1K、2K、4K</td></tr><tr><td>image_count</td><td>integer</td><td>否</td><td>生成图片数量，默认 1，最大 4</td></tr><tr><td>model</td><td>string</td><td>是</td><td>生图模型：nano-banana、nano-banana-2、nano-banana-pro</td></tr></tbody></table><p><strong>响应示例</strong></p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;success&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;data&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;task_id&quot;</span><span class="punctuation">:</span> <span class="string">&quot;task_ai_22ea54346830&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;status&quot;</span><span class="punctuation">:</span> <span class="string">&quot;pending&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;image_count&quot;</span><span class="punctuation">:</span> <span class="number">1</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;message&quot;</span><span class="punctuation">:</span> <span class="string">&quot;图片生成任务已创建&quot;</span></span><br><span class="line">  <span class="punctuation">&#125;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><p>生成的图片同样需要用 <code>GET /api/ai-chat/images/{task_id}</code> 轮询获取结果。</p><h1 id="错误码"><a href="#错误码" class="headerlink" title="错误码"></a>错误码</h1><table><thead><tr><th>HTTP 状态码</th><th>说明</th></tr></thead><tbody><tr><td>200</td><td>请求成功</td></tr><tr><td>400</td><td>参数错误，缺少必填字段或格式不正确</td></tr><tr><td>401</td><td>API Key 无效或缺失</td></tr><tr><td>404</td><td>会话不存在或任务不存在</td></tr><tr><td>429</td><td>请求频率过高，请稍后重试</td></tr><tr><td>500</td><td>服务内部错误</td></tr></tbody></table><h1 id="完整调用示例"><a href="#完整调用示例" class="headerlink" title="完整调用示例"></a>完整调用示例</h1><p>用 curl 完成一次文生图的完整流程：</p><p><strong>创建会话</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">curl -X POST https://img.lusyoe.com/api/ai-chat/sessions \</span><br><span class="line">  -H <span class="string">&quot;Content-Type: application/json&quot;</span> \</span><br><span class="line">  -H <span class="string">&quot;X-API-KEY: your-api-key&quot;</span> \</span><br><span class="line">  -d <span class="string">&#x27;&#123;&quot;title&quot;: &quot;测试生图&quot;&#125;&#x27;</span></span><br></pre></td></tr></table></figure><p><strong>提交文生图任务</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">curl -X POST https://img.lusyoe.com/api/ai-chat/generate-text-to-image \</span><br><span class="line">  -H <span class="string">&quot;Content-Type: application/json&quot;</span> \</span><br><span class="line">  -H <span class="string">&quot;X-API-KEY: your-api-key&quot;</span> \</span><br><span class="line">  -d <span class="string">&#x27;&#123;</span></span><br><span class="line"><span class="string">    &quot;session_id&quot;: &quot;session_d6d8bc43b761&quot;,</span></span><br><span class="line"><span class="string">    &quot;prompt&quot;: &quot;一只橘猫坐在窗台上&quot;,</span></span><br><span class="line"><span class="string">    &quot;image_size&quot;: &quot;auto&quot;,</span></span><br><span class="line"><span class="string">    &quot;image_resolution&quot;: &quot;1K&quot;,</span></span><br><span class="line"><span class="string">    &quot;image_count&quot;: 1,</span></span><br><span class="line"><span class="string">    &quot;model&quot;: &quot;nano-banana-2&quot;</span></span><br><span class="line"><span class="string">  &#125;&#x27;</span></span><br></pre></td></tr></table></figure><p><strong>轮询结果</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">curl -H <span class="string">&quot;X-API-KEY: your-api-key&quot;</span> \</span><br><span class="line">  https://img.lusyoe.com/api/ai-chat/images/task_a1b2c3d4</span><br></pre></td></tr></table></figure>]]>
    </content>
    <id>https://blog.lusyoe.com/article/qingping-img-ai-image-api</id>
    <link href="https://blog.lusyoe.com/article/qingping-img-ai-image-api"/>
    <published>2026-07-08T20:03:00.000+08:00</published>
    <summary>青萍AI图床 AI 生图接口文档，包含创建会话、文生图、图生图三个核心接口的请求方式、参数说明和响应示例，以及基于 task_id 轮询生成状态的使用方式。</summary>
    <title>青萍AI图床：AI 生图接口文档</title>
    <updated>2026-07-08T20:03:00.000+08:00</updated>
  </entry>
  <entry>
    <author>
      <name>青萍叙事</name>
    </author>
    <category term="产品" scheme="https://blog.lusyoe.com/categories/%E4%BA%A7%E5%93%81/"/>
    <category term="一人企业" scheme="https://blog.lusyoe.com/tags/%E4%B8%80%E4%BA%BA%E4%BC%81%E4%B8%9A/"/>
    <category term="统一认证" scheme="https://blog.lusyoe.com/tags/%E7%BB%9F%E4%B8%80%E8%AE%A4%E8%AF%81/"/>
    <category term="产品设计" scheme="https://blog.lusyoe.com/tags/%E4%BA%A7%E5%93%81%E8%AE%BE%E8%AE%A1/"/>
    <content>
      <![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>做一人企业，最怕什么？</p><p>不是技术难题，也不是没用户，而是每次想做点新东西，都要从零开始。</p><p>最近我折腾了几个产品，有一个感慨越来越深：认证体系这件事，开始越随意，后面越痛苦。<br>但反过来，如果一开始就搭好统一认证，后面做新功能、新产品、新端口的效率能翻倍。</p><p>这篇就来聊聊，统一认证对一人企业到底意味着什么。</p><h1 id="更快地试错"><a href="#更快地试错" class="headerlink" title="更快地试错"></a>更快地试错</h1><p>一人企业最大的优势是灵活。</p><p>想做个新功能，今天想出来，明天就能动手。<br>但如果你每次新开一个产品都要重新搭用户系统：注册、登录、密码重置、邮箱验证、OAuth 接入，光这些基础工作就能耗掉好几天。<br>几天时间，对一个 solo 创业者来说是奢侈的。</p><p>有统一认证就不一样了。</p><p>新产品的用户体系直接从老系统继承过来。<br>用户在 A 产品注册过，打开 B 产品直接用同一个账号登录，连注册页面都不用做。<br>省下来的时间可以去验证产品方向、去跟种子用户聊需求、去打磨核心体验。</p><p>快速试错的前提是快速，而统一认证把最耗时的基建砍掉了。</p><h1 id="多端统一"><a href="#多端统一" class="headerlink" title="多端统一"></a>多端统一</h1><p>一人企业做到一定阶段，通常不会只有一个端口。</p><p>Web 端、微信小程序、移动 App，可能还有公众号、H5 页面。<br>每个端口如果各自建一套用户体系，问题就来了：用户在 Web 上注册了，到小程序还得重新注册；在 App 里充了会员，Web 端查不到；数据完全割裂。</p><p>统一认证解决的就是这个问题。</p><p>不管用户从哪个端口进来，背后都是同一个身份。<br>小程序登录的资料在 Web 端能查到，App 里产生的行为数据跟 Web 端打通。<br>对用户来说，一个账号走遍所有端口，不用反复注册、反复填信息。</p><p>对开发者来说更省事，后端只管跟认证中心交互，不用每个端口维护一套独立的用户表。</p><h1 id="权益继承"><a href="#权益继承" class="headerlink" title="权益继承"></a>权益继承</h1><p>这是统一认证最有价值的地方。</p><p>你做了产品 A，用户积累了 1000 积分、买了年费会员、订阅了高级功能。<br>后来你做了产品 B，跟 A 是同一个生态。<br>如果 B 有自己的认证体系，用户到了 B 一切从零开始，之前的积分和会员全都不算数。<br>用户凭什么要重新积累？</p><p>但如果 A 和 B 共享同一个认证中心，用户的积分、会员等级、订阅状态就能跨产品继承。<br>到了 B 产品，发现自己的会员还在、积分还能用，用户自然愿意尝试新产品。</p><p>这就是网络的积累效应。</p><p>每个新产品不再是孤岛，而是已有用户生态的延伸。<br>你不需要在新产品上从零做用户增长，因为老用户带着权益自动过来了。<br>对一人企业来说，这意味着每一个新产品的冷启动成本都大幅降低。</p><h1 id="一人企业的统一认证实践：青萍统一认证"><a href="#一人企业的统一认证实践：青萍统一认证" class="headerlink" title="一人企业的统一认证实践：青萍统一认证"></a>一人企业的统一认证实践：青萍统一认证</h1><p>前面说的都是理念，但理念落不了地就没用。</p><p>我自己维护的产品正好需要这套能力。<br>Web 站一个、移动端一个、微信小程序一个，三个端口各自管用户，每次新开一个产品，用户体系就得重新做一遍。<br>后来我在青萍统一认证系统上把这些问题一次性解决了。</p><p>青萍统一认证基于标准 OIDC（OpenID Connect）协议，同时完整支持 OAuth 2.0。<br>核心能力就三块：多网站单点登录、移动端和小程序统一登录、用户权益跨产品同步。</p><p><strong>多网站单点登录。</strong><br>你在青萍AI语音注册了账号，打开青萍AI视频或青萍AI图床不用再注册，点一下授权就能直接登录。<br>支持跨域无缝会话共享，登录态在所有接入应用间自动同步。<br>开发者侧只需要在认证中心注册一个客户端 ID，配置回调地址，对接标准 OIDC 端点即可。<br>不同产品之间的登录态完全隔离，安全性不降级。</p><p><strong>移动端和小程序统一登录。</strong><br>微信小程序用 wx.login 获取 code，移动 App 用手机号验证码或微信授权，都指向同一个用户 ID。<br>还能绑定 GitHub、Notion 等第三方身份源，用户免注册直接登录。<br>用户在小程序里看到的积分和订单，跟 Web 端完全一致。<br>对于大多数一人企业来说，小程序加 Web 是获客的主战场，这套打通之后，用户无论在哪个端口发起操作，后端处理起来都一样。</p><p><strong>权益跨产品继承。</strong><br>用户在产品 A 里累积的积分、会员等级、订阅时长，到了产品 B 自动生效。<br>不用做数据迁移，不用反复找客服，认证中心就是权益中心。</p><p>这套系统对一人企业友好的地方在于：不需要专门搭一套微服务架构来支撑。<br>认证中心独立运行，其他产品通过 API 对接，改一个地方所有产品都生效。<br>你只管写业务代码，用户体系交给它。</p><h1 id="从第一个产品开始"><a href="#从第一个产品开始" class="headerlink" title="从第一个产品开始"></a>从第一个产品开始</h1><p>认证体系这件事，从第一个产品开始做，成本最低。<br>等有了三个产品再回头改造，就要迁移数据、合并账号、解决冲突，工作量翻倍。</p><p>所以如果你现在正在做一个新产品，哪怕是 demo 阶段，也值得先把认证独立出来。<br>这个习惯养成了，后面的每一个新功能、新产品、新端口，都会跑得更快。</p>]]>
    </content>
    <id>https://blog.lusyoe.com/article/one-person-business-unified-auth</id>
    <link href="https://blog.lusyoe.com/article/one-person-business-unified-auth"/>
    <published>2026-07-07T22:04:31.000+08:00</published>
    <summary>一人企业的认证体系怎么设计？本文从快速试错、多端统一、权益继承三个角度，聊聊为什么统一认证是 solo 创业者最值得投入的基础设施之一。</summary>
    <title>真心建议做一人企业的你，先把统一认证搞定</title>
    <updated>2026-07-07T22:04:31.000+08:00</updated>
  </entry>
  <entry>
    <author>
      <name>青萍叙事</name>
    </author>
    <category term="微信" scheme="https://blog.lusyoe.com/categories/%E5%BE%AE%E4%BF%A1/"/>
    <category term="公众号" scheme="https://blog.lusyoe.com/tags/%E5%85%AC%E4%BC%97%E5%8F%B7/"/>
    <category term="企业微信" scheme="https://blog.lusyoe.com/tags/%E4%BC%81%E4%B8%9A%E5%BE%AE%E4%BF%A1/"/>
    <category term="微信生态" scheme="https://blog.lusyoe.com/tags/%E5%BE%AE%E4%BF%A1%E7%94%9F%E6%80%81/"/>
    <content>
      <![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>最近刚把个人公众号迁到了企业主体，折腾了一趟流程下来，发现有很多值得说的东西。<br>所以今天就聊聊为什么要迁移，以及迁移之后到底拿到了什么好处。</p><p>如果你运营过一个个人公众号，应该多少体会过那种憋屈感：想做个小程序嵌入文章，不行；想把视频号的直播直接推到公众号，不行；想给用户发个服务通知，不行；甚至想给公众号搞个正经菜单，还是不行。</p><p>不是你不会用，是个人号的权限就这么多。</p><h1 id="为什么个人号限制这么多"><a href="#为什么个人号限制这么多" class="headerlink" title="为什么个人号限制这么多"></a>为什么个人号限制这么多</h1><p>先说清楚一个基础设定。<br>微信公众号分两种：<strong>公众号</strong>（原订阅号）和 <strong>服务号</strong>。</p><p>个人只能注册公众号，而且个人主体没有微信认证。<br>企业既可以注册公众号，也可以注册服务号，认证后还能拿到更多接口权限。</p><p>没有认证，意味着没有蓝 V 标识，没有自定义菜单，没有模板消息，没有带参数的二维码，更别谈微信支付。</p><p>换句话说，个人号的公众号本质上只是个内容发布通道。<br>你写文章、发文章、读者看文章，这个流程没问题。<br>但你想要公众号跟其他微信产品联动，对不起，这条路封死了。</p><h1 id="迁移之后拿到了什么"><a href="#迁移之后拿到了什么" class="headerlink" title="迁移之后拿到了什么"></a>迁移之后拿到了什么</h1><p>好，下面说重点。<br>企业认证到底能解锁什么东西。</p><h2 id="蓝-V-认证带来的信任感"><a href="#蓝-V-认证带来的信任感" class="headerlink" title="蓝 V 认证带来的信任感"></a>蓝 V 认证带来的信任感</h2><p>微信认证费用是 300 元一次，有效期一年，到期需要年审。</p><p>认证之后，公众号资料页会显示蓝 V 标识，搜索结果里认证号的权重也比未认证号高。<br>对读者来说，看到蓝 V 和看到 <strong>个人</strong> 两个字的感觉完全不同，特别是在商业场景下。</p><h2 id="自定义菜单和页面模板"><a href="#自定义菜单和页面模板" class="headerlink" title="自定义菜单和页面模板"></a>自定义菜单和页面模板</h2><p>这是最直接的感受提升。</p><p>个人号只能用一个极其简陋的自动回复充当导航，企业认证后可以配置三层自定义菜单。<br>配合页面模板功能，你可以把历史文章、产品介绍、联系方式等组织成几个独立页面，菜单一键跳转。</p><p>公众号瞬间从一个 <strong>发文机器</strong> 变成了一个像样的信息站点。</p><h2 id="小程序：终于能直接放了"><a href="#小程序：终于能直接放了" class="headerlink" title="小程序：终于能直接放了"></a>小程序：终于能直接放了</h2><p>个人号的文章里不能插入小程序卡片，不能跳转到小程序。</p><p>企业认证后，这个问题就解决了。<br>你可以把公众号跟公司的小程序绑定，文章里直接插入小程序卡片，读者点进去就能用你的服务。<br>公众号做流量引导、小程序做服务交付，这是微信生态里最经典的搭配。</p><h2 id="企业微信：客服和用户运营"><a href="#企业微信：客服和用户运营" class="headerlink" title="企业微信：客服和用户运营"></a>企业微信：客服和用户运营</h2><p>企业认证后，公众号可以跟企业微信打通。</p><p>用户关注公众号后，可以一键添加企业微信客服。<br>配合企业微信的客户标签、群发、朋友圈等功能，做私域运营就顺手多了。<br>很多品牌的生意实际上就是从公众号引流到企业微信，再在企微里完成转化和复购。</p><h2 id="视频号：打通内容矩阵"><a href="#视频号：打通内容矩阵" class="headerlink" title="视频号：打通内容矩阵"></a>视频号：打通内容矩阵</h2><p>如果你的公司有视频号，企业认证的公众号可以直接绑定。</p><p>绑定后可以在公众号主页展示视频号入口，视频号直播时也可以推送到公众号。<br>图文 + 短视频 + 直播，三个内容形式串起来，比单一渠道的触达效果好太多。</p><p>此处需配图：公众号主页展示视频号入口的截图</p><h2 id="模板消息：该通知的时候不打扰"><a href="#模板消息：该通知的时候不打扰" class="headerlink" title="模板消息：该通知的时候不打扰"></a>模板消息：该通知的时候不打扰</h2><p>这个功能很多人不知道。</p><p>服务号开通模板消息后，可以在用户完成某个操作后（比如预约成功、订单状态变更）发送结构化的通知消息。<br>通知不占用每月的群发次数，直接出现在用户的聊天列表里，体验比群发好得多。</p><p>个人号没有这个能力，只能靠群发文章去触达用户，太粗暴了。</p><h2 id="带参数的二维码"><a href="#带参数的二维码" class="headerlink" title="带参数的二维码"></a>带参数的二维码</h2><p>这是做渠道投放的利器。</p><p>你可以生成多个不同的关注二维码，每个二维码对应一个渠道（比如公众号底部菜单、线下海报、官网入口）。<br>用户从哪里扫码关注的，后台一清二楚，还能自动打标签分组。</p><p>个人号只能用系统默认的那个关注二维码，完全没法做渠道归因。</p><h1 id="迁移的代价"><a href="#迁移的代价" class="headerlink" title="迁移的代价"></a>迁移的代价</h1><p>好处说完了，说说代价。</p><h2 id="准备工作"><a href="#准备工作" class="headerlink" title="准备工作"></a>准备工作</h2><p>迁移不能直接在原号上改主体，你得先注册一个新的企业号作为目标账号，然后把原号的内容、粉丝、违规记录迁移过去。</p><p>目标账号必须是企业或个体工商户主体，个人号不能作为接收方。<br>如果你还没有企业，走个体户注册是最低成本的方案。</p><h2 id="费用"><a href="#费用" class="headerlink" title="费用"></a>费用</h2><p>迁移本身有成本。<br>微信官方收取 300 元审核费，外加一份公证书的费用。<br>如果自己跑线下公证处，大概 800 元左右。<br>线上公证平台（比如存证云）会便宜一些，499 元左右。<br>同主体迁移（原号和新号的法人是同一人）不需要公证，能省一笔。</p><p>之后每年还有微信认证年审的 300 元。</p><p>总支出大概是 800 到 1100 元的第一年投入，之后每年 300 元。</p><h2 id="时间"><a href="#时间" class="headerlink" title="时间"></a>时间</h2><p>迁移流程走下来，顺利的话 3 到 7 个工作日。<br>主要耗时在公证和微信审核环节。<br>如果资料准备齐全，线上公证能快不少。</p><h2 id="自动回复"><a href="#自动回复" class="headerlink" title="自动回复"></a>自动回复</h2><p>之前设置的关注自动回复以及关键词回复都没有了，需要重新设置。</p><h2 id="私信"><a href="#私信" class="headerlink" title="私信"></a>私信</h2><p>之前账号的私信也没有迁移过来，全部都清空了。</p><h2 id="合集"><a href="#合集" class="headerlink" title="合集"></a>合集</h2><p>之前创建的合集也都被清空了，这点挺意外的。</p><h1 id="要不要走这条路"><a href="#要不要走这条路" class="headerlink" title="要不要走这条路"></a>要不要走这条路</h1><p>如果你只是写写个人博客，不用考虑变现，也不想折腾产品和用户运营，那个人号够用了。</p><p>一旦你有以下需求中的任何一条，就该认真考虑迁移：</p><ul><li>想做小程序跟公众号联动</li><li>想接入微信支付做电商</li><li>想用企业微信做客服和私域</li><li>想把视频号的内容导入公众号</li><li>想做渠道投放，追踪粉丝来源</li><li>想配置正经的自定义菜单</li></ul><p>我自己的感受是，迁移之后公众号不再只是一个 <strong>发文的地方</strong>，它成了微信生态里真正的枢纽。<br>内容、服务、交易、客服，所有东西通过这个号串起来。</p><p>300 块一年换来这么多能力，算下来还是划算的。</p>]]>
    </content>
    <id>https://blog.lusyoe.com/article/personal-wechat-account-migration-experience</id>
    <link href="https://blog.lusyoe.com/article/personal-wechat-account-migration-experience"/>
    <published>2026-07-07T18:00:00.000+08:00</published>
    <summary>从个人公众号迁移到企业公众号到底值不值？本文结合亲身经验，梳理了企业号的五大核心优势：微信认证、自定义菜单、小程序/视频号/企业微信互通、模板消息、渠道二维码等，帮你判断是否有必要走迁移这条路。</summary>
    <title>从个人公众号迁移到企业公众号经验总结</title>
    <updated>2026-07-07T18:00:00.000+08:00</updated>
  </entry>
  <entry>
    <author>
      <name>青萍叙事</name>
    </author>
    <category term="Hermes" scheme="https://blog.lusyoe.com/categories/Hermes/"/>
    <category term="AI" scheme="https://blog.lusyoe.com/tags/AI/"/>
    <category term="HermesAgent" scheme="https://blog.lusyoe.com/tags/HermesAgent/"/>
    <category term="开源" scheme="https://blog.lusyoe.com/tags/%E5%BC%80%E6%BA%90/"/>
    <content>
      <![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>今天我们要聊的是一则大新闻。</p><p>7月3日晚，豆包发布通知，智能体功能将于7月15日正式下线。<br>用户将无法新建智能体，已创建的也无法调用和运行。<br>到10月15日，相关数据会被彻底处理，连查看都做不到。</p><p>仅仅一天后，千问（通义千问）也发了同样的通知。<br>千问的拟人化互动类智能体7月10日先行下线，7月15日全面关闭。</p><p>两家大厂的智能体功能，就这么说关就关了。</p><h1 id="为什么是7月15日"><a href="#为什么是7月15日" class="headerlink" title="为什么是7月15日"></a>为什么是7月15日</h1><p>你可能猜到了，这个日期不是巧合。</p><p>《人工智能拟人化互动服务管理暂行办法》将于2026年7月15日正式施行。<br>这是国内首部专门针对AI拟人化互动服务的监管法规，由网信办、发改委、工信部等五部门联合发布。</p><p>办法对虚拟恋人、深度角色扮演、情感依附类AI服务设立了强约束。<br>用户自建智能体容易出现虚拟陪伴、侵权人设、低俗内容，海量自制内容的审核压力巨大。<br>6月底上海刚通报了清朗行动的结果，累计下架1.4万个违规智能体。</p><p>豆包和千问把下线日定在7月15日，正好是办法施行的同一天。<br>这不是巧合，是平台们在合规大考前做出的选择。</p><h1 id="平台依赖的风险"><a href="#平台依赖的风险" class="headerlink" title="平台依赖的风险"></a>平台依赖的风险</h1><p>这件事暴露了一个扎心的事实：你在云平台上辛辛苦苦调教出来的智能体，说没就没了。</p><p>你定义的人设、积累的对话记忆、精心调试的规则，都跟着功能下线一起归零。<br>豆包还能备份一下，但备份的是文本截图，不是可恢复的智能体配置。<br>千问连备份指引都语焉不详。</p><p>这不只是豆包和千问的问题。<br>只要你的智能体运行在别人的服务器上，就永远面临同一个风险：平台随时可能因为合规、业务调整、成本控制等原因关停功能。</p><p>如果你的智能体只是用来聊天解闷，影响还小。<br>但如果你已经把AI智能体融入工作流，用来处理任务、管理信息、自动化操作，那这种依赖就是实实在在的风险。</p><h1 id="换个思路：用开源自托管的智能体"><a href="#换个思路：用开源自托管的智能体" class="headerlink" title="换个思路：用开源自托管的智能体"></a>换个思路：用开源自托管的智能体</h1><p>那有没有一种方案，智能体的配置、记忆、运行都完全掌握在自己手里？</p><p>有，就是自托管的开源智能体。</p><p>今天要介绍的是 <strong>Hermes Agent</strong>，由 Nous Research 开发的开源自主AI智能体框架。<br>它不是聊天机器人，也不是代码补全工具，而是一个部署在你服务器上、持续学习的数字助理。</p><p>Hermes 的核心能力包括：</p><p><strong>持久记忆。</strong><br>跨会话记住你的偏好、项目和环境。<br>运行越久越了解你，不用每次都从头解释上下文。</p><p><strong>自动技能创建。</strong><br>当 Hermes 解决了一个复杂问题，它会自动写下可复用的技能文档，以后遇到类似场景直接调用。</p><p><strong>多平台消息网关。</strong><br>通过一个网关进程连接飞书、Telegram、Discord、微信等多个平台。<br>你在群聊里就能叫它干活。</p><p><strong>定时自动化任务。</strong><br>内置 cron 调度器，可以设置每日报告、定时提醒、周期性检查。<br>全部无人值守运行。</p><p><strong>浏览器与网页控制。</strong><br>它可以直接操作浏览器，帮你抓信息、填表单、做自动化操作。</p><p>以上所有数据都存储在你自己的机器上，存在 ~&#x2F;.hermes&#x2F; 目录下。<br>MIT 开源许可，没有遥测，没有数据收集，没有什么能远程关掉你的智能体。</p><h1 id="和云平台智能体的对比"><a href="#和云平台智能体的对比" class="headerlink" title="和云平台智能体的对比"></a>和云平台智能体的对比</h1><p>用豆包、千问这类平台自建智能体，本质上是租用平台的能力。<br>你定义角色、设定规则，但底层模型、运行环境、数据存储全在对方手里。</p><p>用 Hermes Agent 则是拥有自己的智能体。<br>你选择底层模型（OpenRouter 200+ 模型、本地 Ollama、vLLM 都可以），掌握所有数据，随时可以调整配置。<br>就算外部平台出了什么变化，你的智能体不会受影响。</p><p>用一句话说就是：云平台的智能体是借的，Hermes 是自己的。</p><h1 id="快速上手"><a href="#快速上手" class="headerlink" title="快速上手"></a>快速上手</h1><p>Hermes Agent 的安装非常简单，一条命令就行：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash</span><br></pre></td></tr></table></figure><p>支持 macOS、Linux 和 WSL2，不需要 sudo 权限，自动安装所有依赖。</p><p>装完之后运行 <code>hermes setup</code> 配置模型，然后就可以开始对话了：<br><code>hermes</code></p><p>整个流程不到十分钟就能跑起来。<br>如果你想接入消息平台（飞书、Telegram等），再跑一遍 <code>hermes gateway setup</code> 即可。</p><p>有了 Hermes，你不用再担心智能体哪天会下线。<br>你的数据在你手里，你的智能体在你手里，谁也关不掉。</p>]]>
    </content>
    <id>https://blog.lusyoe.com/article/doubao-qwen-shutdown-use-hermes</id>
    <link href="https://blog.lusyoe.com/article/doubao-qwen-shutdown-use-hermes"/>
    <published>2026-07-04T17:00:00.000+08:00</published>
    <summary>豆包和千问同时宣布智能体功能将于7月15日下线，恰好与《人工智能拟人化互动服务管理暂行办法》施行同日。国内云平台智能体面临合规大考，你的角色、记忆和配置随时可能归零。是时候考虑开源自托管的 Hermes Agent 了。</summary>
    <title>豆包千问集体下线智能体，是时候拥抱 Hermes Agent 了</title>
    <updated>2026-07-04T17:00:00.000+08:00</updated>
  </entry>
  <entry>
    <author>
      <name>青萍叙事</name>
    </author>
    <category term="青萍商业平台" scheme="https://blog.lusyoe.com/categories/%E9%9D%92%E8%90%8D%E5%95%86%E4%B8%9A%E5%B9%B3%E5%8F%B0/"/>
    <category term="青萍AI语音" scheme="https://blog.lusyoe.com/tags/%E9%9D%92%E8%90%8DAI%E8%AF%AD%E9%9F%B3/"/>
    <category term="配音兼职" scheme="https://blog.lusyoe.com/tags/%E9%85%8D%E9%9F%B3%E5%85%BC%E8%81%8C/"/>
    <category term="声音变现" scheme="https://blog.lusyoe.com/tags/%E5%A3%B0%E9%9F%B3%E5%8F%98%E7%8E%B0/"/>
    <content>
      <![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>今天我们要聊的是配音兼职渠道这件事。</p><p>绝大部分行业的兼职，多多少少都能挣到点零花钱。<br>问题从来不是”能不能挣”，而是渠道从哪里来。</p><p>配音行业比大多数行业都要封闭一些。<br>行业资源长期集中在少数人手里，想入行接单通常靠熟人介绍、师徒带路，或者直接签约工作室。<br>对新人来说，没人引路可能连门都摸不着。</p><h1 id="配音兼职的-5-种常见渠道"><a href="#配音兼职的-5-种常见渠道" class="headerlink" title="配音兼职的 5 种常见渠道"></a>配音兼职的 5 种常见渠道</h1><p>新人想找配音兼职，常见的有这么几条路。</p><p><strong>大平台入驻。</strong><br>喜马拉雅、懒人听书、蜻蜓FM 这些有声平台都有配音需求。<br>但门槛不低，资料审核周期长，新人拿不到流量推荐，平台抽成普遍在 30% 到 50% 之间。<br>这条路更适合有积累的人，新人起步比较吃力。</p><p><strong>配音工作室或社团。</strong><br>它们从需求方接单，再分发给配音师，赚中间差价。<br>优点是有人帮你对接客户，缺点是抽成不透明。<br>30% 算良心价，抽 50% 以上的也不少见。<br>辛辛苦苦录完，到手只剩一半。</p><p><strong>社交群组招募。</strong><br>QQ 群、微信群、豆瓣小组里到处是”长期招募配音兼职”的广告。<br>门槛确实低，但风险也最高。<br>最常见的就是让你交押金、交培训费、交认证费。<br>钱交完了，群要么解散，要么长期没单。</p><p><strong>淘宝店铺应聘。</strong><br>搜”配音服务”，找销量高的店铺，直接问客服要不要兼职配音员。<br>符合要求会被拉进接单群，算是一条相对稳定的路。</p><p><strong>自己做账号。</strong><br>在抖音、小红书发配音作品，简介里写上”配音接单”，让甲方主动来找你。<br>这条路的回报周期最长，但积累的是自己的品牌和资源。</p><h1 id="配音兼职最大的坑：先交钱"><a href="#配音兼职最大的坑：先交钱" class="headerlink" title="配音兼职最大的坑：先交钱"></a>配音兼职最大的坑：先交钱</h1><p>以上渠道各有优劣，但对新人来说最关键的只有一句话：别掏钱。</p><p>很多打着”配音兼职”旗号的机构，真实目的是卖课。<br>先用”0 元试听””在家接单赚钱”吸引你，再展示学员收入截图，诱导你花几千甚至上万买课。<br>中消协都曾点名过这类套路。<br>记住：任何让你先交钱再接单的，直接拉黑。</p><h1 id="一个真正对新人友好的渠道"><a href="#一个真正对新人友好的渠道" class="headerlink" title="一个真正对新人友好的渠道"></a>一个真正对新人友好的渠道</h1><p>那有没有不给钱就能直接接单的平台？</p><p>青萍AI语音平台可以了解一下。</p><p>它是一个 AI 和真人双引擎的语音创作平台。<br>AI 那边能批量生成配音、克隆音色、做多语言翻译，真人配音师这边可以在上面直接接单。<br>覆盖广告配音、有声小说、角色音、纪录片旁白等多个领域。</p><p>对想做配音兼职的新人来说，青萍有几个实在的特点。</p><p><strong>免费入驻，不收一分钱。</strong><br>没有入驻费、认证费、年费、押金。<br>不是什么”限时免费”或”前 100 名免费”，是一直免费。</p><p><strong>不卖课，没有培训捆绑。</strong><br>行业里有些平台打着招募旗号卖课，价格从 1999 到 5999 不等。<br>青萍不做这些。<br>入驻就是入驻，不需要花钱参加任何培训。</p><p><strong>审核通过即刻上线接单。</strong><br>不用排队等派单，不用熬等级熬流量。<br>提交资料审核通过后，个人主页就会出现在平台配音师列表里，客户可以直接查看样音、发送合作邀请。</p><p><strong>覆盖品类广。</strong><br>宣传片、有声书、广告配音、短视频口播、游戏角色音、情感电台、童话故事都有需求。</p><h1 id="入驻流程"><a href="#入驻流程" class="headerlink" title="入驻流程"></a>入驻流程</h1><p>打开官网 <strong>audio.lusyoe.com</strong>，注册账号后进入工作台。<br>找到”合作入驻”入口，填写个人资料和样音作品，提交审核就行。<br>审核通过后，你就可以在平台上接单了。</p><p>最后再提醒一句：配音能力是练出来的，不是花钱买来的。<br>任何让你先交钱再接单的渠道，不管话说得多好听，都别信。<br>真正靠谱的平台，不会在你还没赚到一分钱的时候，就先从你口袋里掏钱。</p>]]>
    </content>
    <id>https://blog.lusyoe.com/article/voice-over-part-time-job-channels</id>
    <link href="https://blog.lusyoe.com/article/voice-over-part-time-job-channels"/>
    <published>2026-07-03T08:00:00.000+08:00</published>
    <summary>盘点五种常见的配音兼职渠道，分析各自的优缺点和风险，重点提醒交押金、培训费、认证费三大陷阱，最后介绍一个真正对新人友好的配音接单平台。适合想入行的配音新手阅读。</summary>
    <title>配音兼职渠道怎么找？5 种渠道和 1 个避坑提醒</title>
    <updated>2026-07-03T08:00:00.000+08:00</updated>
  </entry>
  <entry>
    <author>
      <name>青萍叙事</name>
    </author>
    <category term="产品" scheme="https://blog.lusyoe.com/categories/%E4%BA%A7%E5%93%81/"/>
    <category term="青萍AI语音" scheme="https://blog.lusyoe.com/tags/%E9%9D%92%E8%90%8DAI%E8%AF%AD%E9%9F%B3/"/>
    <category term="兼职" scheme="https://blog.lusyoe.com/tags/%E5%85%BC%E8%81%8C/"/>
    <category term="产品推荐" scheme="https://blog.lusyoe.com/tags/%E4%BA%A7%E5%93%81%E6%8E%A8%E8%8D%90/"/>
    <content>
      <![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>带娃的空隙想做点声音兼职，但真开始找渠道的时候，不少人卡住了。</p><p>喜马拉雅？听说要等好久才开通。</p><p>配音群？怕遇到骗子。</p><p>App 上那些接单平台？也不知道哪个靠谱。</p><p>这篇就从宝妈最在意的三个角度来聊：门槛高不高、要不要交钱、接单方不方便。</p><h1 id="喜马拉雅：大平台，但新人难出头"><a href="#喜马拉雅：大平台，但新人难出头" class="headerlink" title="喜马拉雅：大平台，但新人难出头"></a>喜马拉雅：大平台，但新人难出头</h1><p>喜马拉雅是音频行业的老大哥，有声书需求量确实大。</p><p>广告配音、有声小说、情感电台，每天更新的内容几万条，配音机会是有的。</p><p>但问题出在入门这块。</p><p>想做喜马拉雅的认证主播，得先提交资料审核，包括学历证明、普通话等级证书、样音作品，全套走下来快则一两周，慢则一两个月。</p><p>通过了之后平台不会主动给你推单，得自己去接单广场抢任务。</p><p>新人几乎抢不到好单子。</p><p>因为接单广场上挂出来的任务有限，几十上百个主播盯着。</p><p>有声书分成比例大概 30% 到 50%，平台拿走一大部分，到你手上的并不多。</p><p>对宝妈来说，最难受的是时间。</p><p>有声书录制通常有交稿截止日，有时候一天得录两三个小时。</p><p>带娃的空闲时间本就不固定，赶上孩子生病、学校放假，交稿压力特别大。</p><p>不是说喜马拉雅不好，但它更适合有稳定时间、有作品积累的专业主播。</p><h1 id="配音圈兼职App：自由灵活，但得自己谈"><a href="#配音圈兼职App：自由灵活，但得自己谈" class="headerlink" title="配音圈兼职App：自由灵活，但得自己谈"></a>配音圈兼职App：自由灵活，但得自己谈</h1><p>配音圈兼职App 是四川好声库科技做的平台，模式比较轻：直接让客户和配音员一对一聊。</p><p>你想接什么类型的单子自己选，有声书、广告、短视频、游戏配音都有。</p><p>平台上没有中间商抽成，客户找到你之后，价格你们自己谈。</p><p>优点是自由度很高，不限制接单时间，今天有空接一单，明天没空不接也行。</p><p>缺点是平台只管牵线，不管谈价和交付。</p><p>你上传样音，客户听了觉得合适就来私聊。</p><p>聊价格、聊录制要求、聊修改次数，全得自己来。</p><p>有些客户对声音要求很高，一遍遍让你重录，不好意思拒绝，一单改来改去花好几个小时。</p><p>还有就是单子得自己找。</p><p>平台不主动推送订单，得自己多上线看看有没有客户发来消息。</p><p>宝妈白天带娃没空看手机，等晚上打开 App，人家客户已经找别人了。</p><p>这种模式适合沟通能力强、时间相对灵活、愿意主动找活的人。</p><p>如果你带娃已经很累了，不想再费心跟人讨价还价，这个平台用起来会有点累。</p><h1 id="青萍AI语音：免费入驻，海量订单自动推送"><a href="#青萍AI语音：免费入驻，海量订单自动推送" class="headerlink" title="青萍AI语音：免费入驻，海量订单自动推送"></a>青萍AI语音：免费入驻，海量订单自动推送</h1><p>前两个平台各有各的好，但对宝妈来说，总差那么一点。</p><p>一个门槛高、等太久，一个得靠自己找活谈价格。</p><p>有没有那种入驻不用花钱、不需要自己找客户、订单自动送上门的平台？</p><p>青萍AI语音的真人配音板块，就是照着这个思路做的。</p><p><strong>免费入驻，不收一分钱。</strong></p><p>入驻费、押金、培训费，通通没有。</p><p>注册一个账号就能申请成为配音师，不是什么限时免费，是一直免费。</p><p><strong>没有培训捆绑，不卖课。</strong></p><p>很多配音平台说是招募配音师，进去先推几千块的课程。</p><p>青萍AI语音不卖课，不推培训套餐。</p><p>你有配音能力，直接入驻直接接单。</p><p><strong>订单自动推送，不用自己找活。</strong></p><p>这是最吸引宝妈的一点。</p><p>你入驻通过后，平台上每天都有大量配音需求推送过来。</p><p>有声书、广告配音、短视频口播、游戏角色音、情感电台、童话故事……品类覆盖很广。</p><p>你不需要去跟客户谈价格、改稿子，平台有专人对接。</p><p>订单来了你看着接，合适就接，不合适等下一单。</p><p><strong>时间自由，适合碎片化接单。</strong></p><p>带娃的空闲时间不稳定，今天下午孩子睡午觉能录半小时，明天可能一整天没空。</p><p>青萍AI语音的订单模式支持这种碎片化接单，没有强制交稿时间，不用赶工期。</p><p><strong>怎么入驻。</strong></p><p>打开官网 audio.lusyoe.com，注册账号后进入工作台，找到合作入驻入口，填写个人资料和样音作品，提交审核。</p><p>审核通过后你的配音员页面就上线了，每天等着接单就行。</p><h1 id="三个平台怎么选"><a href="#三个平台怎么选" class="headerlink" title="三个平台怎么选"></a>三个平台怎么选</h1><p>如果你有大量作品积累、有稳定的录制时间，喜马拉雅值得一试。</p><p>如果你擅长沟通、不介意自己谈价格找活，配音圈兼职App 是个灵活的选择。</p><p>如果你带娃时间碎片化、不想花钱、不想费心谈客户，只想安安静静录录音赚点零花钱，青萍AI语音是最省心的方案。</p><p>声音条件不错的宝妈，不妨从青萍AI语音开始试试。</p><p>免费入驻，没有损失。</p><p>万一做着喜欢，再拓展到其他平台也不迟。</p><p>前往 <strong>audio.lusyoe.com</strong> 即可体验。</p>]]>
    </content>
    <id>https://blog.lusyoe.com/article/mom-voice-side-gig-platform-comparison</id>
    <link href="https://blog.lusyoe.com/article/mom-voice-side-gig-platform-comparison"/>
    <published>2026-06-29T10:00:00.000+08:00</published>
    <summary>宝妈做声音兼职，时间碎片化、不想交钱、不愿被坑怎么办？本文横评喜马拉雅、配音圈兼职App和青萍AI语音三个平台，帮你们找到最适合带娃空闲的接单渠道。青萍AI语音免费入驻每日自动派单，特别适合宝妈。</summary>
    <title>宝妈声音兼职去哪接单：三个平台横评，最后一个免费入驻每日自动派单</title>
    <updated>2026-06-29T10:00:00.000+08:00</updated>
  </entry>
  <entry>
    <author>
      <name>青萍叙事</name>
    </author>
    <category term="Hermes" scheme="https://blog.lusyoe.com/categories/Hermes/"/>
    <category term="Hermes-Agent" scheme="https://blog.lusyoe.com/tags/Hermes-Agent/"/>
    <category term="浏览器自动化" scheme="https://blog.lusyoe.com/tags/%E6%B5%8F%E8%A7%88%E5%99%A8%E8%87%AA%E5%8A%A8%E5%8C%96/"/>
    <category term="BrowserHarness" scheme="https://blog.lusyoe.com/tags/BrowserHarness/"/>
    <content>
      <![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>今天我们要介绍的是 Hermes Agent 的浏览器工具集。<br>用一句话说就是：让 AI 替你操作网页。</p><p>你给它一个网址，它能输入文字、点击按钮、滚动页面、截图分析，全程不需要你动手。</p><p>这套能力有两层实现方式。<br>第一层是 Hermes 内置的浏览器工具集，十几个工具覆盖了绝大多数网页操作需求。<br>第二层是 Browser Harness，一个第三方开源框架，能让 AI 自己编写操控脚本并优化，适合更复杂的任务。</p><p>如果你刚开始接触这些工具，别担心，我会从概念开始一步步带着你用起来。</p><h1 id="什么是-Hermes-浏览器工具"><a href="#什么是-Hermes-浏览器工具" class="headerlink" title="什么是 Hermes 浏览器工具"></a>什么是 Hermes 浏览器工具</h1><p>Hermes 的浏览器工具有 10 个核心操作：</p><ul><li><code>browser_navigate</code>，打开网页，是所有操作的前提</li><li><code>browser_snapshot</code>，获取当前页面的无障碍树快照，返回可交互元素的 ref ID</li><li><code>browser_click</code>，点击 ref ID 对应的元素</li><li><code>browser_type</code>，往输入框填入文字</li><li><code>browser_scroll</code>，向上或向下滚动页面</li><li><code>browser_press</code>，按键盘键（Enter、Tab、Escape 等）</li><li><code>browser_back</code>，回退到上一页</li><li><code>browser_vision</code>，截图并用 AI 分析画面内容</li><li><code>browser_get_images</code>，列出页面上的所有图片</li><li><code>browser_console</code>，读取浏览器控制台输出</li></ul><p>如果通过 CDP 连接浏览器，还会额外解锁两个工具：<code>browser_cdp</code>（发送原始 CDP 指令）和 <code>browser_dialog</code>（处理 alert&#x2F;confirm 弹窗）。</p><p>每个浏览器后端都支持这些工具，区别只在于浏览器跑在哪里。</p><h1 id="启用浏览器工具集"><a href="#启用浏览器工具集" class="headerlink" title="启用浏览器工具集"></a>启用浏览器工具集</h1><p>浏览器工具默认没开，需要手动加到工具列表里：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hermes config <span class="built_in">set</span> toolsets <span class="string">&#x27;[&quot;hermes-cli&quot;, &quot;browser&quot;]&#x27;</span></span><br></pre></td></tr></table></figure><p>或者通过交互式配置：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hermes setup tools</span><br></pre></td></tr></table></figure><p>在菜单中选择 Browser Automation 并选择你偏好的后端。</p><h1 id="本地浏览器模式（零成本起步）"><a href="#本地浏览器模式（零成本起步）" class="headerlink" title="本地浏览器模式（零成本起步）"></a>本地浏览器模式（零成本起步）</h1><p>如果你刚开始接触，本地模式是最简单的起点。不花钱，不用注册任何云服务。</p><p>Hermes 通过 <code>agent-browser</code> 驱动本地安装的 Chromium。只需要确保系统里有 Chrome 或 Chromium：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 安装 agent-browser CLI</span></span><br><span class="line">npm install -g agent-browser</span><br></pre></td></tr></table></figure><p>启动 Hermes 后，直接发指令：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">帮我打开 https://www.36kr.com，看看今天有哪些热门资讯</span><br></pre></td></tr></table></figure><p>Hermes 会自动启动一个后台 Chromium 进程，打开页面，抓取内容，然后把结果返回给你。</p><p>所有操作都在你的电脑上完成，不经过第三方服务器。</p><h1 id="CDP-模式（亲眼看着-AI-操作）"><a href="#CDP-模式（亲眼看着-AI-操作）" class="headerlink" title="CDP 模式（亲眼看着 AI 操作）"></a>CDP 模式（亲眼看着 AI 操作）</h1><p>本地模式浏览器跑在后台，你看不到操作过程。<br>如果你想亲眼看着 AI 操作，就用 CDP 模式。</p><p>先以远程调试模式启动你的浏览器。</p><p>macOS 上的 Chrome：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&quot;/Applications/Google Chrome.app/Contents/MacOS/Google Chrome&quot;</span> \</span><br><span class="line">  --remote-debugging-port=9222 \</span><br><span class="line">  --user-data-dir=<span class="string">&quot;<span class="variable">$HOME</span>/.hermes/chrome-debug&quot;</span> \</span><br><span class="line">  --no-first-run --no-default-browser-check &amp;</span><br></pre></td></tr></table></figure><p>浏览器启动后，打开控制台，运行 <code>/browser connect</code>：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/browser connect</span><br></pre></td></tr></table></figure><p>连接成功后，AI 操作会直接反映在你眼前的浏览器窗口中。<br>适合调试网页，或者需要借用你已登录的会话的场景。</p><p>完成后用 <code>/browser disconnect</code> 断开连接。</p><h1 id="Browser-Harness-是什么"><a href="#Browser-Harness-是什么" class="headerlink" title="Browser Harness 是什么"></a>Browser Harness 是什么</h1><p>Browser Harness 是 <a href="https://github.com/browser-use/browser-harness">browser-use&#x2F;browser-harness</a> 开源项目，让 AI 直接通过 CDP WebSocket 连上你的浏览器。<br>和内置的 browser_ 工具集相比，Browser Harness 的操控更底层、更灵活——AI 可以自己编写操控脚本并不断优化，这就是所谓的”自愈”能力。</p><p>它需要手动安装并注册为 Hermes 的技能才能使用：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 克隆仓库</span></span><br><span class="line">git <span class="built_in">clone</span> https://github.com/browser-use/browser-harness ~/browser-harness</span><br><span class="line"><span class="built_in">cd</span> ~/browser-harness</span><br><span class="line"></span><br><span class="line"><span class="comment"># 注册为 Hermes 技能（通过符号链接）</span></span><br><span class="line"><span class="built_in">ln</span> -s <span class="string">&quot;<span class="subst">$(pwd)</span>&quot;</span> ~/.hermes/skills/browser-harness</span><br></pre></td></tr></table></figure><p>然后在 Hermes 终端里直接告诉它用 Browser Harness 操作浏览器即可。</p><p>如果想通过 CDP 连接本地浏览器，还需要先以调试模式启动 Chrome：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&quot;/Applications/Google Chrome.app/Contents/MacOS/Google Chrome&quot;</span> \</span><br><span class="line">  --remote-debugging-port=9222 \</span><br><span class="line">  --user-data-dir=<span class="string">&quot;<span class="variable">$HOME</span>/.hermes/chrome-debug&quot;</span> \</span><br><span class="line">  --no-first-run --no-default-browser-check &amp;</span><br></pre></td></tr></table></figure><p>之后 Hermes 就能通过这个 CDP 通道操控 Chrome 页面。</p><h1 id="使用场景"><a href="#使用场景" class="headerlink" title="使用场景"></a>使用场景</h1><p><strong>填表单、下单、预约</strong></p><p>这是最直接的应用。<br>给 AI 一个注册链接，告诉它填入什么信息，它会自己导航到页面、找到输入框、填入内容、点击提交。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">帮我用 email@example.com 在 example.com 注册一个账号，密码用 xxxxxx</span><br></pre></td></tr></table></figure><p><strong>抓取 JavaScript 渲染的数据</strong></p><p>很多现代网站的数据是通过 AJAX 动态加载的。<br>普通的 web_extract 工具只能拿到初始 HTML，但浏览器工具会等 JavaScript 执行完毕后读取渲染后的 DOM。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">打开我的后台面板 http://localhost:3000/dashboard，截图看看今天的指标</span><br></pre></td></tr></table></figure><p><strong>截图做可视化 QA</strong></p><p>部署新版本后，让 AI 打开几个关键页面截图确认，可以替代人工巡检。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">打开网站首页、登录页、个人中心，每页截图让我看看</span><br></pre></td></tr></table></figure><p><strong>多步骤研究</strong></p><p>从一个文档页面出发，顺着链接跟踪到多个子页面，最后汇总信息。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">打开 Hermes 官方文档的浏览器页面，看看支持哪些后端，帮我汇总成表格</span><br></pre></td></tr></table></figure><p><strong>Browser Harness 进阶：重复性操作自动化</strong></p><p>对于需要每天重复的网页操作（登录后台、导数据、填写日报），Browser Harness 的 domain skills 机制能让这些步骤不断自我优化。AI 会记住每个网站的布局特征和操作流程，下一次执行得更快。</p><h1 id="写在最后"><a href="#写在最后" class="headerlink" title="写在最后"></a>写在最后</h1><p>Hermes 的浏览器工具给 AI 装上了一双能”看”能”点”的手。</p><p>本地模式适合初学者零成本体验，CDP 模式让你看着 AI 操作真实浏览器。<br>Browser Harness 则为复杂场景提供了自愈式的操控能力。</p><p>从简单的截图问答到完整的网页自动化流程，这套工具有很大的想象空间。</p>]]>
    </content>
    <id>https://blog.lusyoe.com/article/hermes-browser-harness</id>
    <link href="https://blog.lusyoe.com/article/hermes-browser-harness"/>
    <published>2026-06-23T10:30:00.000+08:00</published>
    <summary>Hermes 的浏览器工具集能让 AI 像人一样操作网页：填入表单、点击按钮、截图分析。本文从零开始介绍内置浏览器工具和 Browser Harness 的安装与使用</summary>
    <title>Hermes 浏览器工具：让 AI 替你操作网页</title>
    <updated>2026-06-23T10:30:00.000+08:00</updated>
  </entry>
  <entry>
    <author>
      <name>青萍叙事</name>
    </author>
    <category term="AI" scheme="https://blog.lusyoe.com/categories/AI/"/>
    <category term="OpenCode" scheme="https://blog.lusyoe.com/tags/OpenCode/"/>
    <category term="Hindsight" scheme="https://blog.lusyoe.com/tags/Hindsight/"/>
    <category term="AiCoding" scheme="https://blog.lusyoe.com/tags/AiCoding/"/>
    <content>
      <![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>用过 AI 编程工具的人大概都有这种体会：明明上一个会话还聊得好好的，换个项目再回来，它又把你当陌生人。</p><p>OpenCode 也不例外，每次新会话都是一片空白。</p><p>Hindsight 就是来解决这个问题的。<br>这是一个开源的长效记忆系统，它为 AI 工具装上”脑子”——之前聊过的项目上下文、代码决策、踩坑经验，之后都能自动回想起来。</p><p>更实用的是，Hindsight 的 OpenCode 插件支持为每个项目创建独立的记忆库，项目 A 的记忆不会污染项目 B。</p><h1 id="插件安装"><a href="#插件安装" class="headerlink" title="插件安装"></a>插件安装</h1><p>Hindsight for OpenCode 以 npm 包形式发布，直接在 <code>opencode.json</code> 中声明即可。</p><p>打开项目根目录的 <code>opencode.json</code>（或全局配置 <code>~/.config/opencode/opencode.json</code>），在 <code>plugin</code> 数组里加上插件配置：</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;$schema&quot;</span><span class="punctuation">:</span> <span class="string">&quot;https://opencode.ai/config.json&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;plugin&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">    <span class="punctuation">[</span><span class="string">&quot;@vectorize-io/opencode-hindsight&quot;</span><span class="punctuation">,</span> <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;hindsightApiUrl&quot;</span><span class="punctuation">:</span> <span class="string">&quot;http://&lt;your-server-ip&gt;:8888&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;autoRecall&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;autoRetain&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;recallBudget&quot;</span><span class="punctuation">:</span> <span class="string">&quot;mid&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;retainEveryNTurns&quot;</span><span class="punctuation">:</span> <span class="number">3</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;debug&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">false</span></span></span><br><span class="line">    <span class="punctuation">&#125;</span><span class="punctuation">]</span></span><br><span class="line">  <span class="punctuation">]</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><p>OpenCode 启动时会自动从 npm 安装插件，不需要手动执行 <code>npm install</code>。<br>插件安装后直接连接到你指定的 Hindsight 服务器地址。</p><p>如果你用的是 Hindsight Cloud 云服务，需要更换 <code>hindsightApiUrl</code> 并加上 API Token：</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">[</span><span class="string">&quot;@vectorize-io/opencode-hindsight&quot;</span><span class="punctuation">,</span> <span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;hindsightApiUrl&quot;</span><span class="punctuation">:</span> <span class="string">&quot;https://api.hindsight.vectorize.io&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;hindsightApiToken&quot;</span><span class="punctuation">:</span> <span class="string">&quot;your-api-key&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;autoRecall&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;autoRetain&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;recallBudget&quot;</span><span class="punctuation">:</span> <span class="string">&quot;mid&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;retainEveryNTurns&quot;</span><span class="punctuation">:</span> <span class="number">3</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;debug&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">false</span></span></span><br><span class="line"><span class="punctuation">&#125;</span><span class="punctuation">]</span></span><br></pre></td></tr></table></figure><p>API Key 在 <a href="https://ui.hindsight.vectorize.io/connect">ui.hindsight.vectorize.io&#x2F;connect</a> 注册获取。</p><h1 id="每个项目独立记忆库"><a href="#每个项目独立记忆库" class="headerlink" title="每个项目独立记忆库"></a>每个项目独立记忆库</h1><p>这是整个插件最实用的特性：动态记忆库 ID。</p><p>默认情况下，所有项目共享同一个记忆库（bankId 固定为 <code>opencode</code>）。<br>这就意味着 A 项目的记忆会在 B 项目的会话中被召回，两个项目的上下文互相干扰。</p><p>开启动态记忆库后就不一样了：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">export</span> HINDSIGHT_DYNAMIC_BANK_ID=<span class="literal">true</span></span><br></pre></td></tr></table></figure><p>Hindsight 会根据当前项目的特征自动推导一个唯一的 bankId，默认的组合规则是 <code>agent::project</code>。<br>A 项目启动的会话自动关联 A 项目的记忆库，B 项目启动的会话自动关联 B 项目的记忆库，互不干扰。</p><p>支持的特征字段包括 <code>agent</code>（角色名）、<code>project</code>（项目目录名）、<code>channel</code>（渠道名）和 <code>user</code>（用户标识）。<br>如果你需要更细的隔离粒度，可以自定义组合，但默认的 <code>agent::project</code> 已经覆盖了最常见的场景。</p><h1 id="插件提供的三个工具"><a href="#插件提供的三个工具" class="headerlink" title="插件提供的三个工具"></a>插件提供的三个工具</h1><p>安装并连接成功后，Hindsight 会注册三个工具给 OpenCode 的 AI Agent：</p><ul><li><code>hindsight_retain</code>，主动存储信息到长期记忆，适合记录重要的架构决策、踩坑经验</li><li><code>hindsight_recall</code>，搜索长期记忆中的相关信息，跨会话检索之前讨论过的内容</li><li><code>hindsight_reflect</code>，综合多条记忆给出一个回答，适合需要总结归纳的场景</li></ul><p>这些工具 AI Agent 可以在会话中直接调用。<br>但多数情况下你不需要手动触发它们，插件有自动机制。</p><h1 id="自动记忆与召回"><a href="#自动记忆与召回" class="headerlink" title="自动记忆与召回"></a>自动记忆与召回</h1><p>Hindsight 的两个自动行为让记忆真正”无感”。</p><p><strong>auto-retain</strong>：当会话进入空闲状态时，插件自动把当前对话内容存入记忆。<br>你可以通过 <code>retainEveryNTurns</code> 控制存储频率。<br>默认每 3 轮交互保存一次。</p><p><strong>auto-recall</strong>：每次新会话启动时，插件自动检索与该项目相关的历史记忆。<br>这些记忆会被注入到系统提示词中。<br>AI Agent 加载后就拥有了之前会话的上下文，不需要你主动”提醒”。</p><p>当 OpenCode 压缩上下文窗口时，插件也会先保存当前会话内容再压缩，确保记忆在上下文截断后不会丢失。</p><h1 id="持久配置"><a href="#持久配置" class="headerlink" title="持久配置"></a>持久配置</h1><p>如果不想在每个项目里重复配，可以创建 <code>~/.hindsight/opencode.json</code> 文件，这里面的配置对所有项目生效：</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;hindsightApiUrl&quot;</span><span class="punctuation">:</span> <span class="string">&quot;http://&lt;your-server-ip&gt;:8888&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;recallBudget&quot;</span><span class="punctuation">:</span> <span class="string">&quot;mid&quot;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><p>配置的优先级从低到高依次是：</p><p>默认值 &lt; <code>~/.hindsight/opencode.json</code> &lt; <code>opencode.json</code> 插件选项</p><p>后面的会覆盖前面的，灵活度很高。</p><h1 id="完整配置参考"><a href="#完整配置参考" class="headerlink" title="完整配置参考"></a>完整配置参考</h1><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;$schema&quot;</span><span class="punctuation">:</span> <span class="string">&quot;https://opencode.ai/config.json&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;plugin&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">    <span class="punctuation">[</span><span class="string">&quot;@vectorize-io/opencode-hindsight&quot;</span><span class="punctuation">,</span> <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;hindsightApiUrl&quot;</span><span class="punctuation">:</span> <span class="string">&quot;https://api.hindsight.vectorize.io&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;hindsightApiToken&quot;</span><span class="punctuation">:</span> <span class="string">&quot;your-api-key&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;bankId&quot;</span><span class="punctuation">:</span> <span class="string">&quot;my-project&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;autoRecall&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;autoRetain&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;recallBudget&quot;</span><span class="punctuation">:</span> <span class="string">&quot;mid&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;recallTags&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;retainTags&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;retainEveryNTurns&quot;</span><span class="punctuation">:</span> <span class="number">3</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;debug&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">false</span></span></span><br><span class="line">    <span class="punctuation">&#125;</span><span class="punctuation">]</span></span><br><span class="line">  <span class="punctuation">]</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><p>几个关键选项说明：</p><ul><li><code>bankId</code>：静态记忆库 ID，不开启动态模式时使用</li><li><code>recallBudget</code>：召回量，可选 <code>low</code> &#x2F; <code>mid</code> &#x2F; <code>high</code>，默认 <code>mid</code></li><li><code>recallTags</code> &#x2F; <code>retainTags</code>：按标签过滤存储或召回</li><li><code>retainEveryNTurns</code>：自动保存频率，每 N 轮交互存一次</li></ul><h1 id="写在最后"><a href="#写在最后" class="headerlink" title="写在最后"></a>写在最后</h1><p>Hindsight 给 OpenCode 补上了最关键的一环：记忆。</p><p>安装只需要在配置里加一行插件声明，连接 Hindsight 服务器后，每个项目就有了自己独立的记忆空间。<br>之前讨论过的架构、发现过的 bug、做过的决策，新会话直接继承，不需要重复交代。</p>]]>
    </content>
    <id>https://blog.lusyoe.com/article/hindsight-opencode-memory-bank</id>
    <link href="https://blog.lusyoe.com/article/hindsight-opencode-memory-bank"/>
    <published>2026-06-23T10:00:00.000+08:00</published>
    <summary>给 OpenCode 装上 Hindsight 插件后，每个项目都拥有独立的记忆库，跨会话自动回忆上下文，无需手动记录</summary>
    <title>Hindsight for OpenCode：给每个项目装上专属记忆库</title>
    <updated>2026-06-23T10:00:00.000+08:00</updated>
  </entry>
  <entry>
    <author>
      <name>青萍叙事</name>
    </author>
    <category term="Hermes" scheme="https://blog.lusyoe.com/categories/Hermes/"/>
    <category term="Hermes-Agent" scheme="https://blog.lusyoe.com/tags/Hermes-Agent/"/>
    <category term="Gateway" scheme="https://blog.lusyoe.com/tags/Gateway/"/>
    <category term="Profile" scheme="https://blog.lusyoe.com/tags/Profile/"/>
    <content>
      <![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>2026 年 6 月 19 日，Hermes Agent 发布了 v0.17.0 版本，代号 The Reach Release（触达版）。<br>这个版本从 v0.16.0 算起积累了约 1,475 次提交、800 个合并 PR 和 300 多个修复的 issue，245 位社区贡献者参与开发。<br>版本名”触达”的含义很直白：扩展 Agent 能到达的地方，包括新的消息渠道、更深的工具集成，以及面向团队部署的能力增强。<br>其中最值得关注的架构改进，是一个 Gateway 进程同时服务多个 Profile 的多路复用功能。</p><h1 id="版本概览"><a href="#版本概览" class="headerlink" title="版本概览"></a>版本概览</h1><p>v0.17.0 的更新覆盖面很广，挑几个主要方向：</p><ul><li><strong>iMessage 支持</strong>，通过 Photon Spectrum 接入，不再需要一台 Mac 做中继</li><li><strong>后台子代理</strong>，delegate_task 支持 background 模式，派发任务后继续做别的事</li><li><strong>图片编辑</strong>，image_generate 工具支持图生图，传入原图加提示词即可修改</li><li><strong>Automation Blueprints</strong>，用问答方式设置定时任务，不用背 cron 语法</li><li><strong>Dashboard Profile Builder</strong>，浏览器里选模型、选技能、挂 MCP，直接构建完整 Profile</li><li><strong>memory 批量操作</strong>，原子化的 add&#x2F;replace&#x2F;remove 批处理，一次调用完成多步编辑</li><li><strong>WhatsApp Business Cloud API</strong>，官方适配器，不用再维护 Baileys 桥接进程</li><li><strong>Telegram 富文本</strong>，Bot API 10.1，回复消息原生渲染格式</li></ul><p>这些功能每一个都值得单独聊，但这篇文章的重点在 Gateway 多路复用。</p><h1 id="单-Gateway-多-Profile"><a href="#单-Gateway-多-Profile" class="headerlink" title="单 Gateway 多 Profile"></a>单 Gateway 多 Profile</h1><h2 id="之前的问题"><a href="#之前的问题" class="headerlink" title="之前的问题"></a>之前的问题</h2><p>Hermes 的 Profile 机制允许在同一台机器上运行多个独立的 Agent 实例。<br>每个 Profile 有自己的 config.yaml、.env、SOUL.md、记忆、会话、技能和定时任务。</p><p>但在 v0.17.0 之前，多 Profile 部署有一个绕不开的代价：每个 Profile 都要启动一个独立的 Gateway 进程。<br>你有 3 个 Profile，就要跑 3 个 Gateway，每个都有自己的 PID、锁文件、端口和系统服务单元。<br>N 个 Profile 就有 N 个 Gateway 要配置、监控和重启。</p><p>用 Docker 部署时，s6-overlay 会自动管理这些进程，但容器内进程数随 Profile 数量线性增长。<br>维护成本不低。</p><h2 id="新的方案"><a href="#新的方案" class="headerlink" title="新的方案"></a>新的方案</h2><p>v0.17.0 引入了 Gateway 多路复用（<a href="https://github.com/NousResearch/hermes-agent/pull/48273">PR #48273</a>），让一个 Gateway 进程同时服务所有 Profile。</p><p>这是一个 opt-in 功能，通过配置项 <code>gateway.multiplex_profiles</code> 开启，默认关闭。<br>关闭时行为与之前完全一致，不会影响任何现有部署。</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">gateway:</span></span><br><span class="line">  <span class="attr">multiplex_profiles:</span> <span class="literal">true</span></span><br></pre></td></tr></table></figure><p>开启后，默认的 Gateway 进程会自动枚举所有 Profile，为每个 Profile 注册独立的适配器实例。<br>自己的 bot token、自己的会话存储、自己的凭证。</p><h2 id="凭证隔离"><a href="#凭证隔离" class="headerlink" title="凭证隔离"></a>凭证隔离</h2><p>多路复用面临的核心技术挑战是凭证隔离。</p><p>如果直接把所有 Profile 的密钥合并到进程级的 os.environ，Profile A 的 API Key 会在 Profile B 的请求中被读到。<br>更危险的是，所有子进程（MCP Server、Kanban Worker）都会继承这份全局环境变量，导致跨 Profile 泄露。</p><p>v0.17.0 的解决方案是 fail-closed 的 <code>get_secret()</code> 机制。<br>多路复用模式下，凭证读取由一个 context-local 的 secret scope 包裹。<br>当读取凭证时没有安装对应的 scope，<code>get_secret()</code> 会直接抛出 <code>UnscopedSecretError</code> 异常。<br>它不会回退到 os.environ。<br>这确保了即使代码中有遗漏的调用点，也会在运行时立即暴露，不会静默泄露。</p><p>真正全局的变量（HERMES_* 系列、PATH、Kanban 路径等）通过一个白名单继续从 os.environ 读取。<br>每轮对话开始时重新加载对应 Profile 的 .env 文件，不再修改全局的 os.environ。</p><h2 id="怎么用"><a href="#怎么用" class="headerlink" title="怎么用"></a>怎么用</h2><p>先升级到 v0.17.0：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hermes update</span><br></pre></td></tr></table></figure><p>然后在默认 Profile 中开启多路复用：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hermes config <span class="built_in">set</span> gateway.multiplex_profiles <span class="literal">true</span></span><br></pre></td></tr></table></figure><p>重启 Gateway 后，它会自动枚举所有 Profile 并为每个创建独立的适配器实例。<br>之后只需要维护一个 Gateway 服务，所有 Profile 的消息渠道都通过它收发。</p><p>每个 Profile 仍然在各自的 .env 中配置 bot token 和允许用户列表。<br>如果两个 Profile 不小心配了相同的 token，系统会直接报错并指出冲突。</p><p>注意一点：多路复用模式开启后，不能用 <code>hermes -p &lt;name&gt; gateway run</code> 单独为某个 Profile 启动 Gateway。<br>系统会检测到多路复用器正在运行并阻止这种操作，避免端口和 token 冲突。</p><h1 id="其他团队部署改进"><a href="#其他团队部署改进" class="headerlink" title="其他团队部署改进"></a>其他团队部署改进</h1><p>除了 Gateway 多路复用，v0.17.0 还有一批面向团队和规模化部署的更新：</p><ul><li><strong>Managed Scope</strong>，管理员可以从 root 权限的 &#x2F;etc&#x2F;hermes 锁定不可变的配置和密钥，普通用户无法修改</li><li><strong>可插拔 CronScheduler</strong>，支持 Chronos 等托管 cron 服务，实现 scale-to-zero 的定时任务调度</li><li><strong>Gateway-Gateway Relay</strong>，多级 Gateway 中继协议，适合跨网络、跨区域的 Agent 部署</li><li><strong>安全加固</strong>，凭证审批默认 fail-closed、MCP stdio 配置安全扫描、REST cron 提示词校验</li></ul><h1 id="升级方式"><a href="#升级方式" class="headerlink" title="升级方式"></a>升级方式</h1><p>一行命令：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hermes update</span><br></pre></td></tr></table></figure><p>升级会自动同步新增的 bundled skills 到所有 Profile，用户自定义的 skills 不会被覆盖。<br>更新完成后用 <code>hermes -V</code> 确认版本号显示 v0.17.0 (2026.6.19) 即可。</p>]]>
    </content>
    <id>https://blog.lusyoe.com/article/hermes-v017-gateway-multiplex</id>
    <link href="https://blog.lusyoe.com/article/hermes-v017-gateway-multiplex"/>
    <published>2026-06-23T09:00:00.000+08:00</published>
    <summary>Hermes Agent v0.17.0 代号 The Reach Release，核心更新是单 Gateway 多路复用功能。一个进程服务所有 Profile，无需为每个 Profile 独立部署 Gateway，大幅降低多 Profile 部署运维成本</summary>
    <title>Hermes v0.17.0 最值得升级的理由：一个进程，管所有 Profile</title>
    <updated>2026-06-23T09:00:00.000+08:00</updated>
  </entry>
  <entry>
    <author>
      <name>青萍叙事</name>
    </author>
    <category term="技术分享" scheme="https://blog.lusyoe.com/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/"/>
    <category term="音频可视化" scheme="https://blog.lusyoe.com/tags/%E9%9F%B3%E9%A2%91%E5%8F%AF%E8%A7%86%E5%8C%96/"/>
    <category term="FFmpeg" scheme="https://blog.lusyoe.com/tags/FFmpeg/"/>
    <category term="WebAudio" scheme="https://blog.lusyoe.com/tags/WebAudio/"/>
    <content>
      <![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>播客、音乐、配音，这些音频内容有个共同的短板：看不见。</p><p>在短视频平台上，纯音频的完播率远低于带视觉元素的内容。<br>一段好听的配音，如果配上跳动的波形或炫酷的频谱，观感完全不同。</p><p>音频可视化就是把声音变成画面。<br>这篇文章介绍三种主流的可视化形式，以及两种能直接上手的实现方案。</p><h1 id="三种可视化形式"><a href="#三种可视化形式" class="headerlink" title="三种可视化形式"></a>三种可视化形式</h1><h2 id="波形图"><a href="#波形图" class="headerlink" title="波形图"></a>波形图</h2><p>最经典的形式，展示音频幅度随时间的变化。<br>横轴是时间，纵轴是音量大小，看起来像一组密集的竖线。</p><p>波形图制作简单，辨识度高，适合有声书、播客、语音备忘录。</p><h2 id="频谱图"><a href="#频谱图" class="headerlink" title="频谱图"></a>频谱图</h2><p>展示音频的频率分布，用颜色表示不同频段的强度。<br>低频在底部呈现暖色（红&#x2F;橙），高频在顶部呈现冷色（蓝&#x2F;紫），形成类似热力图的效果。</p><p>频谱图视觉冲击力强，适合音乐类内容。</p><h2 id="粒子动效"><a href="#粒子动效" class="headerlink" title="粒子动效"></a>粒子动效</h2><p>波形和频谱的组合升级版。<br>音频数据驱动粒子系统的运动，音量大时粒子炸开，音量小时收拢，节奏感极强。</p><p>这种效果在 EDM（电子舞曲）视频和游戏混剪中最常见，但实现成本也最高。</p><h1 id="方案一：FFmpeg-命令行"><a href="#方案一：FFmpeg-命令行" class="headerlink" title="方案一：FFmpeg 命令行"></a>方案一：FFmpeg 命令行</h1><p>FFmpeg 内置了一组音频可视化滤镜，不需要写代码，一行命令就能生成视频。</p><h2 id="生成波形视频"><a href="#生成波形视频" class="headerlink" title="生成波形视频"></a>生成波形视频</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">ffmpeg -i input.mp3 -filter_complex \</span><br><span class="line">  <span class="string">&quot;[0:a]showwaves=s=1280x720:colors=white,format=yuv420p[v]&quot;</span> \</span><br><span class="line">  -map <span class="string">&quot;[v]&quot;</span> -map 0:a -c:a aac output.mp4</span><br></pre></td></tr></table></figure><p><code>showwaves</code> 滤镜把音频波形渲染到画面上。<br><code>s=1280x720</code> 设置输出分辨率，<code>colors=white</code> 设置波形颜色。</p><h2 id="生成频谱视频"><a href="#生成频谱视频" class="headerlink" title="生成频谱视频"></a>生成频谱视频</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">ffmpeg -i input.mp3 -filter_complex \</span><br><span class="line">  <span class="string">&quot;[0:a]showspectrum=s=1280x720:mode=combined,format=yuv420p[v]&quot;</span> \</span><br><span class="line">  -map <span class="string">&quot;[v]&quot;</span> -map 0:a -c:a aac output.mp4</span><br></pre></td></tr></table></figure><p><code>showspectrum</code> 滤镜生成频谱热力图。<br><code>mode=combined</code> 将所有声道合并显示，适合音乐。</p><p>FFmpeg 方案的优势是快，缺点是画面风格固定，自定义空间有限。</p><h1 id="方案二：Web-Audio-API"><a href="#方案二：Web-Audio-API" class="headerlink" title="方案二：Web Audio API"></a>方案二：Web Audio API</h1><p>需要在网页端实时渲染音频可视化，Web Audio API 是首选方案。</p><p>核心流程分三步：解码音频 → 提取频域数据 → 绘制到 Canvas。</p><div class="mermaid-wrap"><pre class="mermaid-src" hidden>  flowchart LR    A[音频文件] --&gt; B[AudioContext 解码]    B --&gt; C[AnalyserNode 分析]    C --&gt; D[getByteFrequencyData]    D --&gt; E[Canvas 绘制]    E --&gt;|requestAnimationFrame| C  </pre></div><h2 id="关键代码"><a href="#关键代码" class="headerlink" title="关键代码"></a>关键代码</h2><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 创建音频上下文和分析节点</span></span><br><span class="line"><span class="keyword">const</span> audioCtx = <span class="keyword">new</span> <span class="title class_">AudioContext</span>();</span><br><span class="line"><span class="keyword">const</span> analyser = audioCtx.<span class="title function_">createAnalyser</span>();</span><br><span class="line">analyser.<span class="property">fftSize</span> = <span class="number">256</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 连接音频源到分析节点</span></span><br><span class="line"><span class="keyword">const</span> audioElement = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&#x27;audio&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> source = audioCtx.<span class="title function_">createMediaElementSource</span>(audioElement);</span><br><span class="line">source.<span class="title function_">connect</span>(analyser);</span><br><span class="line">analyser.<span class="title function_">connect</span>(audioCtx.<span class="property">destination</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 获取频率数据并绘制</span></span><br><span class="line"><span class="keyword">const</span> bufferLength = analyser.<span class="property">frequencyBinCount</span>;</span><br><span class="line"><span class="keyword">const</span> dataArray = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>(bufferLength);</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">draw</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="title function_">requestAnimationFrame</span>(draw);</span><br><span class="line">  analyser.<span class="title function_">getByteFrequencyData</span>(dataArray);</span><br><span class="line">  <span class="comment">// 用 dataArray 的值在 Canvas 上画柱状图</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>fftSize</code> 决定频率分辨率，值越大细节越丰富但计算量也越大。<br><code>getByteFrequencyData</code> 返回 0-255 的整数值数组，每个元素对应一个频段的能量。</p><p>Web Audio API 方案的优势是灵活，可以自由设计视觉效果。<br>缺点是需要前端开发能力，且浏览器兼容性需要处理。</p><h1 id="两种方案怎么选"><a href="#两种方案怎么选" class="headerlink" title="两种方案怎么选"></a>两种方案怎么选</h1><p>选 FFmpeg 的场景：批量处理、后台生成、不需要实时预览。<br>选 Web Audio API 的场景：在线播放器、交互式可视化、需要自定义动画风格。</p><p>如果两种都不想碰，还有一个零门槛的选择。</p><h1 id="零门槛方案：青萍-AI-语音的音频生视频"><a href="#零门槛方案：青萍-AI-语音的音频生视频" class="headerlink" title="零门槛方案：青萍 AI 语音的音频生视频"></a>零门槛方案：青萍 AI 语音的音频生视频</h1><p>上面两种方案，FFmpeg 需要命令行基础，Web Audio API 需要前端开发能力。<br>对大多数创作者来说，门槛还是高了。</p><p>青萍 AI 语音（audio.lusyoe.com）提供了<strong>音频生视频</strong>功能。<br>上传一段音频，系统自动生成带波形和频谱动效的视频，不需要任何技术操作。</p><p>效果上，它会根据音频的节奏和音量动态生成可视化画面。<br>适合做短视频配音、播客片段分享、音乐可视化等场景。</p><p>配合平台已有的语音合成和音色克隆功能，整个流程可以这样串起来：<br>用 AI 语音生成配音，一键转成可视化视频，直接发到短视频平台。</p><p>从文字到声音到画面，一个平台搞定。</p>]]>
    </content>
    <id>https://blog.lusyoe.com/article/audio-visualization-guide</id>
    <link href="https://blog.lusyoe.com/article/audio-visualization-guide"/>
    <published>2026-06-21T19:00:00.000+08:00</published>
    <summary>音频可视化把看不见的声音变成可视的波形和频谱动效。本文介绍波形图、频谱图、粒子动效三种形式，覆盖 FFmpeg 命令行和 Web Audio API 两种实现方案，文末推荐青萍 AI 语音的音频生视频功能。</summary>
    <title>音频可视化：从波形到视频的三种实现路径</title>
    <updated>2026-06-21T19:00:00.000+08:00</updated>
  </entry>
  <entry>
    <author>
      <name>青萍叙事</name>
    </author>
    <category term="Hermes" scheme="https://blog.lusyoe.com/categories/Hermes/"/>
    <category term="Hermes-Agent" scheme="https://blog.lusyoe.com/tags/Hermes-Agent/"/>
    <category term="自动化" scheme="https://blog.lusyoe.com/tags/%E8%87%AA%E5%8A%A8%E5%8C%96/"/>
    <category term="定时任务" scheme="https://blog.lusyoe.com/tags/%E5%AE%9A%E6%97%B6%E4%BB%BB%E5%8A%A1/"/>
    <content>
      <![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>大部分 AI 助手有个共同的局限：你问一句，它答一句。<br>你不说话，它就安安静静待着。</p><p>但日常工作和生活里，很多事情是周期性的。<br>每天早上想看一眼科技新闻摘要，每周想检查一次关注的仓库有没有新动态，某个网页更新了想第一时间知道。</p><p>这些事情反复做，每次手动问 AI 太累了。<br>Hermes Agent 的 Cron 定时任务功能就是来解决这个问题的。</p><p>你可以让 AI 在指定时间自动干活，结果直接推送到飞书、微信等消息平台。<br>相当于给 AI 管家装了一个闹钟，到点就上班。</p><h1 id="Cron-是什么"><a href="#Cron-是什么" class="headerlink" title="Cron 是什么"></a>Cron 是什么</h1><p>Hermes 的 Cron 是内置在 Gateway 网关里的定时调度器。</p><p>Gateway 每 60 秒检查一次任务列表，发现到期任务就启动一个全新的 Agent 会话来执行。<br>执行完成后，结果自动推送到你指定的消息渠道。</p><p>跟传统 crontab 相比，最大的区别是 Hermes 的 Cron 任务由 AI 来执行，不是跑固定的 shell 命令。<br>你给它一段自然语言指令，它自己理解、拆解、调用工具、输出结果。</p><div class="mermaid-wrap"><pre class="mermaid-src" hidden>  flowchart LR    A[Gateway 调度器] --&gt;|每60秒检查| B[任务列表]    B --&gt;|发现到期任务| C[启动独立 Agent 会话]    C --&gt; D[执行 Prompt]    D --&gt; E[结果自动推送]    E --&gt; F[飞书 &#x2F; 微信 &#x2F; 钉钉]  </pre></div><h1 id="创建任务的三种方式"><a href="#创建任务的三种方式" class="headerlink" title="创建任务的三种方式"></a>创建任务的三种方式</h1><p>最方便的是直接在对话里说自然语言。<br>比如直接对 Hermes 说，每天早上 9 点搜一下今天的 AI 新闻，整理成简报发到飞书。<br>Hermes 会自动创建任务，你不需要记任何命令。</p><p>需要精确控制参数时，可以用斜杠命令。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/cron add <span class="string">&quot;0 9 * * *&quot;</span> <span class="string">&quot;搜索今天的 AI 领域新闻，整理成 5 条摘要，每条配链接&quot;</span> --name <span class="string">&quot;每日AI简报&quot;</span> --deliver feishu</span><br></pre></td></tr></table></figure><p>终端操作的话，CLI 命令也可以。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hermes cron create <span class="string">&quot;0 9 * * *&quot;</span> <span class="string">&quot;搜索今天的 AI 领域新闻，整理成 5 条摘要&quot;</span> --name <span class="string">&quot;每日AI简报&quot;</span> --deliver feishu</span><br></pre></td></tr></table></figure><p>三种方式效果一样，选你顺手的就行。</p><h1 id="调度格式速查"><a href="#调度格式速查" class="headerlink" title="调度格式速查"></a>调度格式速查</h1><table><thead><tr><th>格式</th><th>示例</th><th>含义</th></tr></thead><tbody><tr><td>相对延迟</td><td><code>30m</code></td><td>30 分钟后执行一次</td></tr><tr><td>间隔循环</td><td><code>every 2h</code></td><td>每 2 小时执行一次</td></tr><tr><td>Cron 表达式</td><td><code>0 9 * * 1-5</code></td><td>工作日每天 9 点</td></tr><tr><td>ISO 时间戳</td><td><code>2026-06-21T09:00:00</code></td><td>指定时刻执行一次</td></tr></tbody></table><p>常用的就是 Cron 表达式和间隔循环。<br><code>0 9 * * *</code> 是每天早上 9 点。<br><code>0 9 * * 1-5</code> 是工作日早上 9 点。<br><code>0 */6 * * *</code> 是每 6 小时一次。</p><h1 id="每日新闻简报自动推送"><a href="#每日新闻简报自动推送" class="headerlink" title="每日新闻简报自动推送"></a>每日新闻简报自动推送</h1><p>这是最经典的应用。</p><p>创建一个每天早上 9 点运行的任务，自动搜索 AI 领域新闻，整理成简报推送到飞书。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/cron add <span class="string">&quot;0 9 * * *&quot;</span> <span class="string">&quot;搜索过去 24 小时的 AI 领域重要新闻，选出最有价值的 5 条。每条包含标题、一句话摘要和原文链接。格式简洁，适合手机上快速浏览。&quot;</span> --name <span class="string">&quot;每日AI简报&quot;</span> --deliver feishu</span><br></pre></td></tr></table></figure><p>每天到点，飞书就会收到一条整理好的新闻摘要。<br>早上喝咖啡的时间就把行业动态刷完了。</p><h1 id="网站变更监控"><a href="#网站变更监控" class="headerlink" title="网站变更监控"></a>网站变更监控</h1><p>想盯一个网页看它什么时候更新，手动刷新太蠢了。<br>这个场景有个关键技巧：<code>[SILENT]</code> 标记。</p><p>配一个脚本先检查网页内容有没有变化。<br>如果没变化，让 Agent 回复 <code>[SILENT]</code>，Cron 就不会推送任何消息。<br>如果有变化，Agent 正常输出摘要，你才会收到通知。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/cron add <span class="string">&quot;every 1h&quot;</span> <span class="string">&quot;如果脚本输出显示 CHANGE DETECTED，分析网页发生了什么变化并简要说明。如果输出是 NO_CHANGE，只回复 [SILENT]。&quot;</span> --script ~/.hermes/scripts/watch-site.py --name <span class="string">&quot;网页监控&quot;</span> --deliver feishu</span><br></pre></td></tr></table></figure><p>只有网页真的变了，你才会被通知。<br>这就是 <code>[SILENT]</code> 的价值：让监控类任务在没事的时候保持安静。</p><h1 id="GitHub-仓库动态"><a href="#GitHub-仓库动态" class="headerlink" title="GitHub 仓库动态"></a>GitHub 仓库动态</h1><p>关注一个开源项目，想第一时间知道有没有新 issue 或 PR。<br>这个场景不需要写脚本，Hermes 内置的终端工具可以直接跑 <code>gh</code> 命令。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/cron add <span class="string">&quot;every 6h&quot;</span> <span class="string">&quot;检查 NousResearch/hermes-agent 仓库过去 6 小时的新动态。用 gh issue list 和 gh pr list 命令查询，筛选出最近 6 小时内的更新。如果没有新动态，回复 [SILENT]。否则简要列出新增的 issue 和 PR。&quot;</span> --name <span class="string">&quot;仓库监控&quot;</span> --deliver feishu</span><br></pre></td></tr></table></figure><p>每 6 小时自动检查一次，有动静才通知你。</p><h1 id="任务全生命周期"><a href="#任务全生命周期" class="headerlink" title="任务全生命周期"></a>任务全生命周期</h1><p>创建之后，任务不是一成不变的。<br>Hermes 提供了完整的管理命令。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">/cron list                    <span class="comment"># 查看所有任务</span></span><br><span class="line">/cron run &lt;任务名&gt;             <span class="comment"># 立即触发一次（测试用）</span></span><br><span class="line">/cron pause &lt;任务名&gt;           <span class="comment"># 暂停，不删除</span></span><br><span class="line">/cron resume &lt;任务名&gt;          <span class="comment"># 恢复执行</span></span><br><span class="line">/cron edit &lt;任务名&gt; --schedule <span class="string">&quot;every 4h&quot;</span>  <span class="comment"># 改调度频率</span></span><br><span class="line">/cron remove &lt;任务名&gt;          <span class="comment"># 彻底删除</span></span><br></pre></td></tr></table></figure><p>任务名不区分大小写，用名称代替 ID 就行。<br>改调度频率或提示词不需要删了重建，直接 edit。</p><h1 id="两个关键注意点"><a href="#两个关键注意点" class="headerlink" title="两个关键注意点"></a>两个关键注意点</h1><p><strong>提示词必须自包含。</strong></p><p>Cron 任务运行在全新的会话里，没有你之前聊天的上下文。<br>如果你只写 <strong>检查一下那个服务器</strong>，Agent 根本不知道是哪台服务器。<br>IP 地址、用户名、具体命令都要写在 prompt 里。</p><p><strong>Gateway 必须在运行。</strong></p><p>Cron 调度器是 Gateway 网关的一部分。<br>Gateway 没跑，定时任务就不会触发。<br>用 macOS 的话，推荐用 launchd 托管 Gateway，设置 <code>RunAtLoad=true</code> 和 <code>KeepAlive.SuccessfulExit=false</code>，开机自动启动，意外退出自动重启。</p>]]>
    </content>
    <id>https://blog.lusyoe.com/article/hermes-cron-scheduled-tasks</id>
    <link href="https://blog.lusyoe.com/article/hermes-cron-scheduled-tasks"/>
    <published>2026-06-21T18:00:00.000+08:00</published>
    <summary>Hermes Agent 内置 Cron 定时调度器，支持用自然语言创建定时任务，结果自动推送到飞书等消息平台。本文通过每日新闻简报、网站变更监控、GitHub 仓库动态三个实战场景，介绍从创建到管理的完整流程。</summary>
    <title>Hermes 定时任务实战</title>
    <updated>2026-06-21T18:00:00.000+08:00</updated>
  </entry>
  <entry>
    <author>
      <name>青萍叙事</name>
    </author>
    <category term="产品" scheme="https://blog.lusyoe.com/categories/%E4%BA%A7%E5%93%81/"/>
    <category term="青萍AI语音" scheme="https://blog.lusyoe.com/tags/%E9%9D%92%E8%90%8DAI%E8%AF%AD%E9%9F%B3/"/>
    <category term="兼职" scheme="https://blog.lusyoe.com/tags/%E5%85%BC%E8%81%8C/"/>
    <category term="真人配音" scheme="https://blog.lusyoe.com/tags/%E7%9C%9F%E4%BA%BA%E9%85%8D%E9%9F%B3/"/>
    <content>
      <![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>声音好听的你，有没有想过用这个优势赚点外快？</p><p>真人配音兼职这几年越来越火。<br>有声书、短视频、广告宣传片、游戏角色配音，需求量大，价格也不低。</p><p>但很多想入行的人卡在第一步：去哪里接单？</p><p>这篇聊聊几个常见的配音接单渠道，再推荐一个免费入驻的平台。</p><h1 id="喜马拉雅：门槛高，但单量稳定"><a href="#喜马拉雅：门槛高，但单量稳定" class="headerlink" title="喜马拉雅：门槛高，但单量稳定"></a>喜马拉雅：门槛高，但单量稳定</h1><p>喜马拉雅是最大的有声书平台之一，对配音师的需求量确实大。</p><p>有声书分成、平台任务、接单广场，几个渠道加起来，月入过万的主播不在少数。</p><p>但问题也很明显。<br>想做喜马拉雅的认证主播，需要提交学历证明、普通话等级证书、作品样音，审核周期长。<br>通过之后，新人几乎拿不到流量推荐，得从最基础的低价单开始熬。</p><p>平台抽成也不低。<br>大部分有声书任务的分成比例在 30% 到 50% 之间，配音师拿到手的比想象中少。</p><p>适合已经有大量作品积累、不愁没单的专业配音员。<br>新人想靠它起步，压力和投入都不小。</p><h1 id="配音工作室和社团：中间商赚差价"><a href="#配音工作室和社团：中间商赚差价" class="headerlink" title="配音工作室和社团：中间商赚差价"></a>配音工作室和社团：中间商赚差价</h1><p>市面上的配音工作室和配音社团也不少。<br>它们从需求方接单，再分发给旗下的配音师，赚中间的差价。</p><p>优点是工作室会帮你对接客户、安排档期，你只需要专注录音就行。</p><p>缺点是抽成比例不透明。<br>有些工作室抽 30% 算良心价，抽 50% 以上的也不少见。<br>配音师辛辛苦苦录完，稿费到手只剩一半。</p><p>还有些工作室设置了阶梯派单制度：想接高价单，先接几单低价单攒星级。<br>新人几个月下来都在白忙。</p><h1 id="社交群组招募：门槛低但风险高"><a href="#社交群组招募：门槛低但风险高" class="headerlink" title="社交群组招募：门槛低但风险高"></a>社交群组招募：门槛低但风险高</h1><p>QQ 群、微信群、豆瓣小组，到处都有”长期招募配音兼职”的广告。</p><p>这种渠道的好处是几乎没有门槛。<br>发一段试音，对方觉得可以，直接派单。</p><p>但风险也是最高的。</p><p>最常见的套路是”交押金才能接单””交培训费才能提升等级””交认证费才能解锁高价单”。<br>钱交完，群要么解散，要么长期没单派。</p><p>还有一些是做”卖课”生意的。<br>打着招募旗号吸引人进群，然后推配音课程，价格从 199 到 5999 不等。<br>课卖了，单不一定有。</p><p>不是所有群都是骗子，但对新人来说，要分辨哪些靠谱、哪些是坑，难度很大。</p><h1 id="青萍AI语音：免费入驻，在线接单"><a href="#青萍AI语音：免费入驻，在线接单" class="headerlink" title="青萍AI语音：免费入驻，在线接单"></a>青萍AI语音：免费入驻，在线接单</h1><p>这些痛点，市面上有没有平台真的在认真解决？</p><p><strong>青萍AI语音</strong>的真人配音板块就是针对这些问题设计的。</p><h2 id="免费入驻，不收-1-分钱"><a href="#免费入驻，不收-1-分钱" class="headerlink" title="免费入驻，不收 1 分钱"></a>免费入驻，不收 1 分钱</h2><p>入驻青萍AI语音不需要交任何费用。<br>入驻费、认证费、年费、押金，通通没有。<br>注册一个账号就能申请成为配音师。</p><p>不是什么”限时免费”或”前 100 名免费”，是一直免费。</p><h2 id="没有培训捆绑"><a href="#没有培训捆绑" class="headerlink" title="没有培训捆绑"></a>没有培训捆绑</h2><p>我们不卖配音课程，不推培训套餐。<br>不需要在入驻前花一分钱参加任何培训。<br>有配音能力，直接入驻接单。</p><h2 id="审核通过即刻上线"><a href="#审核通过即刻上线" class="headerlink" title="审核通过即刻上线"></a>审核通过即刻上线</h2><p>提交资料审核通过后，你的配音员主页立即上线。<br>客户能在平台上搜索到你，在线试听你的样音作品，直接下单。</p><p>不用排队等单，不用熬等级熬流量。</p><h2 id="怎么入驻"><a href="#怎么入驻" class="headerlink" title="怎么入驻"></a>怎么入驻</h2><p>打开官网 audio.lusyoe.com，注册账号后进入工作台，找到合作入驻入口，填写个人资料和样音作品，提交审核。</p><p>审核通过后，你的页面就会出现在配音员列表中。<br>客户可以直接下单、发起试音。</p><p>平台提供一对一专属对接服务。<br>从沟通需求到交付成品有专人跟进，不用自己跟客户扯价格和修改。</p><p>覆盖宣传片、有声书、广告配音、短视频口播、游戏角色音、情感电台、童话故事等多个品类。</p><p>如果你声音条件不错，想找一条靠谱的配音兼职路，不妨从这里开始。</p><p>前往 <strong>audio.lusyoe.com</strong> 体验。</p>]]>
    </content>
    <id>https://blog.lusyoe.com/article/real-voice-actor-side-gig-guide</id>
    <link href="https://blog.lusyoe.com/article/real-voice-actor-side-gig-guide"/>
    <published>2026-06-18T14:00:00.000+08:00</published>
    <summary>真人配音兼职去哪里接单？本文对比喜马拉雅、配音工作室、社群招募等常见渠道的优缺点，文末推荐青萍AI语音平台：免费入驻、不收1分钱、没有培训捆绑，入驻即可在线接单。</summary>
    <title>真人配音兼职怎么找：几个渠道对比，末尾推荐一个免费入驻的</title>
    <updated>2026-06-18T14:00:00.000+08:00</updated>
  </entry>
  <entry>
    <author>
      <name>青萍叙事</name>
    </author>
    <category term="AI" scheme="https://blog.lusyoe.com/categories/AI/"/>
    <category term="青萍AI语音" scheme="https://blog.lusyoe.com/tags/%E9%9D%92%E8%90%8DAI%E8%AF%AD%E9%9F%B3/"/>
    <category term="语音合成" scheme="https://blog.lusyoe.com/tags/%E8%AF%AD%E9%9F%B3%E5%90%88%E6%88%90/"/>
    <category term="语音识别" scheme="https://blog.lusyoe.com/tags/%E8%AF%AD%E9%9F%B3%E8%AF%86%E5%88%AB/"/>
    <content>
      <![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>这两年 AI 语音技术进步很快。<br>但大多数人提到它，想到的还是 Siri 或者剪映里的文本朗读。<br>其实 AI 语音已经分成两个明确的方向：语音合成（让文字开口说话）和语音识别（把声音变成文字）。<br>两个方向解决的是不同的问题，但对创作者来说，最好两个都有。</p><h1 id="语音合成：让文字开口说话"><a href="#语音合成：让文字开口说话" class="headerlink" title="语音合成：让文字开口说话"></a>语音合成：让文字开口说话</h1><p>语音合成就是文字转语音，简称 TTS。<br>你给一段文字，它读出来。<br>十年前那个水平的 TTS 机械感很重，现在完全不一样了。</p><h2 id="声音克隆"><a href="#声音克隆" class="headerlink" title="声音克隆"></a>声音克隆</h2><p>现在的 TTS 已经能做声音克隆。<br>上传一段录音，AI 就能学会你的声音，然后用你的音色去读任何文字。<br>做有声书的时候，你可以给每个角色克隆一个专属音色，切换着用。</p><h2 id="声音设计"><a href="#声音设计" class="headerlink" title="声音设计"></a>声音设计</h2><p>现在的 TTS 不只是克隆已有声音。<br>你可以用文字描述来创造一个不存在的声音，比如写一句 “一个低沉的男中音，带点沙哑感”，模型就能直接生成对应的音色。<br>不需要录音，不需要素材，适合虚拟角色和个性化场景。</p><h2 id="多语言合成"><a href="#多语言合成" class="headerlink" title="多语言合成"></a>多语言合成</h2><p>TTS 现在已经能讲几十种语言。<br>用中文写稿，系统自动翻译成英文、日语、法语再合成，一个声音说多国语言。<br>对做跨境电商、出海内容的团队来说很实用。</p><h1 id="语音识别：让声音变成文字"><a href="#语音识别：让声音变成文字" class="headerlink" title="语音识别：让声音变成文字"></a>语音识别：让声音变成文字</h1><p>语音识别就是自动语音识别，简称 ASR。<br>它和合成互为逆过程：合成是文字变成声音，识别是声音变成文字。</p><h2 id="谁在用"><a href="#谁在用" class="headerlink" title="谁在用"></a>谁在用</h2><p>开会录音转纪要、播客出字幕、访谈快速出稿、课堂录音变笔记、微信语音转文字。<br>这些场景都用得上语音识别。</p><h2 id="工具在变强"><a href="#工具在变强" class="headerlink" title="工具在变强"></a>工具在变强</h2><p>以前的语音识别只能输出一段没标点的文字，谁说了什么都分不清。<br>现在的 ASR 可以自动加标点、区分不同说话人、给每句话打时间戳直接生成字幕文件。<br>对于 <strong>中文专业术语识别不准</strong> 的问题，还能设置热词，告诉系统哪些词比较重要。</p><h2 id="门槛在降低"><a href="#门槛在降低" class="headerlink" title="门槛在降低"></a>门槛在降低</h2><p>以前要用语音识别，得自己部署模型、调参数。<br>现在上传文件等几秒钟就能拿到结果。</p><h1 id="从单点到平台：青萍AI语音"><a href="#从单点到平台：青萍AI语音" class="headerlink" title="从单点到平台：青萍AI语音"></a>从单点到平台：青萍AI语音</h1><p>说了这么多，自己搭一套语音合成加语音识别并不轻松。<br>一个平台把这两件事都做了，才是省心的方案。</p><p><strong>青萍AI语音</strong>就是这样的平台。<br>它同时覆盖了语音合成和语音识别两个方向。</p><p><strong>合成这边：</strong><br>音色克隆上传录音就行，11 种语言支持自动翻译再合成。<br>配音工作台左侧写稿、右侧调参数、底部播预览，多人对话模式几分钟就能产出播客。<br>多音字手动校对功能也是标配，生成前把所有多音字标出来，点一下就能改。</p><p><strong>识别这边：</strong><br>上传音频或视频文件，自动提取对话内容，输出可编辑的文字。<br>支持多人对话识别，自动标注谁说了什么、什么时候说的。<br>结果可以带时间戳导出 SRT 字幕，导入剪映直接能用。<br>支持 MP3、WAV、MP4、MOV 等常见格式，视频文件上传后自动提取音轨，不用手动转格式。</p><p><strong>还有真人兜底。</strong><br>AI 不是万能的，遇到高端宣传片、品牌广告这类场景，平台上有上百位配音老师可以约。<br>AI 做初稿、真人做精修，两种模式灵活切。</p><p>无论你是工作室做短视频、团队管内容、自己折腾 AI 项目，一个平台搞定语音的进和出，省下来的时间是实打实的。</p><p>前往 <strong>audio.lusyoe.com</strong> 即可体验。</p>]]>
    </content>
    <id>https://blog.lusyoe.com/article/ai-voice-tech-beginners-guide</id>
    <link href="https://blog.lusyoe.com/article/ai-voice-tech-beginners-guide"/>
    <published>2026-06-15T10:00:00.000+08:00</published>
    <summary>语音合成和语音识别是AI语音的两大核心方向。这篇文章用大白话讲清楚它们分别能做什么、怎么用，最后推荐一个把两者都做到一起的工具：青萍AI语音。</summary>
    <title>AI语音技术到底能做什么</title>
    <updated>2026-06-15T10:00:00.000+08:00</updated>
  </entry>
  <entry>
    <author>
      <name>青萍叙事</name>
    </author>
    <category term="青萍创作者平台" scheme="https://blog.lusyoe.com/categories/%E9%9D%92%E8%90%8D%E5%88%9B%E4%BD%9C%E8%80%85%E5%B9%B3%E5%8F%B0/"/>
    <category term="AI配音" scheme="https://blog.lusyoe.com/tags/AI%E9%85%8D%E9%9F%B3/"/>
    <category term="青萍AI语音" scheme="https://blog.lusyoe.com/tags/%E9%9D%92%E8%90%8DAI%E8%AF%AD%E9%9F%B3/"/>
    <category term="漫剧" scheme="https://blog.lusyoe.com/tags/%E6%BC%AB%E5%89%A7/"/>
    <content>
      <![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>做漫剧的朋友大概都经历过这种崩溃：画面调好了，节奏卡准了，就差配音。<br>找配音员试音，声音合适的排期排到两周后，有档期的声音又不搭。<br>自己录吧，没隔音环境，出来的效果跟语音备忘录差不多。<br>用AI合成，角色说话跟念课文似的，没有情绪起伏，观众听两句就划走了。</p><p>漫剧配音的痛点集中在三件事。<br>角色多，一部漫剧动辄十几个角色，每个都要不同的声线和语调。<br>找齐合适的配音员就是个大工程。<br>改动频繁，台词改了就得重新录，配音员的时间你控制不了。<br>一个字改了可能要等两天。<br>情绪表达，AI合成的语音太平，遇到哭戏、吵架、低声下气这些场景完全撑不住。</p><h1 id="青萍AI语音，一站搞定漫剧配音"><a href="#青萍AI语音，一站搞定漫剧配音" class="headerlink" title="青萍AI语音，一站搞定漫剧配音"></a>青萍AI语音，一站搞定漫剧配音</h1><p>青萍AI语音是一个AI和真人双引擎的语音创作平台，官网地址 audio.lusyoe.com。<br>不管是AI批量生成配音，还是找专业真人配音员精修，都在一个平台上完成。</p><p><img src="https://img-cdn.lusyoe.cn/images/lusyoe/2026/06/10/5yu5ysea3g.webp" alt="青萍AI语音首页"></p><p><strong>克隆音色。</strong><br>上传 3 到 10 秒的声音样本，AI就能精准复刻这个人的声音特征。<br>音色、语调和情感风格都能保留。<br>你可以为漫剧里的每个角色建立专属音色，主角、配角、反派各一个声线，互不干扰。<br>克隆一个音色只需要 5 秒左右，一部漫剧的角色音色库，半小时就能搭好。</p><p><img src="https://img-cdn.lusyoe.com/images/lusyoe/2026/04/29/n7oge6s22d.webp" alt="音色克隆功能界面"></p><p><strong>设计音色。</strong><br>不想用真人声音，也可以从零设计一个虚拟音色。<br>通过参数调节音高、音色、语速，打造出你需要的声音类型。<br>萝莉音、大叔音、反派低沉嗓音，参数调一调就能生成，不用四处找声源。</p><p><strong>配音生成。</strong><br>把台词输入进去，选好角色音色，点击生成就行。<br>支持批量生成，一集漫剧十几段台词，几分钟就能全部搞定。</p><p><img src="https://img-cdn.lusyoe.cn/images/lusyoe/2026/06/10/w7b92jyz7k.webp" alt="配音生成页面"></p><p>平台内置多音字检测功能，生成前手动确认读音。<br>比如避免把”音乐”的”乐”读成”快乐”的”乐”。</p><p><strong>情绪参数。</strong><br>漫剧配音最怕的就是”一个情绪演到底”。<br>青萍AI语音支持为每段台词单独设定情绪参数，愤怒、悲伤、平静、兴奋都能调。<br>同一段台词切换不同情绪，出来的效果完全不一样。<br>吵架场景拉满愤怒值，独白选悲伤模式，情绪到位了观众才会真正代入。</p><h1 id="真人配音服务"><a href="#真人配音服务" class="headerlink" title="真人配音服务"></a>真人配音服务</h1><p>有些场景AI确实拿不准，比如高张力的哭戏、方言演绎、或者品牌级项目的品质要求。</p><p>青萍AI语音接入了大量专业配音员，每位都有独立主页和样音展示。<br>你可以直接在线试听，找到合适的再下单，拿不准还能让多人免费试录一小段。</p><p><img src="https://img-cdn.lusyoe.cn/images/lusyoe/2026/05/25/t7a3es4p0x.webp" alt="真人配音页面"></p><p>价格按 100 字计费，从几块钱到几十块都有，丰俭由人。</p><p>AI做初稿批量出活，真人做精修保证质量，两种模式灵活切换。<br>漫剧制作周期紧的时候先用AI出初版，关键场景再交给真人精修，效率和质量都不耽误。</p><h1 id="开始使用"><a href="#开始使用" class="headerlink" title="开始使用"></a>开始使用</h1><p>网页版访问 audio.lusyoe.com 注册即可使用。<br>另外微信小程序版也已上线，搜索”青萍叙事创作工具”就能找到。<br>关注公众号「青萍叙事」，回复邀请码，通过邀请码注册可免费获得 120 积分。<br>最多可生成 5.1 万字配音，够你把克隆音色、配音生成这些核心功能都体验一遍。</p>]]>
    </content>
    <id>https://blog.lusyoe.com/article/ai-comic-drama-dubbing</id>
    <link href="https://blog.lusyoe.com/article/ai-comic-drama-dubbing"/>
    <published>2026-06-10T18:00:00.000+08:00</published>
    <summary>漫剧配音成本高、周期长、改动频繁，一直是创作者最头疼的环节。青萍AI语音提供音色克隆、音色设计、配音生成和情绪参数等AI功能，同时接入大量专业真人配音员，一站式解决漫剧配音难题。关注公众号青萍叙事获取邀请码可免费获得 120 积分。</summary>
    <title>AI漫剧之配音篇</title>
    <updated>2026-06-10T18:00:00.000+08:00</updated>
  </entry>
  <entry>
    <author>
      <name>青萍叙事</name>
    </author>
    <category term="Hermes" scheme="https://blog.lusyoe.com/categories/Hermes/"/>
    <category term="DevOps" scheme="https://blog.lusyoe.com/tags/DevOps/"/>
    <category term="Hermes-Agent" scheme="https://blog.lusyoe.com/tags/Hermes-Agent/"/>
    <category term="工作流" scheme="https://blog.lusyoe.com/tags/%E5%B7%A5%E4%BD%9C%E6%B5%81/"/>
    <content>
      <![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>写内容有个尴尬的阶段：写一篇文章不难，但是从写完到发布，中间有一堆琐事。</p><p>审查格式、修破折号、生成封面图、压缩上传、git 提交。<br>每篇都来一遍，烦不烦？<br>烦。</p><p>所以我把这个过程做成了一条自动化生产线。<br>用 Hermes Agent 的 Profile 系统和多 Agent 协作，从写完文章到发布，一条指令搞定。</p><p>目前跑下来效果不错，写出来分享一下。</p><h1 id="整条生产线长什么样"><a href="#整条生产线长什么样" class="headerlink" title="整条生产线长什么样"></a>整条生产线长什么样</h1><p>流程分成 6 个步骤，全部用 Hermes 的 <code>delegate_task</code> 串起来：</p><p>写作，内容审查，修复，二次审查，封面图生成与上传，发布。</p><p><img src="https://img-cdn.lusyoe.cn/images/lusyoe/2026/06/10/pipeline-flow@2x.webp" alt="内容生产线流程"></p><p>每个步骤都是独立的 Agent，互不干扰。<br>写作阶段我在主会话里完成，后面的脏活累活丢给子 Agent 去跑。</p><p>核心思路很简单：把以前手动做的事情，写成可重复的 Agent 工作流。</p><h1 id="内容审查：让人工智能检查人工智能"><a href="#内容审查：让人工智能检查人工智能" class="headerlink" title="内容审查：让人工智能检查人工智能"></a>内容审查：让人工智能检查人工智能</h1><p>这是整个流程里最重要的一环。<br>Hermes 写文章有时候会带点 AI 腔，写多了还会漏掉格式规范。</p><p>审查 Agent 专门用 <code>deepseek-v4-pro</code> 模型，因为审查对细节敏感度要求高，普通模型的注意力不够。<br>它带着整篇文章和完整的写作规范清单去逐行检查，发现的问题按严重程度标注：</p><ul><li>🔴 必须修。比如破折号、角括号、分割线。</li><li>🟡 建议修。比如一句多行、标题内容不匹配。</li><li>🟢 可优化。比如代码示例不完整、字段缺失。</li></ul><p>审查 Agent 不写临时文件，结论直接 return 给我。<br>修完一轮还得二次审查，确保前面改的问题没有漏网之鱼，也没有因为改东西引入新问题。</p><p>这个双轮审查机制救了我好几次。<br>有一次 ai 字段里写了 <code>RuntimeError: Executor shutdown has been called</code>，其中的冒号加空格让 YAML 解析直接挂了，审查 Agent 一眼就发现了。</p><h1 id="封面图：从-HTML-到-CDN-的最后一公里"><a href="#封面图：从-HTML-到-CDN-的最后一公里" class="headerlink" title="封面图：从 HTML 到 CDN 的最后一公里"></a>封面图：从 HTML 到 CDN 的最后一公里</h1><p>文章定稿后，封面图生成是个独立步骤。</p><p>Hermes 的 <code>cover-image-generator</code> skill 负责这件事。<br>它用一套 HTML 模板拼接文章信息：标题、副标题、Logo、标签，然后用 Playwright 调用系统的 Chrome 浏览器截图。</p><p>说起来简单，但踩过不少坑。<br>之前用的渐变背景看起来太廉价，后来改成纯色深底加 Logo 大字的风格，顺眼多了。<br>Logo 统一从 jsdelivr 拉 CDN 版本，Hermes 系列文章用绿色强调色。</p><p>截图出来是 3840x2160 的 PNG，用 <code>cwebp -q 75</code> 压到 50KB 左右的 WebP，再调用青萍图床的 API 上传。</p><p>封面和配图能稳定上线，全靠青萍图床这个基础设施。<br>它是面向内容创作和电商设计的图片管理平台，官网在 <a href="https://img.lusyoe.com/">img.lusyoe.com</a>。<br>上传后自动分配 CDN 加速地址，不需要自己搭 OSS 或折腾 Nginx。<br>整个生产线里，封面图、内文配图、产品展示图，都走这一条链路。</p><p>这里有个有意思的设计：封面图生成后不自动上传，等我说了 <strong>上传</strong> 才执行。<br>因为截图效果好不好，我得先看一眼。</p><h1 id="content-publisher：收尾一步交给专用-Agent"><a href="#content-publisher：收尾一步交给专用-Agent" class="headerlink" title="content-publisher：收尾一步交给专用 Agent"></a>content-publisher：收尾一步交给专用 Agent</h1><p>封面图上传到 CDN、写入文章的 cover 字段后，发布是收尾。</p><p>这一步我单独拆了一个 <code>content-publisher</code> 专用 Agent。<br>发布到个人博客（Hexo）时，它的职责很单一：<code>git add</code>、<code>git commit</code>、<code>git push</code>。<br>不多不少。</p><p>但它不止管博客。<br>同一条内容，可以一键分发到知乎、博客园、微信公众号、今日头条等多个渠道。<br>每次调用时指定目标渠道，content-publisher 自动适配对应的格式和发布方式。</p><p>为什么不用主 Agent 直接操作 git？<br>两个原因。<br>一是权限隔离，发布 Agent 只需要终端和文件工具的权限，没有理由给它更多。<br>二是专注性，主 Agent 可以花很长时间研究文章内容，发布 Agent 只做一件事，不会分心。</p><p>从 <code>delegate_task</code> 调过去时，带上 git 仓库的地址和凭据，它几秒钟就搞定了。<br>我这边继续写下一篇文章，它后面默默把发布跑完。</p><p><img src="https://img-cdn.lusyoe.cn/images/lusyoe/2026/06/10/delegate-arch@2x.webp" alt="delegate_task 多 Agent 协作架构"></p><h1 id="这条生产线给我带来了什么"><a href="#这条生产线给我带来了什么" class="headerlink" title="这条生产线给我带来了什么"></a>这条生产线给我带来了什么</h1><p>以前发一篇文章，从写完到上线，怎么也得 15 到 20 分钟的收尾工作。</p><p>现在写完文章说一句 <strong>帮我走流程</strong>，然后等着就行。</p><p>审查 Agent 找出问题，我确认修复。<br>封面图生成后看一眼效果，确认上传。<br>发布 Agent 推完代码，回来告诉我 commit SHA。</p><p>省下来的时间不多，但每篇都省一点，积少成多。<br>说白了，那些枯燥的重复劳动不用我自己干了。<br>机器擅长的事就交给机器，人只做需要判断的事。<br>这大概就是自动化最朴素的价值。</p>]]>
    </content>
    <id>https://blog.lusyoe.com/article/hermes-agent-content-production-line</id>
    <link href="https://blog.lusyoe.com/article/hermes-agent-content-production-line"/>
    <published>2026-06-10T14:00:00.000+08:00</published>
    <summary>用 Hermes Agent 搭了一条从写作到发布的全自动内容生产线，Agent 自动走完审查、修复、封面图、上传和发布。</summary>
    <title>用 Hermes Agent 搭了一条内容生产线</title>
    <updated>2026-06-10T14:00:00.000+08:00</updated>
  </entry>
  <entry>
    <author>
      <name>青萍叙事</name>
    </author>
    <category term="Hermes" scheme="https://blog.lusyoe.com/categories/Hermes/"/>
    <category term="Hermes-Agent" scheme="https://blog.lusyoe.com/tags/Hermes-Agent/"/>
    <category term="运维" scheme="https://blog.lusyoe.com/tags/%E8%BF%90%E7%BB%B4/"/>
    <category term="macOS" scheme="https://blog.lusyoe.com/tags/macOS/"/>
    <content>
      <![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>昨天手痒，给 Hermes Gateway 换了个新模型。<br>结果飞书那边突然就收不到消息了。</p><p>第一反应是：换模型搞坏了？<br>赶紧查 Gateway 日志，看到了这么一行：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">RuntimeError: Executor shutdown has been called</span><br></pre></td></tr></table></figure><p>飞书的 WebSocket 连接也断了，Gateway 看起来还在跑，但实际上已经是个空壳。</p><h1 id="排查：先看-Gateway-日志"><a href="#排查：先看-Gateway-日志" class="headerlink" title="排查：先看 Gateway 日志"></a>排查：先看 Gateway 日志</h1><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">2026-06-09 14:23:45 INFO  Gateway started</span><br><span class="line">2026-06-09 14:23:46 INFO  Feishu WebSocket connected</span><br><span class="line">...</span><br><span class="line">2026-06-09 15:34:12 ERROR RuntimeError: Executor shutdown has been called</span><br><span class="line">2026-06-09 15:34:12 ERROR Feishu WebSocket connection lost</span><br></pre></td></tr></table></figure><p>Gateway 14:23 启动，15:34 报错，刚好运行了 <strong>1 小时 11 分钟</strong>。</p><p>这个时间点很微妙，不是刚启动就挂，而是运行了一段时间后才出问题。<br>换模型的操作发生在 15:30 左右，看起来像是换模型触发了问题，但实际上根因不在这里。</p><h1 id="根因：Python-asyncio-executor-的生命周期陷阱"><a href="#根因：Python-asyncio-executor-的生命周期陷阱" class="headerlink" title="根因：Python asyncio executor 的生命周期陷阱"></a>根因：Python asyncio executor 的生命周期陷阱</h1><p>Gateway 是 Python 写的，核心用的是 asyncio event loop。<br>问题出在 <code>run_in_executor</code> 这个调用上。</p><p>Python asyncio 的 <code>loop.run_in_executor()</code> 会把同步代码丢到线程池里执行。<br>默认情况下，它用的是 event loop 自带的 <code>ThreadPoolExecutor</code>。<br>这个 executor 的生命周期管理有个坑：</p><p><strong>如果 executor 的引用计数归零，Python 的垃圾回收器会把它清理掉，调用 <code>shutdown()</code>。</strong></p><p>在长时间运行的服务里，这种情况可能悄无声息地发生：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 这段代码可能出问题</span></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">def</span> <span class="title function_">call_llm</span>(<span class="params">prompt</span>):</span><br><span class="line">    loop = asyncio.get_event_loop()</span><br><span class="line">    <span class="comment"># 如果 executor 被 GC 回收，这里就会报错</span></span><br><span class="line">    result = <span class="keyword">await</span> loop.run_in_executor(<span class="literal">None</span>, sync_llm_call, prompt)</span><br><span class="line">    <span class="keyword">return</span> result</span><br></pre></td></tr></table></figure><p>日志里的 <code>Executor shutdown has been called</code> 就是这么来的。<br>executor 被关了，所有依赖它的异步任务都会失败，飞书的 WebSocket 消息处理自然也跟着挂了。</p><p>加上 macOS 的内存压力管理（memory pressure），长时间运行的 Python 进程更容易触发这类内部状态异常。<br>系统可能在后台杀掉了一些不活跃的线程，导致 executor 的内部状态被破坏。</p><h1 id="发现问题：-–replace-的坑"><a href="#发现问题：-–replace-的坑" class="headerlink" title="发现问题：`–replace` 的坑"></a>发现问题：`–replace` 的坑</h1><p>最直接的办法就是重启：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hermes gateway start</span><br></pre></td></tr></table></figure><p>重启后飞书消息恢复正常。<br>但这只是临时方案，后面还会遇到同样的问题。</p><p>这里又踩了一个坑，我发现之前的 Gateway 是用 <code>--replace</code> 模式启动的：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hermes gateway start --replace</span><br></pre></td></tr></table></figure><p><code>--replace</code> 的作用是如果已有 Gateway 在跑，先杀掉再启动新的。<br>听起来很方便对吧？<br>但在 macOS 上，如果你用了 launchd 来管理服务，<code>--replace</code> 会导致冲突。</p><p><strong>Gateway 被 launchd 拉起来后，你手动 <code>--replace</code> 启动一个新的，launchd 不知道旧的被杀了，新旧进程就会打架。</strong></p><h1 id="最佳实践：用-launchd-托管-Gateway"><a href="#最佳实践：用-launchd-托管-Gateway" class="headerlink" title="最佳实践：用 launchd 托管 Gateway"></a>最佳实践：用 launchd 托管 Gateway</h1><p>macOS 上管理后台服务，launchd 是正道。<br>先看看现有的配置：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">ls</span> ~/Library/LaunchAgents/ai.hermes.gateway-*.plist</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">/Users/lu/Library/LaunchAgents/ai.hermes.gateway-default.plist</span><br><span class="line">/Users/lu/Library/LaunchAgents/ai.hermes.gateway-work.plist</span><br></pre></td></tr></table></figure><p>每个 profile 有一个对应的 plist 文件。<br>看看里面写了什么：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cat</span> ~/Library/LaunchAgents/ai.hermes.gateway-default.plist</span><br></pre></td></tr></table></figure><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="meta">&lt;!DOCTYPE <span class="keyword">plist</span> <span class="keyword">PUBLIC</span> <span class="string">&quot;-//Apple//DTD PLIST 1.0//EN&quot;</span> </span></span><br><span class="line"><span class="meta">  <span class="string">&quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">plist</span> <span class="attr">version</span>=<span class="string">&quot;1.0&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dict</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">key</span>&gt;</span>Label<span class="tag">&lt;/<span class="name">key</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">string</span>&gt;</span>ai.hermes.gateway-default<span class="tag">&lt;/<span class="name">string</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">key</span>&gt;</span>ProgramArguments<span class="tag">&lt;/<span class="name">key</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">array</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">string</span>&gt;</span>/Users/lu/.hermes/bin/hermes<span class="tag">&lt;/<span class="name">string</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">string</span>&gt;</span>gateway<span class="tag">&lt;/<span class="name">string</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">string</span>&gt;</span>start<span class="tag">&lt;/<span class="name">string</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">string</span>&gt;</span>--replace<span class="tag">&lt;/<span class="name">string</span>&gt;</span>   <span class="comment">&lt;!-- 问题在这 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">array</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">key</span>&gt;</span>RunAtLoad<span class="tag">&lt;/<span class="name">key</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">true</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">key</span>&gt;</span>KeepAlive<span class="tag">&lt;/<span class="name">key</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dict</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">key</span>&gt;</span>SuccessfulExit<span class="tag">&lt;/<span class="name">key</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">false</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dict</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dict</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">plist</span>&gt;</span></span><br></pre></td></tr></table></figure><p>看到了吧，<code>ProgramArguments</code> 里赫然写着 <code>--replace</code>。<br>这就是问题所在。</p><h1 id="批量修复-plist-配置"><a href="#批量修复-plist-配置" class="headerlink" title="批量修复 plist 配置"></a>批量修复 plist 配置</h1><p>检查了一下，所有 profile 的 plist 都有这个问题。<br>手动改太慢，写个脚本批量处理：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 查看所有有问题的 plist</span></span><br><span class="line">grep -l <span class="string">&quot;\-\-replace&quot;</span> ~/Library/LaunchAgents/ai.hermes.gateway-*.plist</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">/Users/lu/Library/LaunchAgents/ai.hermes.gateway-default.plist</span><br><span class="line">/Users/lu/Library/LaunchAgents/ai.hermes.gateway-work.plist</span><br></pre></td></tr></table></figure><p>批量移除 <code>--replace</code>：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> plist <span class="keyword">in</span> ~/Library/LaunchAgents/ai.hermes.gateway-*.plist; <span class="keyword">do</span></span><br><span class="line">    <span class="comment"># 移除 --replace 那一行</span></span><br><span class="line">    sed -i <span class="string">&#x27;&#x27;</span> <span class="string">&#x27;/&lt;string&gt;--replace&lt;\/string&gt;/d&#x27;</span> <span class="string">&quot;<span class="variable">$plist</span>&quot;</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">&quot;Fixed: <span class="variable">$plist</span>&quot;</span></span><br><span class="line"><span class="keyword">done</span></span><br></pre></td></tr></table></figure><p>重新加载所有 launchd 服务：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 先卸载再加载</span></span><br><span class="line">launchctl unload ~/Library/LaunchAgents/ai.hermes.gateway-*.plist</span><br><span class="line">launchctl load ~/Library/LaunchAgents/ai.hermes.gateway-*.plist</span><br></pre></td></tr></table></figure><blockquote><p>新版 macOS 上 <code>unload</code>&#x2F;<code>load</code> 已标记为 legacy，推荐用 <code>bootout</code>&#x2F;<code>bootstrap</code>：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">launchctl bootout gui/$(<span class="built_in">id</span> -u) ~/Library/LaunchAgents/ai.hermes.gateway-*.plist 2&gt;/dev/null</span><br><span class="line">launchctl bootstrap gui/$(<span class="built_in">id</span> -u) ~/Library/LaunchAgents/ai.hermes.gateway-*.plist</span><br></pre></td></tr></table></figure></blockquote><p>验证一下：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">launchctl list | grep hermes</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">ai.hermes.gateway-default    0    com.apple.xpc.launchd.oneshot.0x10000001.hermes</span><br><span class="line">ai.hermes.gateway-work       0    com.apple.xpc.launchd.oneshot.0x10000002.hermes</span><br></pre></td></tr></table></figure><p>状态码是 0，说明正常运行。</p><h1 id="踩坑后的教训"><a href="#踩坑后的教训" class="headerlink" title="踩坑后的教训"></a>踩坑后的教训</h1><p><strong>asyncio executor 的坑要提前防。</strong></p><p>长时间运行的 Python 服务，executor 的生命周期不能完全交给垃圾回收器。<br>要么显式持有 executor 的引用，要么定期检查 executor 状态。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 显式持有 executor 引用</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Gateway</span>:</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self</span>):</span><br><span class="line">        <span class="variable language_">self</span>._executor = ThreadPoolExecutor(max_workers=<span class="number">4</span>)</span><br><span class="line">        <span class="variable language_">self</span>._loop = asyncio.get_event_loop()</span><br><span class="line">        <span class="variable language_">self</span>._loop.set_default_executor(<span class="variable language_">self</span>._executor)</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">async</span> <span class="keyword">def</span> <span class="title function_">call_in_background</span>(<span class="params">self, func, *args</span>):</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">await</span> <span class="variable language_">self</span>._loop.run_in_executor(<span class="variable language_">self</span>._executor, func, *args)</span><br></pre></td></tr></table></figure><p><strong>macOS 服务必须用 launchd 托管。</strong></p><p>别用 <code>nohup</code> 后台跑。<br>别用 <code>--replace</code>。<br>别用 <code>screen</code> 或 <code>tmux</code>。<br>launchd 是 macOS 原生的服务管理器，它会帮你处理进程崩溃重启、开机自启、资源限制等问题。</p><p>关键配置点：</p><ul><li><code>RunAtLoad=true</code>：登录时自动启动</li><li><code>KeepAlive.SuccessfulExit=false</code>：正常退出不重启，异常退出才重启</li><li>不要加 <code>--replace</code>：让 launchd 管理进程生命周期</li></ul><p><strong>遇到连接问题先查日志。</strong></p><p>飞书消息发不出去，原因可能很多：网络问题、token 过期、服务挂了……<br>别上来就重启，先看日志。<br>日志里的错误信息通常能直接指向问题根因。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 查看 Gateway 最近日志</span></span><br><span class="line"><span class="built_in">tail</span> -100 ~/.hermes/logs/gateway-default.log</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看 launchd 的日志</span></span><br><span class="line"><span class="built_in">log</span> show --predicate <span class="string">&#x27;processImagePath contains &quot;hermes&quot;&#x27;</span> --last 1h</span><br></pre></td></tr></table></figure><p>这次排查让我对 Python asyncio 的底层机制有了更深的理解。<br>asyncio 不是银弹。<br>executor 管理、事件循环生命周期这些细节，在开发阶段很难暴露，往往要跑到生产环境、运行一段时间后才会出问题。</p><p>好在这次只是飞书消息发不出去，不是什么致命故障。<br>但也提醒我，对于长时间运行的服务，监控和容错设计真的不能偷懒。</p>]]>
    </content>
    <id>https://blog.lusyoe.com/article/hermes-gateway-feishu-connection-issues</id>
    <link href="https://blog.lusyoe.com/article/hermes-gateway-feishu-connection-issues"/>
    <published>2026-06-10T10:00:00.000+08:00</published>
    <summary>记录一次 Hermes Gateway 飞书消息发不出去的排查过程。从飞书 WebSocket 断连到发现 asyncio executor 被意外关闭，再到修复 launchd 配置，完整复盘。</summary>
    <title>Hermes Gateway 飞书连接断开排查</title>
    <updated>2026-06-10T10:00:00.000+08:00</updated>
  </entry>
</feed>
