<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Home on Kmoon Blog</title>
    <link>https://blog.kmoon.fun/</link>
    <description>Recent content in Home on Kmoon Blog</description>
    <generator>Hugo</generator>
    <language>zh-CN</language>
    
      <managingEditor>hushan@kmoon.fun (Kmoon)</managingEditor>
    
    
      <webMaster>hushan@kmoon.fun (Kmoon)</webMaster>
    
    
    <copyright>Copyright © 2020-2026. Kmoon.</copyright>
    
    
    <lastBuildDate>Fri, 26 Jun 2026 13:10:41 +0800</lastBuildDate>
    
    
    <follow_challenge>
        <feedId>00000000000000000</feedId>
        <userId>00000000000000000</userId>
    </follow_challenge>
    
    <atom:link href="https://blog.kmoon.fun/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Links</title>
      <link>https://blog.kmoon.fun/links/</link>
      <pubDate>Wed, 17 Jun 2026 17:08:16 +0800</pubDate><author>hushan@kmoon.fun (Kmoon)</author>
      <guid>https://blog.kmoon.fun/links/</guid>
      <description>&lt;p&gt;A small map of places I return to, things I build, and people I am glad to know online.&lt;/p&gt;&#xA;&lt;p&gt;If you&amp;rsquo;d like to exchange links, feel free to reach out. Please submit &lt;a href=&#34;https://my.feishu.cn/share/base/form/shrcnBEu9mmLeio3pbLasFJCH2b&#34;&gt;this&lt;/a&gt;!&lt;/p&gt;&#xA;&lt;section class=&#34;links-section&#34;&gt;&#xA;  &lt;div class=&#34;links-section-header&#34;&gt;&#xA;    &lt;p class=&#34;links-section-kicker&#34;&gt;Regular reads&lt;/p&gt;&#xA;  &lt;/div&gt;&#xA;  &lt;div class=&#34;links-grid links-grid--reads&#34;&gt;&#xA;    &lt;a href=&#34;https://www.hellogithub.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34; class=&#34;link-card&#34;&gt;&#xA;      &lt;img src=&#34;https://www.hellogithub.com/favicon.ico&#34; class=&#34;link-avatar&#34; loading=&#34;lazy&#34;&gt;&#xA;      &lt;div class=&#34;link-info&#34;&gt;&#xA;        &lt;span class=&#34;link-domain&#34;&gt;hellogithub.com&lt;/span&gt;&#xA;        &lt;span class=&#34;link-name&#34;&gt;Hello Github 月刊&lt;/span&gt;&#xA;      &lt;/div&gt;&#xA;      &lt;span class=&#34;link-arrow&#34; aria-hidden=&#34;true&#34;&gt;↗&lt;/span&gt;&#xA;    &lt;/a&gt;&#xA;    &lt;a href=&#34;https://www.ruanyifeng.com/blog/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34; class=&#34;link-card&#34;&gt;&#xA;      &lt;img src=&#34;https://www.ruanyifeng.com/favicon.ico&#34; class=&#34;link-avatar&#34; loading=&#34;lazy&#34;&gt;&#xA;      &lt;div class=&#34;link-info&#34;&gt;&#xA;        &lt;span class=&#34;link-domain&#34;&gt;www.ruanyifeng.com&lt;/span&gt;&#xA;        &lt;span class=&#34;link-name&#34;&gt;阮一峰的网络日志&lt;/span&gt;&#xA;      &lt;/div&gt;&#xA;      &lt;span class=&#34;link-arrow&#34; aria-hidden=&#34;true&#34;&gt;↗&lt;/span&gt;&#xA;    &lt;/a&gt;&#xA;    &lt;a href=&#34;https://github.com/trending&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34; class=&#34;link-card&#34;&gt;&#xA;      &lt;img src=&#34;https://github.githubassets.com/favicons/favicon.svg&#34; class=&#34;link-avatar&#34; loading=&#34;lazy&#34;&gt;&#xA;      &lt;div class=&#34;link-info&#34;&gt;&#xA;        &lt;span class=&#34;link-domain&#34;&gt;github.com/trending&lt;/span&gt;&#xA;        &lt;span class=&#34;link-name&#34;&gt;GitHub Trending&lt;/span&gt;&#xA;      &lt;/div&gt;&#xA;      &lt;span class=&#34;link-arrow&#34; aria-hidden=&#34;true&#34;&gt;↗&lt;/span&gt;&#xA;    &lt;/a&gt;&#xA;    &lt;a href=&#34;https://www.v2ex.com&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34; class=&#34;link-card&#34;&gt;&#xA;      &lt;img src=&#34;https://www.v2ex.com/static/favicon.ico&#34; class=&#34;link-avatar&#34; loading=&#34;lazy&#34;&gt;&#xA;      &lt;div class=&#34;link-info&#34;&gt;&#xA;        &lt;span class=&#34;link-domain&#34;&gt;www.v2ex.com&lt;/span&gt;&#xA;        &lt;span class=&#34;link-name&#34;&gt;V2EX&lt;/span&gt;&#xA;      &lt;/div&gt;&#xA;      &lt;span class=&#34;link-arrow&#34; aria-hidden=&#34;true&#34;&gt;↗&lt;/span&gt;&#xA;    &lt;/a&gt;&#xA;    &lt;a href=&#34;https://space.bilibili.com/316183842&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34; class=&#34;link-card&#34;&gt;&#xA;      &lt;img src=&#34;https://cdn.kmoon.fun/%E5%93%94%E5%93%A9%E5%93%94%E5%93%A9.png&#34; class=&#34;link-avatar link-avatar--cover&#34; loading=&#34;lazy&#34;&gt;&#xA;      &lt;div class=&#34;link-info&#34;&gt;&#xA;        &lt;span class=&#34;link-domain&#34;&gt;space.bilibili.com&lt;/span&gt;&#xA;        &lt;span class=&#34;link-name&#34;&gt;技术爬爬虾&lt;/span&gt;&#xA;      &lt;/div&gt;&#xA;      &lt;span class=&#34;link-arrow&#34; aria-hidden=&#34;true&#34;&gt;↗&lt;/span&gt;&#xA;    &lt;/a&gt;&#xA;    &lt;a href=&#34;https://space.bilibili.com/1815948385&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34; class=&#34;link-card&#34;&gt;&#xA;      &lt;img src=&#34;https://cdn.kmoon.fun/%E5%93%94%E5%93%A9%E5%93%94%E5%93%A9.png&#34; class=&#34;link-avatar link-avatar--cover&#34; loading=&#34;lazy&#34;&gt;&#xA;      &lt;div class=&#34;link-info&#34;&gt;&#xA;        &lt;span class=&#34;link-domain&#34;&gt;space.bilibili.com&lt;/span&gt;&#xA;        &lt;span class=&#34;link-name&#34;&gt;马克的技术工作坊&lt;/span&gt;&#xA;      &lt;/div&gt;&#xA;      &lt;span class=&#34;link-arrow&#34; aria-hidden=&#34;true&#34;&gt;↗&lt;/span&gt;&#xA;    &lt;/a&gt;&#xA;    &lt;a href=&#34;https://testerhome.com&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34; class=&#34;link-card&#34;&gt;&#xA;      &lt;img src=&#34;https://testerhome.com/photo/favicon.png&#34; class=&#34;link-avatar link-avatar--cover&#34; loading=&#34;lazy&#34;&gt;&#xA;      &lt;div class=&#34;link-info&#34;&gt;&#xA;        &lt;span class=&#34;link-domain&#34;&gt;testerhome.com&lt;/span&gt;&#xA;        &lt;span class=&#34;link-name&#34;&gt;TesterHome&lt;/span&gt;&#xA;      &lt;/div&gt;&#xA;      &lt;span class=&#34;link-arrow&#34; aria-hidden=&#34;true&#34;&gt;↗&lt;/span&gt;&#xA;    &lt;/a&gt;&#xA;  &lt;/div&gt;&#xA;&lt;/section&gt;&#xA;&lt;section class=&#34;links-section&#34;&gt;&#xA;  &lt;div class=&#34;links-section-header&#34;&gt;&#xA;    &lt;p class=&#34;links-section-kicker&#34;&gt;Friends on the web&lt;/p&gt;&#xA;  &lt;/div&gt;&#xA;  &lt;div class=&#34;links-grid links-grid--friends&#34;&gt;&#xA;    &lt;a href=&#34;https://blog.pdjjq.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34; class=&#34;link-card&#34;&gt;&#xA;      &lt;img src=&#34;https://blog.pdjjq.org//images/apple-touch-icon.png&#34; class=&#34;link-avatar link-avatar--cover&#34; loading=&#34;lazy&#34;&gt;&#xA;      &lt;div class=&#34;link-info&#34;&gt;&#xA;        &lt;span class=&#34;link-domain&#34;&gt;blog.pdjjq.org&lt;/span&gt;&#xA;        &lt;span class=&#34;link-name&#34;&gt;DJJ&lt;/span&gt;&#xA;        &lt;span class=&#34;link-desc&#34;&gt;反抗吧，朋友！&lt;/span&gt;&#xA;      &lt;/div&gt;&#xA;      &lt;span class=&#34;link-arrow&#34; aria-hidden=&#34;true&#34;&gt;↗&lt;/span&gt;&#xA;    &lt;/a&gt;&#xA;    &lt;a href=&#34;https://blog.zhilu.site/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34; class=&#34;link-card&#34;&gt;&#xA;      &lt;img src=&#34;https://www.zhilu.site/api/avatar.png&#34; class=&#34;link-avatar link-avatar--cover&#34; loading=&#34;lazy&#34;&gt;&#xA;      &lt;div class=&#34;link-info&#34;&gt;&#xA;        &lt;span class=&#34;link-domain&#34;&gt;zhilu.site&lt;/span&gt;&#xA;        &lt;span class=&#34;link-name&#34;&gt;纸鹿摸鱼处&lt;/span&gt;&#xA;        &lt;span class=&#34;link-desc&#34;&gt;纸鹿至麓不知路&lt;/span&gt;&#xA;      &lt;/div&gt;&#xA;      &lt;span class=&#34;link-arrow&#34; aria-hidden=&#34;true&#34;&gt;↗&lt;/span&gt;&#xA;    &lt;/a&gt;&#xA;    &lt;a href=&#34;https://imbottle.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34; class=&#34;link-card&#34;&gt;&#xA;      &lt;img src=&#34;https://raw.githubusercontent.com/SomeBottle/somebottle/master/sticker/cut_the_potato.gif&#34; class=&#34;link-avatar link-avatar--cover&#34; loading=&#34;lazy&#34;&gt;&#xA;      &lt;div class=&#34;link-info&#34;&gt;&#xA;        &lt;span class=&#34;link-domain&#34;&gt;bottle.moe&lt;/span&gt;&#xA;        &lt;span class=&#34;link-name&#34;&gt;些瓶的小站&lt;/span&gt;&#xA;        &lt;span class=&#34;link-desc&#34;&gt;相信的心就是你的魔法！&lt;/span&gt;&#xA;      &lt;/div&gt;&#xA;      &lt;span class=&#34;link-arrow&#34; aria-hidden=&#34;true&#34;&gt;↗&lt;/span&gt;&#xA;    &lt;/a&gt;&#xA;    &lt;a href=&#34;https://blog.hazenix.top&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34; class=&#34;link-card&#34;&gt;&#xA;      &lt;img src=&#34;https://blog.hazenix.top/avatar.webp&#34; class=&#34;link-avatar link-avatar--cover&#34; loading=&#34;lazy&#34;&gt;&#xA;      &lt;div class=&#34;link-info&#34;&gt;&#xA;        &lt;span class=&#34;link-domain&#34;&gt;blog.hazenix.top&lt;/span&gt;&#xA;        &lt;span class=&#34;link-name&#34;&gt;Hazenix&#39;s Blog&lt;/span&gt;&#xA;        &lt;span class=&#34;link-desc&#34;&gt;我会一直走，走到灯火通明。&lt;/span&gt;&#xA;      &lt;/div&gt;&#xA;      &lt;span class=&#34;link-arrow&#34; aria-hidden=&#34;true&#34;&gt;↗&lt;/span&gt;&#xA;    &lt;/a&gt;&#xA;    &lt;a href=&#34;https://feeshy.top&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34; class=&#34;link-card&#34;&gt;&#xA;      &lt;img src=&#34;https://feeshy.top/favicon.svg&#34; class=&#34;link-avatar link-avatar--cover&#34; loading=&#34;lazy&#34;&gt;&#xA;      &lt;div class=&#34;link-info&#34;&gt;&#xA;        &lt;span class=&#34;link-domain&#34;&gt;feeshy.top&lt;/span&gt;&#xA;        &lt;span class=&#34;link-name&#34;&gt;浮鲜&lt;/span&gt;&#xA;        &lt;span class=&#34;link-desc&#34;&gt;feeshy的多元兴趣探索记录&lt;/span&gt;&#xA;      &lt;/div&gt;&#xA;      &lt;span class=&#34;link-arrow&#34; aria-hidden=&#34;true&#34;&gt;↗&lt;/span&gt;&#xA;    &lt;/a&gt;&#xA;  &lt;/div&gt;&#xA;  &lt;/br&gt;&#xA;&lt;/section&gt;&#xA;&lt;style&gt;&#xA;.links-section {&#xA;  margin: 22px 0 26px;&#xA;}&#xA;&#xA;.links-section-header {&#xA;  margin-bottom: 8px;&#xA;}&#xA;&#xA;.links-section-kicker {&#xA;  margin: 0;&#xA;  font-family: var(--font-secondary), serif;&#xA;  font-size: 10px;&#xA;  letter-spacing: 0.1em;&#xA;  text-transform: uppercase;&#xA;  color: var(--text-color-tertiary);&#xA;}&#xA;&#xA;.links-grid {&#xA;  --link-card-paper: #fbfcfe;&#xA;  --link-card-muted: #5b6675;&#xA;  --link-card-shadow: 0 8px 18px rgba(15, 23, 42, 0.05);&#xA;  display: grid;&#xA;  gap: 12px;&#xA;  margin: 0;&#xA;}&#xA;&#xA;.links-grid--reads,&#xA;.links-grid--works,&#xA;.links-grid--friends {&#xA;  grid-template-columns: repeat(3, minmax(0, 1fr));&#xA;}&#xA;&#xA;.link-card,&#xA;.link-card:visited,&#xA;.link-card:hover,&#xA;.link-card:active {&#xA;  position: relative;&#xA;  display: flex;&#xA;  align-items: center;&#xA;  gap: 10px;&#xA;  min-height: 48px;&#xA;  padding: 10px 13px;&#xA;  background: linear-gradient(180deg, var(--link-card-paper) 0%, var(--bg-color-secondary) 100%);&#xA;  border: 1px solid var(--border-color);&#xA;  border-radius: 14px;&#xA;  box-shadow: var(--link-card-shadow);&#xA;  text-decoration: none;&#xA;  color: inherit;&#xA;  overflow: hidden;&#xA;  transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease, background-color 0.18s ease;&#xA;}&#xA;&#xA;.link-card::before {&#xA;  content: &#34;&#34;;&#xA;  position: absolute;&#xA;  inset: 0 0 auto;&#xA;  height: 4px;&#xA;  background: repeating-linear-gradient(&#xA;    90deg,&#xA;    var(--link-card-stripe-a) 0 18px,&#xA;    transparent 18px 24px,&#xA;    var(--link-card-stripe-b) 24px 42px,&#xA;    transparent 42px 48px,&#xA;    var(--link-card-stripe-c) 48px 66px,&#xA;    transparent 66px 72px&#xA;  );&#xA;}&#xA;&#xA;.link-card:hover,&#xA;.link-card:focus-visible {&#xA;  transform: translateY(-2px);&#xA;  border-color: var(--link-color);&#xA;  box-shadow: 0 12px 22px rgba(15, 23, 42, 0.09);&#xA;  text-decoration: none;&#xA;}&#xA;&#xA;.link-card:focus-visible {&#xA;  outline: 2px solid var(--link-color);&#xA;  outline-offset: 3px;&#xA;}&#xA;&#xA;.link-avatar {&#xA;  width: 40px;&#xA;  height: 40px;&#xA;  margin: 0;&#xA;  padding: 5px;&#xA;  border-radius: 12px;&#xA;  box-sizing: border-box;&#xA;  border: 1px solid var(--border-color);&#xA;  background: linear-gradient(180deg, rgba(255, 255, 255, 0.92) 0%, rgba(244, 247, 251, 0.92) 100%);&#xA;  overflow: hidden;&#xA;  object-fit: contain;&#xA;  flex-shrink: 0;&#xA;}&#xA;&#xA;.link-avatar--cover {&#xA;  padding: 0;&#xA;  object-fit: cover;&#xA;}&#xA;&#xA;.link-card:hover .link-avatar,&#xA;.link-card:focus-visible .link-avatar {&#xA;  transform: translateY(-1px);&#xA;  border-color: var(--link-color);&#xA;}&#xA;&#xA;.link-info {&#xA;  display: grid;&#xA;  gap: 2px;&#xA;  min-width: 0;&#xA;  flex: 1;&#xA;}&#xA;&#xA;.link-domain {&#xA;  font-family: var(--font-secondary), serif;&#xA;  font-size: 10px;&#xA;  letter-spacing: 0.08em;&#xA;  text-transform: uppercase;&#xA;  color: var(--link-card-muted);&#xA;}&#xA;&#xA;.link-name {&#xA;  font-size: 12px;&#xA;  font-weight: 700;&#xA;  color: var(--text-color-primary);&#xA;  line-height: 1.3;&#xA;}&#xA;&#xA;.link-desc {&#xA;  font-size: 8px;&#xA;  color: var(--text-color-secondary);&#xA;  line-height: 1.45;&#xA;  display: -webkit-box;&#xA;  -webkit-line-clamp: 2;&#xA;  -webkit-box-orient: vertical;&#xA;  overflow: hidden;&#xA;}&#xA;&#xA;.link-arrow {&#xA;  align-self: center;&#xA;  font-size: 16px;&#xA;  line-height: 1;&#xA;  color: var(--text-color-tertiary);&#xA;  flex-shrink: 0;&#xA;  transition: transform 0.18s ease, color 0.18s ease;&#xA;}&#xA;&#xA;.link-card:hover .link-arrow,&#xA;.link-card:focus-visible .link-arrow {&#xA;  color: var(--link-color);&#xA;  transform: translate(2px, -2px);&#xA;}&#xA;&#xA;[data-theme=&#34;dark&#34;] .links-grid {&#xA;  --link-card-paper: #151a22;&#xA;  --link-card-muted: #9ba8b8;&#xA;  --link-card-shadow: 0 12px 24px rgba(0, 0, 0, 0.24);&#xA;}&#xA;&#xA;[data-theme=&#34;dark&#34;] .link-card:hover,&#xA;[data-theme=&#34;dark&#34;] .link-card:focus-visible {&#xA;  box-shadow: 0 16px 28px rgba(0, 0, 0, 0.32);&#xA;}&#xA;&#xA;[data-theme=&#34;dark&#34;] .link-avatar {&#xA;  background: linear-gradient(180deg, rgba(28, 36, 48, 0.92) 0%, rgba(22, 28, 38, 0.92) 100%);&#xA;}&#xA;&#xA;@media (prefers-color-scheme: dark) {&#xA;  :root:not([data-theme=&#34;light&#34;]) .links-grid {&#xA;    --link-card-paper: #151a22;&#xA;    --link-card-muted: #9ba8b8;&#xA;    --link-card-shadow: 0 12px 24px rgba(0, 0, 0, 0.24);&#xA;  }&#xA;&#xA;  :root:not([data-theme=&#34;light&#34;]) .link-card:hover,&#xA;  :root:not([data-theme=&#34;light&#34;]) .link-card:focus-visible {&#xA;    box-shadow: 0 16px 28px rgba(0, 0, 0, 0.32);&#xA;  }&#xA;&#xA;  :root:not([data-theme=&#34;light&#34;]) .link-avatar {&#xA;    background: linear-gradient(180deg, rgba(28, 36, 48, 0.92) 0%, rgba(22, 28, 38, 0.92) 100%);&#xA;  }&#xA;}&#xA;&#xA;@media (max-width: 860px) {&#xA;  .links-grid--reads,&#xA;  .links-grid--works,&#xA;  .links-grid--friends {&#xA;    grid-template-columns: repeat(2, minmax(0, 1fr));&#xA;  }&#xA;}&#xA;&#xA;@media (max-width: 640px) {&#xA;  .links-section {&#xA;    margin: 20px 0 24px;&#xA;  }&#xA;&#xA;  .links-grid,&#xA;  .links-grid--reads,&#xA;  .links-grid--works,&#xA;  .links-grid--friends {&#xA;    grid-template-columns: 1fr;&#xA;    gap: 10px;&#xA;  }&#xA;&#xA;  .link-card,&#xA;  .link-card:visited,&#xA;  .link-card:hover,&#xA;  .link-card:active {&#xA;    min-height: 32px;&#xA;    padding: 11px 12px 9px;&#xA;  }&#xA;&#xA;  .link-avatar {&#xA;    width: 36px;&#xA;    height: 36px;&#xA;    padding: 4px;&#xA;    border-radius: 11px;&#xA;  }&#xA;&#xA;  .link-arrow {&#xA;    display: none;&#xA;  }&#xA;}&#xA;&#xA;@media (prefers-reduced-motion: reduce) {&#xA;  .link-card,&#xA;  .link-avatar,&#xA;  .link-arrow {&#xA;    transition: none;&#xA;  }&#xA;&#xA;  .link-card:hover,&#xA;  .link-card:focus-visible,&#xA;  .link-card:hover .link-avatar,&#xA;  .link-card:focus-visible .link-avatar,&#xA;  .link-card:hover .link-arrow,&#xA;  .link-card:focus-visible .link-arrow {&#xA;    transform: none;&#xA;  }&#xA;}&#xA;&lt;/style&gt;&#xA;</description>
    </item>
    <item>
      <title>Resume</title>
      <link>https://blog.kmoon.fun/resume/</link>
      <pubDate>Fri, 05 Jun 2026 21:23:36 +0800</pubDate><author>hushan@kmoon.fun (Kmoon)</author>
      <guid>https://blog.kmoon.fun/resume/</guid>
      <description>&lt;p&gt;This page is a short landing page for my latest resume.&lt;/p&gt;&#xA;&lt;p&gt;You can view the full PDF version &lt;a href=&#34;https://blog.kmoon.fun/resume.pdf&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>About</title>
      <link>https://blog.kmoon.fun/about/</link>
      <pubDate>Fri, 05 Jun 2026 21:25:11 +0800</pubDate><author>hushan@kmoon.fun (Kmoon)</author>
      <guid>https://blog.kmoon.fun/about/</guid>
      <description>&lt;div class=&#34;solar-hero&#34;&gt;&#xA;  &lt;div class=&#34;solar-system&#34;&gt;&#xA;    &lt;div class=&#34;sun&#34;&gt;&lt;div class=&#34;star&#34;&gt;&lt;/div&gt;&lt;/div&gt;&#xA;    &lt;div class=&#34;mercury&#34;&gt;&lt;div class=&#34;planet&#34;&gt;&lt;div class=&#34;shadow&#34;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&#xA;    &lt;div class=&#34;venus&#34;&gt;&lt;div class=&#34;planet&#34;&gt;&lt;div class=&#34;shadow&#34;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&#xA;    &lt;div class=&#34;earth&#34;&gt;&lt;div class=&#34;planet&#34;&gt;&lt;div class=&#34;shadow&#34;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&#xA;    &lt;div class=&#34;mars&#34;&gt;&lt;div class=&#34;planet&#34;&gt;&lt;div class=&#34;shadow&#34;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&#xA;    &lt;div class=&#34;jupiter&#34;&gt;&lt;div class=&#34;planet&#34;&gt;&lt;div class=&#34;shadow&#34;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&#xA;    &lt;div class=&#34;avatar1&#34;&gt;&lt;div class=&#34;planet avatar-planet&#34; style=&#34;background-image:url(https://cdn.kmoon.fun/profile.jpeg)&#34;&gt;&lt;div class=&#34;shadow&#34;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&#xA;    &lt;div class=&#34;avatar2&#34;&gt;&lt;div class=&#34;planet avatar-planet&#34; style=&#34;background-image:url(https://cdn.kmoon.fun/2026/2026-06-13T06-02-53-930Z.png)&#34;&gt;&lt;div class=&#34;shadow&#34;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&#xA;  &lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;h3 id=&#34;hi-im-hushan&#34;&gt;Hi, I&amp;rsquo;m Hushan.&lt;/h3&gt;&#xA;&lt;p&gt;💻 a coder.&lt;/p&gt;&#xA;&lt;p&gt;2️⃣ 4️⃣ years old.&lt;/p&gt;&#xA;&lt;p&gt;MBTI: ESTJ（良好秩序乃万物之基）.&lt;/p&gt;&#xA;&lt;p&gt;Education: whut 👉 whut.&lt;/p&gt;&#xA;&lt;p&gt;Intern: &lt;img src=&#34;https://cdn.kmoon.fun/iflytek.svg&#34; width=&#34;36&#34; style=&#34;border:none;display:inline;vertical-align:middle;border-radius:0&#34; alt=&#34;iFlytek&#34;&gt; iFlytek 👉 &lt;img src=&#34;https://cdn.kmoon.fun/%E5%BF%AB%E6%89%8B.svg&#34; width=&#34;20&#34; height=&#34;20&#34; style=&#34;border:none;display:inline;vertical-align:middle;border-radius:0&#34; alt=&#34;Kuaishou&#34;&gt; Kuaishou 👉 &lt;img src=&#34;https://cdn.kmoon.fun/bytedance.svg&#34; width=&#34;20&#34; height=&#34;20&#34; style=&#34;border:none;display:inline;vertical-align:middle;border-radius:0&#34; alt=&#34;ByteDance&#34;&gt; ByteDance.&lt;/p&gt;&#xA;&lt;p&gt;Skills: Python、Java.&lt;/p&gt;&#xA;&lt;p&gt;Future: YouthTry.com&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>QUERY：全新的 HTTP 请求方法</title>
      <link>https://blog.kmoon.fun/query%E5%85%A8%E6%96%B0%E7%9A%84-http-%E8%AF%B7%E6%B1%82%E6%96%B9%E6%B3%95/</link>
      <pubDate>Fri, 26 Jun 2026 13:10:41 +0800</pubDate><author>hushan@kmoon.fun (Kmoon)</author>
      <guid>https://blog.kmoon.fun/query%E5%85%A8%E6%96%B0%E7%9A%84-http-%E8%AF%B7%E6%B1%82%E6%96%B9%E6%B3%95/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://kreya.app/blog/new-http-query-method-explained/&#34;&gt;The new HTTP QUERY method explained&lt;/a&gt;&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>不同 AI Coding Agent 对 Skills 的管理方式</title>
      <link>https://blog.kmoon.fun/%E4%B8%8D%E5%90%8C-ai-coding-agent-%E5%AF%B9-skills-%E7%9A%84%E7%AE%A1%E7%90%86%E6%96%B9%E5%BC%8F/</link>
      <pubDate>Mon, 22 Jun 2026 19:57:10 +0800</pubDate><author>hushan@kmoon.fun (Kmoon)</author>
      <guid>https://blog.kmoon.fun/%E4%B8%8D%E5%90%8C-ai-coding-agent-%E5%AF%B9-skills-%E7%9A%84%E7%AE%A1%E7%90%86%E6%96%B9%E5%BC%8F/</guid>
      <description>&lt;p&gt;前两天我在做一个工具，想统计一下自己每天到底调用了多少次 Claude Code 的 skill。&lt;/p&gt;&#xA;&lt;p&gt;听起来很简单对吧，就是做个上报，记录一下什么时候用了什么 skill，用了几次。但我刚开始写代码就懵了。&lt;/p&gt;&#xA;&lt;p&gt;Claude Code 的 skill 是本地 Markdown 文件，Cursor IDE 的 skill 藏在设置里的 JSON 配置，Codex CLI 的 skill 是 YAML 格式。我要适配所有 Coding Agent，却发现它们管理 skill 的方式完全是八套不同的逻辑。&lt;/p&gt;&#xA;&lt;p&gt;不是哥们，我就想记个日志，怎么各家差别能这么大？？？&lt;/p&gt;&#xA;&lt;p&gt;这件事让我意识到，如果你想做一个通用的 skill 调用上报工具，首先得搞清楚每家 Agent 在三个维度上的差异。&lt;/p&gt;&#xA;&lt;p&gt;存放路径在哪，怎么加载，以及最关键的，Hook 模型是什么样的。&lt;/p&gt;&#xA;&lt;p&gt;咱们一个个拆开了聊。&lt;/p&gt;&#xA;&lt;p&gt;先从 CLI 工具说起。&lt;/p&gt;&#xA;&lt;p&gt;Claude Code 是最直白的。它就放在项目目录下的 &lt;code&gt;.claude/skills/&lt;/code&gt; 文件夹里，每个 skill 是一个子文件夹，里面必须有一个 &lt;code&gt;skill.md&lt;/code&gt; 文件。&lt;/p&gt;&#xA;&lt;p&gt;这种设计的好处是，skill 就是项目代码的一部分。你把项目仓库 clone 下来，skill 跟着一起下来了，完全不需要额外安装。而且因为就在文件系统里，你想做监控很容易，用文件系统监听或者直接读目录结构都行。&lt;/p&gt;&#xA;&lt;p&gt;我跟你说，我做上报工具的时候，Claude Code 这块儿是最省心的。直接遍历 &lt;code&gt;.claude/skills/&lt;/code&gt; 目录，解析每个子文件夹里的 &lt;code&gt;skill.md&lt;/code&gt;，提取 frontmatter 里的 name 和 description，一个 &lt;code&gt;os.walk&lt;/code&gt; 就搞定了。&lt;/p&gt;&#xA;&lt;p&gt;Codex CLI 是 OpenAI 出的官方 Coding Agent，它的 skill 系统叫 Commands，配置放在 &lt;code&gt;.codex/commands/&lt;/code&gt; 目录下，每个 command 是一个 YAML 文件。&lt;/p&gt;&#xA;&lt;p&gt;Codex 也支持全局和项目级配置，全局的在 &lt;code&gt;~/.codex/commands/&lt;/code&gt;。Codex 的设计介于 Claude Code 和 Cursor 之间，它用 YAML 而不是 Markdown，保留了一些可读性，同时保持了结构化的优势。每个 command 可以定义参数、描述、还有可选的 hooks，比如在代码提交前自动执行。&lt;/p&gt;&#xA;&lt;p&gt;然后是 Trae CLI，也叫 CoCo，字节出的命令行工具。&lt;/p&gt;&#xA;&lt;p&gt;CoCo 的 skill 配置放在 &lt;code&gt;.coco/skills/&lt;/code&gt; 目录，格式是 TOML。TOML 比 JSON 友好，比 YAML 简单，CoCo 选择这个格式是有考量的。而且 CoCo 支持 skill 市场，你可以从远程仓库拉取别人分享的 skill，本地只是一个缓存。&lt;/p&gt;&#xA;&lt;p&gt;这种设计给上报带来了复杂性，因为 skill 可能来自远程，本地文件只是一个副本，版本可能随时变化。&lt;/p&gt;&#xA;&lt;p&gt;接下来是 Gemini CLI，Google 的命令行工具。&lt;/p&gt;&#xA;&lt;p&gt;Gemini CLI 的 skill 系统叫 Code Actions，配置方式很特别，它不是本地文件，而是 Google Cloud 上的资源。你在本地项目里看不到任何 skill 配置文件，所有的 skill 都定义在 Cloud Console 里，通过项目 ID 关联。&lt;/p&gt;&#xA;&lt;p&gt;这种云原生的设计意味着，做上报工具的时候，你必须调用 Google Cloud API 才能获取 skill 列表，本地文件系统帮不上忙。&lt;/p&gt;&#xA;&lt;p&gt;好，CLI 说完了，聊聊 IDE。&lt;/p&gt;&#xA;&lt;p&gt;Cursor IDE 也有 skill 系统，虽然它也在推 MCP，但 Cursor 本身有一套原生的 skill 配置。它的 skill 分为两类，一类是全局 skill，一类是项目级 skill。&lt;/p&gt;&#xA;&lt;p&gt;全局 skill 的配置存在 &lt;code&gt;~/.cursor/settings.json&lt;/code&gt; 里。项目级 skill 配置在项目根目录的 &lt;code&gt;.cursor/skills.json&lt;/code&gt; 里。&lt;/p&gt;&#xA;&lt;p&gt;注意，Cursor 的 skill 配置是纯 JSON，不像 Claude Code 是 Markdown。每个 skill 有一个 name、description、prompt，还可以定义什么时候触发。这种结构化的好处是解析简单，坏处是可读性差，写 prompt 的时候不能换行、不能用 Markdown 格式，一长串文本挤在 JSON 字符串里，看着头大。&lt;/p&gt;&#xA;&lt;p&gt;Trae IDE 是字节出的桌面端，它的 skill 系统叫智能体，配置放在 &lt;code&gt;.trae/agents/&lt;/code&gt; 目录下。每个智能体是一个 JSON 文件，但 Trae 的创新点是支持多轮对话模板，你可以定义一个完整的对话流程，而不只是一个静态 prompt。&lt;/p&gt;&#xA;&lt;p&gt;这种设计让 skill 更像是一个剧本，AI 按照预设的步骤和用户交互。对于我的上报工具来说，这意味着我需要解析更复杂的结构，因为每个 skill 可能包含多个步骤的触发点。&lt;/p&gt;&#xA;&lt;p&gt;说到 OpenCode，开源社区孵化的 Coding Agent。&lt;/p&gt;&#xA;&lt;p&gt;OpenCode 的 skill 系统是最激进的，它完全照搬了 Claude Code 的设计，放在 &lt;code&gt;.opencode/skills/&lt;/code&gt; 目录，也是 Markdown 格式。但它加了一个功能叫 skill 继承，一个项目可以继承另一个项目的 skill，形成层级结构。&lt;/p&gt;&#xA;&lt;p&gt;这意味着 skill 的来源不只是当前项目，可能还有父项目、全局配置。做上报的时候，你得递归解析整个继承链，才能知道最终有哪些 skill 可用。&lt;/p&gt;&#xA;&lt;p&gt;然后是 OpenClaw，飞书出的 Coding Agent。&lt;/p&gt;&#xA;&lt;p&gt;OpenClaw 的 skill 配置放在 &lt;code&gt;.openclaw/skills/&lt;/code&gt; 目录，格式是 JSON。但 OpenClaw 的特殊之处在于它和飞书生态深度绑定，skill 可以通过飞书多维表格来管理，本地文件只是同步下来的缓存。&lt;/p&gt;&#xA;&lt;p&gt;这种设计对上报工具很不友好，因为 skill 的真相在云端，本地文件可能过期，也可能被手动修改后还没同步。&lt;/p&gt;&#xA;&lt;p&gt;说到这儿，你可能会发现一个问题。&lt;/p&gt;&#xA;&lt;p&gt;CLI 和 IDE 在 skill 存放路径上有个本质区别。CLI 工具基本都是项目级配置，skill 文件就在项目里，跟着代码走。IDE 则既有全局配置又有项目级配置，而且往往把配置藏在用户目录或者云端。&lt;/p&gt;&#xA;&lt;p&gt;这个区别对上报工具的影响很大。CLI 工具的上报可以基于文件系统监听，IDE 的上报则需要同时监控多个位置，还要处理合并逻辑。&lt;/p&gt;&#xA;&lt;p&gt;好，路径聊完了，说说加载方式。&lt;/p&gt;&#xA;&lt;p&gt;这块儿才是真正考验适配难度的地方。&lt;/p&gt;&#xA;&lt;p&gt;Claude Code 的加载方式是静态扫描加热重载。启动的时候，它会递归扫描 &lt;code&gt;.claude/skills/&lt;/code&gt; 目录，读取每个 &lt;code&gt;skill.md&lt;/code&gt; 文件，解析 YAML frontmatter 和正文内容，然后把这些 skill 注册到内存里。而且支持热重载，你修改了 skill 文件，保存后立刻生效，不需要重启。&lt;/p&gt;&#xA;&lt;p&gt;对于我的上报工具来说，这意味着我需要监听文件系统变化，持续更新 skill 列表。&lt;/p&gt;&#xA;&lt;p&gt;Codex CLI 的加载也是静态扫描加热重载，和 Claude Code 类似。但它多了一个条件加载，支持在 command 里定义 when 条件，比如当文件是 Python 时才显示这个 command。这意味着即使扫描到了 skill，也不一定对所有文件都可用。&lt;/p&gt;&#xA;&lt;p&gt;CoCo 的加载需要区分本地 skill 和远程 skill。本地的是静态扫描，远程的需要调用 API 获取列表，还要处理版本缓存。如果网络不好，CoCo 会回退到本地缓存，这时候上报的数据可能不准确。&lt;/p&gt;&#xA;&lt;p&gt;Gemini CLI 的加载完全依赖网络，启动时调用 Google Cloud API 获取项目的 Code Actions。如果网络不通，Gemini 就完全没有 skill 可用。这种设计对上报工具来说，意味着必须处理各种网络异常。&lt;/p&gt;&#xA;&lt;p&gt;说到 IDE 的加载方式。&lt;/p&gt;&#xA;&lt;p&gt;Cursor IDE 的加载方式是静态扫描，但它不支持热重载。你修改了 &lt;code&gt;.cursor/skills.json&lt;/code&gt;，需要重启 Cursor 才能生效。而且全局 skill 和项目级 skill 是合并加载的，如果有同名 skill，项目级的会覆盖全局的。&lt;/p&gt;&#xA;&lt;p&gt;这种合并逻辑给上报带来了麻烦，因为你得知道最终生效的是哪个 skill。我的方案是启动时读取全局配置，然后读取项目配置，自己做合并逻辑，和 Cursor 保持一致。&lt;/p&gt;&#xA;&lt;p&gt;Trae IDE 的加载方式更复杂，因为它支持动态智能体。除了启动时扫描 &lt;code&gt;.trae/agents/&lt;/code&gt;，Trae 还可以在对话过程中动态加载新的智能体，基于上下文判断用户需要什么能力。这种动态加载给上报带来了挑战，因为 skill 列表不是固定的。&lt;/p&gt;&#xA;&lt;p&gt;OpenCode 的加载最复杂，因为要处理 skill 继承链。它需要先加载全局 skill，然后加载父项目的 skill，最后加载当前项目的 skill，每一层都可能覆盖上一层的同名 skill。这个过程是递归的，如果项目嵌套很深，加载时间会很长。&lt;/p&gt;&#xA;&lt;p&gt;OpenClaw 的加载需要同步飞书云端。启动时会检查本地缓存和云端的版本，如果有更新就下载。这意味着 skill 列表可能随时变化，上报工具需要持续监听同步事件。&lt;/p&gt;&#xA;&lt;p&gt;说到加载，必须提一嘴 skill 的概念。&lt;/p&gt;&#xA;&lt;p&gt;Claude Code 支持子 skill，你可以在一个 skill 文件夹里放多个子文件夹，每个子文件夹是一个子 skill。比如 &lt;code&gt;adk-sdd/&lt;/code&gt; 下面有 &lt;code&gt;adk-sdd-plan/&lt;/code&gt;、&lt;code&gt;adk-sdd-implement/&lt;/code&gt; 等。它们之间可以互相调用，形成一个完整的工具链。&lt;/p&gt;&#xA;&lt;p&gt;这种层级结构给上报带来了额外复杂度，因为你得递归扫描子目录，而且子 skill 的调用关系也得记录。&lt;/p&gt;&#xA;&lt;p&gt;OpenCode 也支持类似的层级结构，而且它还有 skill 继承，复杂度更高。其他 Agent 像 Cursor、Trae、Codex、CoCo 都不支持子 skill，是扁平结构。&lt;/p&gt;&#xA;&lt;p&gt;好，路径和加载都说完了，最后聊聊 Hook 模型。&lt;/p&gt;&#xA;&lt;p&gt;这是各家差异最大的部分，也是我做上报工具时最纠结的地方。&lt;/p&gt;&#xA;&lt;p&gt;Claude Code 的 Hook 模型，我总结为被动触发加语义匹配。你不需要显式调用 skill，Claude Code 会根据对话内容自动判断，把 skill 的 description 和 user message 做语义匹配，超过阈值就注入 prompt。&lt;/p&gt;&#xA;&lt;p&gt;这种模型的优点是交互自然，缺点是可控性差。做上报的时候，Claude Code 没有官方 Hook 点，我只能通过解析 &lt;code&gt;.claude/logs/&lt;/code&gt; 目录下的日志来间接推断 skill 是否被激活。&lt;/p&gt;&#xA;&lt;p&gt;Codex CLI 的 Hook 模型是命令式加事件式结合。Commands 可以显式调用，也可以通过定义的 hooks 在特定事件触发，比如 onSave、onCommit。做上报的时候，你需要同时监控用户命令和编辑器事件。&lt;/p&gt;&#xA;&lt;p&gt;CoCo 的 Hook 模型是关键词触发加场景识别，除了匹配关键词，CoCo 还会分析当前编辑场景，比如你在写测试，它就自动推荐测试相关的 skill。这种模型需要上报工具理解场景是怎么定义的。&lt;/p&gt;&#xA;&lt;p&gt;Gemini CLI 的 Hook 模型完全是黑盒，因为 skill 在云端，触发逻辑也由服务端控制。本地只能看到最终的 AI 回复，看不到中间过程。做上报基本不可能，除非 Google 开放 API。&lt;/p&gt;&#xA;&lt;p&gt;说到 IDE 的 Hook 模型。&lt;/p&gt;&#xA;&lt;p&gt;Cursor IDE 的 Hook 模型是混合触发，可以通过 &lt;code&gt;/skill-name&lt;/code&gt; 显式调用，也可以让 AI 自动判断。显式调用容易监控，自动判断就需要解析日志。&lt;/p&gt;&#xA;&lt;p&gt;Trae IDE 的 Hook 模型是剧本驱动，因为支持多轮对话模板，一个 skill 可能在对话的不同阶段多次触发。比如第一步询问需求，第二步生成代码，第三步解释代码。每个步骤都是一个 Hook 点，上报工具需要追踪整个对话流程。&lt;/p&gt;&#xA;&lt;p&gt;OpenCode 的 Hook 模型和 Claude Code 类似，也是被动触发。但由于有 skill 继承，触发的时候可能同时激活了父项目和子项目的 skill，上报工具需要记录这个层级关系。&lt;/p&gt;&#xA;&lt;p&gt;OpenClaw 的 Hook 模型是意图识别加工作流，它会先识别用户意图，然后触发对应的工作流。工作流可能包含多个 skill 的串联调用，上报的时候你需要记录整个调用链。&lt;/p&gt;&#xA;&lt;p&gt;说了这么多，我来帮你理一理这八家 Agent 的差异。&lt;/p&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;Agent&lt;/th&gt;&#xA;          &lt;th&gt;类型&lt;/th&gt;&#xA;          &lt;th&gt;路径&lt;/th&gt;&#xA;          &lt;th&gt;格式&lt;/th&gt;&#xA;          &lt;th&gt;加载方式&lt;/th&gt;&#xA;          &lt;th&gt;Hook 模型&lt;/th&gt;&#xA;          &lt;th&gt;上报难度&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Claude Code&lt;/td&gt;&#xA;          &lt;td&gt;CLI&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;.claude/skills/&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;Markdown&lt;/td&gt;&#xA;          &lt;td&gt;静态扫描加热重载&lt;/td&gt;&#xA;          &lt;td&gt;被动触发&lt;/td&gt;&#xA;          &lt;td&gt;中等&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Codex CLI&lt;/td&gt;&#xA;          &lt;td&gt;CLI&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;.codex/commands/&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;YAML&lt;/td&gt;&#xA;          &lt;td&gt;静态加热重载加条件&lt;/td&gt;&#xA;          &lt;td&gt;命令加事件&lt;/td&gt;&#xA;          &lt;td&gt;中等&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;CoCo&lt;/td&gt;&#xA;          &lt;td&gt;CLI&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;.coco/skills/&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;TOML&lt;/td&gt;&#xA;          &lt;td&gt;静态加远程&lt;/td&gt;&#xA;          &lt;td&gt;关键词加场景&lt;/td&gt;&#xA;          &lt;td&gt;高&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Gemini CLI&lt;/td&gt;&#xA;          &lt;td&gt;CLI&lt;/td&gt;&#xA;          &lt;td&gt;Cloud Console&lt;/td&gt;&#xA;          &lt;td&gt;-&lt;/td&gt;&#xA;          &lt;td&gt;API 获取&lt;/td&gt;&#xA;          &lt;td&gt;黑盒&lt;/td&gt;&#xA;          &lt;td&gt;不可能&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Cursor IDE&lt;/td&gt;&#xA;          &lt;td&gt;IDE&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;~/.cursor/settings.json&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;JSON&lt;/td&gt;&#xA;          &lt;td&gt;静态扫描&lt;/td&gt;&#xA;          &lt;td&gt;混合触发&lt;/td&gt;&#xA;          &lt;td&gt;中等偏高&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Trae IDE&lt;/td&gt;&#xA;          &lt;td&gt;IDE&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;.trae/agents/&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;JSON&lt;/td&gt;&#xA;          &lt;td&gt;静态加动态&lt;/td&gt;&#xA;          &lt;td&gt;剧本驱动&lt;/td&gt;&#xA;          &lt;td&gt;高&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;OpenCode&lt;/td&gt;&#xA;          &lt;td&gt;IDE&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;.opencode/skills/&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;Markdown&lt;/td&gt;&#xA;          &lt;td&gt;继承链加载&lt;/td&gt;&#xA;          &lt;td&gt;被动触发&lt;/td&gt;&#xA;          &lt;td&gt;中等偏高&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;OpenClaw&lt;/td&gt;&#xA;          &lt;td&gt;IDE&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;.openclaw/skills/&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;JSON&lt;/td&gt;&#xA;          &lt;td&gt;云端同步&lt;/td&gt;&#xA;          &lt;td&gt;意图加工作流&lt;/td&gt;&#xA;          &lt;td&gt;很高&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;从这张表你能看出什么？&lt;/p&gt;&#xA;&lt;p&gt;首先，CLI 和 IDE 泾渭分明。CLI 工具普遍使用项目级配置，格式多样，Markdown、YAML、TOML 都有。IDE 则倾向于 JSON 配置，而且普遍有全局加项目级的双层结构。&lt;/p&gt;&#xA;&lt;p&gt;其次，云原生是趋势。CoCo、Gemini CLI、OpenClaw 都不同程度地依赖云端，本地只是一个视图或缓存。这对上报工具提出了新要求，不能只盯着文件系统，还得调 API、处理网络异常。&lt;/p&gt;&#xA;&lt;p&gt;最后，Hook 模型越来越复杂。从最简单的显式调用，到被动触发，再到剧本驱动、意图识别，Agent 越来越智能，但也越来越不透明。上报工具能拿到的信息越来越少，很多都是黑盒。&lt;/p&gt;&#xA;&lt;p&gt;说真的，写到这儿，我突然意识到一个问题。&lt;/p&gt;&#xA;&lt;p&gt;为什么各家在 skill 管理上差异这么大？&lt;/p&gt;&#xA;&lt;p&gt;背后其实是产品哲学的不同，CLI 和 IDE 的目标用户不一样，设计思路自然也不同。&lt;/p&gt;&#xA;&lt;p&gt;Claude Code 和 OpenCode 相信文件即真理。skill 就应该像代码一样，放在版本控制里，任何人都能看、能改、能复现。这种哲学决定了本地优先、透明可见的设计。&lt;/p&gt;&#xA;&lt;p&gt;Codex CLI 相信配置的标准化。YAML 比 Markdown 结构化，比 JSON 可读性好，是工程化团队的首选。&lt;/p&gt;&#xA;&lt;p&gt;CoCo 相信生态的力量。skill 不应该绑定在本地，而应该可以分享、可以订阅、可以版本管理。这种设计牺牲了离线可用性，换来了社区活力。&lt;/p&gt;&#xA;&lt;p&gt;Gemini CLI 相信云服务的整合。skill 是 Google Cloud 生态的一部分，用户不需要关心配置，只需要用。&lt;/p&gt;&#xA;&lt;p&gt;Cursor IDE 和 Trae IDE 相信配置的灵活性。JSON 虽然难写，但好解析，适合图形化配置界面。而且全局加项目级的双层结构，满足了个人习惯和团队协作的不同需求。&lt;/p&gt;&#xA;&lt;p&gt;OpenClaw 相信飞书生态的协同。skill 可以通过多维表格管理，非技术人员也能参与配置。&lt;/p&gt;&#xA;&lt;p&gt;这八种哲学没有对错，只是取舍不同。&lt;/p&gt;&#xA;&lt;p&gt;但对于我这种想做通用上报工具的人来说，这就很痛苦了。因为没有标准，每家都有自己的玩法，你得为每家写一套适配代码。&lt;/p&gt;&#xA;&lt;p&gt;我有时候觉得，AI Coding Agent 的发展，就像早期的浏览器大战。Netscape 和 IE 各有各的 DOM API，开发者苦不堪言。直到 W3C 标准化之后才好转。&lt;/p&gt;&#xA;&lt;p&gt;skill 管理目前还没有统一标准，Markdown、JSON、YAML、TOML 混用，触发模型也五花八门。&lt;/p&gt;&#xA;&lt;p&gt;短期内，这种碎片化还会继续。&lt;/p&gt;&#xA;&lt;p&gt;写到这儿，我突然想起我做上报工具的初衷。&lt;/p&gt;&#xA;&lt;p&gt;我其实只是想知道自己每天用了多少次 skill，哪些 skill 最有用，哪些可能可以删掉。一个简单的数据分析需求，却因为底层差异变得异常复杂。&lt;/p&gt;&#xA;&lt;p&gt;但换个角度想，这种复杂度本身，就是 AI 工具现状的真实写照。&lt;/p&gt;&#xA;&lt;p&gt;我们还在早期，还在探索，还在争吵什么是最好的方案。这种混乱是创新的代价，也是进化的必经之路。&lt;/p&gt;&#xA;&lt;p&gt;或许几年后回头看，今天的这些差异都会显得幼稚。但在当下，我们必须面对它们，理解它们，在碎片中寻找规律。&lt;/p&gt;&#xA;&lt;p&gt;这就是我这几天做适配的最大感受。&lt;/p&gt;&#xA;&lt;p&gt;无论你用 Claude Code、Cursor、Trae 还是 Codex，skill 管理的本质问题是一样的，怎么让 AI 学会新能力，怎么让它在合适的时机调用这些能力，怎么让这一切对开发者透明、可控。&lt;/p&gt;&#xA;&lt;p&gt;每家产品都有自己的答案，而我在这些答案之间，试图搭一座桥。&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>词根词缀记忆法</title>
      <link>https://blog.kmoon.fun/essay/%E8%AF%8D%E6%A0%B9%E8%AF%8D%E7%BC%80%E8%AE%B0%E5%BF%86%E6%B3%95/</link>
      <pubDate>Sun, 21 Jun 2026 18:24:06 +0800</pubDate><author>hushan@kmoon.fun (Kmoon)</author>
      <guid>https://blog.kmoon.fun/essay/%E8%AF%8D%E6%A0%B9%E8%AF%8D%E7%BC%80%E8%AE%B0%E5%BF%86%E6%B3%95/</guid>
      <description>&lt;p&gt;故事是这样的。&lt;/p&gt;&#xA;&lt;p&gt;我最近刷 B 站的时候，被推荐了一个讲背单词方法的视频。本来只是想随便看看，结果那个 UP 主讲了一个观点，直接给我干懵了。&lt;/p&gt;&#xA;&lt;p&gt;他说，你以为英语单词是 26 个字母随机组合的吗？&lt;/p&gt;&#xA;&lt;p&gt;不是的。绝大多数单词，其实都是「零件组装」出来的。&lt;/p&gt;&#xA;&lt;p&gt;我当时就愣住了。&lt;/p&gt;&#xA;&lt;p&gt;因为我突然意识到，我背了十几年单词，从来没有想过这个问题。我就是那种典型的「abandon 型选手」，从 A 开始背，背到 C 放弃，过两个月再从 A 开始，循环往复，永无止境。&lt;/p&gt;&#xA;&lt;p&gt;那个视频说，英语单词就像乐高积木，由三个部分组成：前缀 + 词根 + 后缀。掌握一套「零件」，就能批量解锁几十个甚至上百个单词。&lt;/p&gt;&#xA;&lt;p&gt;这感觉，就像你千辛万苦爬上喜马拉雅山顶，想求见传说中的武林宗师，结果宗师摸着胡子告诉你，背单词的终极秘籍，就八个字：&lt;strong&gt;拆开来看，组装着记。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;说实话，我一开始是不信的。这听起来太像那种「七天记住一万词」的智商税广告了。&lt;/p&gt;&#xA;&lt;p&gt;但我反正这段时间也没啥事，就决定，亲自下场验证一下。&lt;/p&gt;&#xA;&lt;h2 id=&#34;词典无法定义语言&#34;&gt;词典无法定义语言&lt;/h2&gt;&#xA;&lt;p&gt;在讲词根词缀之前，我想先聊一个让我后劲很大的发现。&lt;/p&gt;&#xA;&lt;p&gt;我在查资料的时候，找到了一个叫 &lt;a href=&#34;https://www.etymonline.com/&#34;&gt;Online Etymonline Dictionary&lt;/a&gt; 的网站，专门查英语单词的词源。网站的介绍页里，引用了博尔赫斯的一句话。&lt;/p&gt;&#xA;&lt;p&gt;博尔赫斯你知道吧，就是那个写《小径分岔的花园》的阿根廷老头，一辈子痴迷迷宫、图书馆、词典这些东西。&lt;/p&gt;&#xA;&lt;p&gt;他在这本诗集的序言里写：&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;人们常常忽略一件事：词典本是人为搭建的文字库房，在其所记述的语言诞生许久之后才编纂而成。语言的本源毫无理性可循，自带一种奇幻玄妙的特质。&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;翻译成人话就是：词典是后加的说明书，而语言本身，是一种魔法。&lt;/p&gt;&#xA;&lt;p&gt;我当时看到这段话，真的被震撼到了。&lt;/p&gt;&#xA;&lt;p&gt;因为我们从小到大接受的教育，都在告诉我们「词典是最权威的」「查字典才能知道正确答案」。但博尔赫斯说，不对，词典只是人工的归档系统，真正的语言，比词典古老得多，也混沌得多。&lt;/p&gt;&#xA;&lt;p&gt;这让我想到，背单词这件事，可能从一开始我们就搞错了方向。&lt;/p&gt;&#xA;&lt;p&gt;我们不是在学习一套「已经被定义好的规则」，我们是在试图理解一种「活了几千年的混沌魔法」。&lt;/p&gt;&#xA;&lt;p&gt;这个想法一旦打开，后面的很多东西，突然就串起来了。&lt;/p&gt;&#xA;&lt;h2 id=&#34;英语的两层皮肤&#34;&gt;英语的两层皮肤&lt;/h2&gt;&#xA;&lt;p&gt;验证词根词缀的过程中，我发现了一个特别有意思的现象。&lt;/p&gt;&#xA;&lt;p&gt;英语其实有两层「皮肤」。&lt;/p&gt;&#xA;&lt;p&gt;底层是古英语，也叫本土日耳曼词。这是公元 5 世纪盎格鲁-撒克逊人带来的，是英语最原生的那部分。它们的特点是：短、简单、日常必备。&lt;/p&gt;&#xA;&lt;p&gt;比如这些词：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;fire、water、sun、moon&lt;/li&gt;&#xA;&lt;li&gt;head、hand、eye、heart&lt;/li&gt;&#xA;&lt;li&gt;father、mother、brother、sister&lt;/li&gt;&#xA;&lt;li&gt;good、bad、big、small&lt;/li&gt;&#xA;&lt;li&gt;I、you、he、she、it&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;这些词你根本不用「记」，你早就认识了。它们就扎根在你的本能里。&lt;/p&gt;&#xA;&lt;p&gt;但英语还有另一层皮肤，是外来词。&lt;/p&gt;&#xA;&lt;p&gt;占现代英语一半以上的词汇，其实来源于拉丁语、法语、希腊语。它们的特点是：长、正式、显得高级。&lt;/p&gt;&#xA;&lt;p&gt;而且最骚的是，很多概念，英语里有两套表达。&lt;/p&gt;&#xA;&lt;p&gt;一套是本土的「土话版」，一套是外来的「高级版」：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;ask（本土）👉 inquire（拉丁）&lt;/li&gt;&#xA;&lt;li&gt;help（本土）👉 assist（拉丁）&lt;/li&gt;&#xA;&lt;li&gt;kingly（本土）👉 royal（法语）&lt;/li&gt;&#xA;&lt;li&gt;buy（本土）👉 purchase（拉丁）&lt;/li&gt;&#xA;&lt;li&gt;end（本土）👉 terminate（拉丁）&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;你发现规律了吗？&lt;/p&gt;&#xA;&lt;p&gt;本土词短，外来词长。本土词口语，外来词书面。本土词日常，外来词正式。&lt;/p&gt;&#xA;&lt;p&gt;这让我突然理解了一件事：为什么有时候读英文论文或合同，明明每个单词都认识，放在一起就是看不懂。&lt;/p&gt;&#xA;&lt;p&gt;因为它们用的全是那套「高级皮肤」。&lt;/p&gt;&#xA;&lt;p&gt;所以背单词的第一个心法就是：&lt;strong&gt;先分清这是哪层皮肤。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;如果是 1-2 个音节的短词，大概率是日耳曼本土词，直接背，图像记忆，看到 fire 就想象火苗🔥，不要先翻译成「火」。&lt;/p&gt;&#xA;&lt;p&gt;如果是 3 个音节以上的「学术感」词汇，那它很可能是拉丁或希腊血统，这时候，词根词缀法就派上用场了。&lt;/p&gt;&#xA;&lt;h2 id=&#34;词根词缀的拆解游戏&#34;&gt;词根词缀的拆解游戏&lt;/h2&gt;&#xA;&lt;p&gt;好，现在进入正题。&lt;/p&gt;&#xA;&lt;p&gt;词根词缀法，说白了，就是把长单词当成乐高来拆。&lt;/p&gt;&#xA;&lt;p&gt;我举个例子。&lt;/p&gt;&#xA;&lt;p&gt;port 这个词根，来自拉丁语 portare，意思是「搬运、携带」。&lt;/p&gt;&#xA;&lt;p&gt;掌握这一个词根，你能解锁多少单词？&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;port&lt;/strong&gt; = 港口（搬运货物的地方）&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;transport&lt;/strong&gt; = 运输（trans- 跨越 + port 搬运 = 从这边搬到那边）&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;export&lt;/strong&gt; = 出口（ex- 向外 + port 搬运 = 向外搬）&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;import&lt;/strong&gt; = 进口（im- 向内 + port 搬运 = 向内搬）&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;portable&lt;/strong&gt; = 便携的（port 搬运 + -able 能够 = 能够搬运的）&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;porter&lt;/strong&gt; = 搬运工（port 搬运 + -er 人 = 搬运的人）&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;你看，记住一个 port，等于记住了 6 个词，而且它们的逻辑是通的。&lt;/p&gt;&#xA;&lt;p&gt;这就是词根词缀的威力：&lt;strong&gt;不用死背单个单词，掌握一套部件，批量解锁。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;我自己试了一段时间，坦白讲，一开始是有点痛苦的。&lt;/p&gt;&#xA;&lt;p&gt;因为你需要先去学那些词根，这本身就是一笔前置投入。而且有些词根的变形很多，port 有时候变成 port，有时候变成 part（partition），有时候变成 portion，你得慢慢熟悉它们的「变体规律」。&lt;/p&gt;&#xA;&lt;p&gt;但坚持大概两三周之后，突然有一个时刻，我感觉自己「开了天眼」。&lt;/p&gt;&#xA;&lt;p&gt;看一个长单词，不再是一串随机的字母组合，而是能看到它的结构。看到 introduce，脑子里会自动拆分：intro-（向内）+ duc（引导）+ e = 引导进来 = 介绍。&lt;/p&gt;&#xA;&lt;p&gt;这种感觉太爽了。&lt;/p&gt;&#xA;&lt;h2 id=&#34;最常用的几套零件&#34;&gt;最常用的几套零件&lt;/h2&gt;&#xA;&lt;p&gt;如果你也想试试这个方法，我整理了一些最基础的「零件库」，你可以从这几套开始。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;最常用的 50 个词根：&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;vis/vid（看）：visible、vision、television、revise、supervise&#xA;dict（说）：dictionary、predict、contradict、dictate&#xA;spect（看）：inspect、prospect、respect、suspect、aspect&#xA;mit/miss（派送）：mission、emit、submit、transmit、dismiss&#xA;struct（建造）：structure、construct、destroy、instruct&#xA;duc/duct（引导）：educate、introduce、conduct、produce&#xA;cred（相信）：credit、credible、incredible&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;最常用的前缀（改变词义）：&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;un-/in-/im-（不）：unhappy、impossible、incorrect&#xA;re-（再/回）：return、review、repeat、refresh&#xA;ex-/e-（向外）：exit、export、expand、emit&#xA;pre-（在前）：preview、prepare、predict&#xA;pro-（向前）：progress、proceed、promote&#xA;de-（向下/否定）：decrease、destroy、decode&#xA;inter-（之间）：internet、interview、international&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;最常用的后缀（改变词性）：&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;-tion/-sion（名词）：education、information、decision&#xA;-ment（名词）：development、movement、achievement&#xA;-able/-ible（形容词）：comfortable、terrible、visible&#xA;-ful（形容词）：beautiful、helpful、successful&#xA;-ly（副词）：quickly、slowly、carefully&#xA;-er/-or（人）：teacher、actor、driver&lt;/p&gt;&#xA;&lt;p&gt;这些不是要你一天背完。我自己的做法是，每次遇到一个新单词，就顺手查一下它的词源，看看能不能拆解。&lt;/p&gt;&#xA;&lt;p&gt;积少成多，慢慢地，你的「零件库」就越来越丰富了。&lt;/p&gt;&#xA;&lt;h2 id=&#34;博尔赫斯的迷宫&#34;&gt;博尔赫斯的迷宫&lt;/h2&gt;&#xA;&lt;p&gt;写到这，我突然想起博尔赫斯的另一篇小说，《巴别图书馆》。&lt;/p&gt;&#xA;&lt;p&gt;那个故事里，宇宙就是一个无限延伸的图书馆，里面收藏着所有可能的书籍，包含一切可能的字母组合。但问题是，绝大多数书都是毫无意义的乱码。&lt;/p&gt;&#xA;&lt;p&gt;背单词，其实就像在这个图书馆里找路。&lt;/p&gt;&#xA;&lt;p&gt;如果你把每个单词当成独立的乱码去记，那你就是在无限的迷宫里盲走，永远走不出去。&lt;/p&gt;&#xA;&lt;p&gt;但词根词缀，就像是图书馆的索引系统。它不能告诉你全部，但至少能给你一个方向，让你知道这个词从哪来，大概是什么意思。&lt;/p&gt;&#xA;&lt;p&gt;词典无法定义语言，但它可以帮助我们，在这片混沌的魔法森林里，找到一点点秩序。&lt;/p&gt;&#xA;&lt;p&gt;说到底，学习语言不是为了背单词，而是为了理解。理解另一种思维方式，理解另一种看待世界的角度。&lt;/p&gt;&#xA;&lt;p&gt;这个词根词缀的方法，我不能保证对每个人都有用。我自己也还在摸索，也还在踩坑。&lt;/p&gt;&#xA;&lt;p&gt;但如果你和我一样，曾经被困在 abandon 的循环里，不妨试试这个思路。&lt;/p&gt;&#xA;&lt;p&gt;拆开来看，组装着记。&lt;/p&gt;&#xA;&lt;p&gt;也许你会发现，那些看似杂乱无章的字母组合，背后其实藏着一条隐秘的路径。&lt;/p&gt;&#xA;&lt;p&gt;顺着它走，也许就能走出这座迷宫。&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>一文讲清 RAG 效果评测 101</title>
      <link>https://blog.kmoon.fun/%E4%B8%80%E6%96%87%E8%AE%B2%E6%B8%85-rag-%E6%95%88%E6%9E%9C%E8%AF%84%E6%B5%8B-101/</link>
      <pubDate>Sat, 20 Jun 2026 20:26:53 +0800</pubDate><author>hushan@kmoon.fun (Kmoon)</author>
      <guid>https://blog.kmoon.fun/%E4%B8%80%E6%96%87%E8%AE%B2%E6%B8%85-rag-%E6%95%88%E6%9E%9C%E8%AF%84%E6%B5%8B-101/</guid>
      <description>&lt;h2 id=&#34;评估阶段&#34;&gt;评估阶段&lt;/h2&gt;&#xA;&lt;p&gt;针对 RAG 的评估主要分为两个阶段的评估：检索阶段、生成阶段。其中检索阶段需要评估召回的文档的相关性，生成阶段需要评估模型生成的内容的正确性。&lt;/p&gt;&#xA;&lt;h3 id=&#34;检索阶段&#34;&gt;检索阶段&lt;/h3&gt;&#xA;&lt;h3 id=&#34;生成阶段&#34;&gt;生成阶段&lt;/h3&gt;&#xA;&lt;h2 id=&#34;评估指标&#34;&gt;评估指标&lt;/h2&gt;&#xA;&lt;h2 id=&#34;评估框架&#34;&gt;评估框架&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://github.com/vibrantlabsai/ragas&#34;&gt;RAGAS&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://github.com/Marker-Inc-Korea/AutoRAG&#34;&gt;AutoRAG&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.zdoc.app/zh/confident-ai/deepeval&#34;&gt;DeepEval&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</description>
    </item>
    <item>
      <title>luckin CLI：实现在终端里点杯瑞幸咖啡</title>
      <link>https://blog.kmoon.fun/luckin-cli%E5%AE%9E%E7%8E%B0%E5%9C%A8%E7%BB%88%E7%AB%AF%E9%87%8C%E7%82%B9%E6%9D%AF%E7%91%9E%E5%B9%B8%E5%92%96%E5%95%A1/</link>
      <pubDate>Thu, 18 Jun 2026 11:28:59 +0800</pubDate><author>hushan@kmoon.fun (Kmoon)</author>
      <guid>https://blog.kmoon.fun/luckin-cli%E5%AE%9E%E7%8E%B0%E5%9C%A8%E7%BB%88%E7%AB%AF%E9%87%8C%E7%82%B9%E6%9D%AF%E7%91%9E%E5%B9%B8%E5%92%96%E5%95%A1/</guid>
      <description>&lt;p&gt;上周末加班，今天调休，相当于提前放端午假了哈哈。&lt;/p&gt;&#xA;&lt;p&gt;瑞幸咖啡太能整活了，听说出了瑞幸咖啡 CLI 服务，可以在终端调用 CLI 服务，让下单更加便捷。刚好前几天女朋友跟我说瑞幸出了一个新品，“弗朗明戈-跳跳冰茶”，说里面有跳跳躺，喝起来很神奇。我们今天就来尝尝看，顺便看看这个 CLI 是整活还是真能用！&lt;/p&gt;&#xA;&lt;img src= &#34;https://cdn.kmoon.fun/2026/2026-06-18T05-07-49-696Z.png&#34; width=200/&gt;&#xA;&lt;p&gt;首先，访问&lt;a href=&#34;https://open.lkcoffee.com/cli&#34;&gt;瑞幸咖啡AI开放平台&lt;/a&gt;，可以看到网站做的还是很简洁科技风的。&lt;/p&gt;&#xA;&lt;img src= &#34;https://cdn.kmoon.fun/2026/2026-06-18T03-31-46-639Z.png&#34; width=500/&gt;&#xA;&lt;p&gt;我们按照官网教程，安装 CLI 工具：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;curl -fsSL https://open.lkcoffee.com/install &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; bash&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;img src= &#34;https://cdn.kmoon.fun/2026/2026-06-18T03-36-16-259Z.png&#34; width=500/&gt;&#xA;&lt;p&gt;我们可以看到已经成功安装了 luckin 0.0.1 CLI 工具。接下来我们在终端输入 luckin 回车：&lt;/p&gt;&#xA;&lt;img src= &#34;https://cdn.kmoon.fun/2026/2026-06-18T03-38-18-773Z.png&#34; width=500/&gt;&#xA;&lt;p&gt;需要先登录授权一下，这里可以看到是跳转到浏览器官网进行授权登录，然后创建一个 Token。&lt;/p&gt;&#xA;&lt;figure&gt;&#xA;&lt;img src=&#34;https://cdn.kmoon.fun/2026/2026-06-18T03-39-51-212Z.png&#34; width=300/&gt;&#xA;&lt;img src=&#34;https://cdn.kmoon.fun/2026/2026-06-18T03-40-18-960Z.png&#34; width=300/&gt;&#xA;&lt;/figure&gt;&#xA;&lt;p&gt;然后我们返回终端，可以看到已经登录成功了，并且可以看到支持哪些斜杠命令：&lt;/p&gt;&#xA;&lt;img src= &#34;https://cdn.kmoon.fun/2026/2026-06-18T03-41-02-898Z.png&#34; width=500/&gt;&#xA;&lt;img src= &#34;https://cdn.kmoon.fun/2026/2026-06-18T03-47-39-742Z.png&#34; width=500/&gt;&#xA;&lt;p&gt;我们先查看一下附近门店，使用 /store 命令，这里突然离谱了起来，这个命令居然需要我自己输入经纬度？？？&lt;/p&gt;&#xA;&lt;img src= &#34;https://cdn.kmoon.fun/2026/2026-06-18T03-49-24-902Z.png&#34; width=500/&gt;&#xA;&lt;p&gt;算了，我们还是在 Claude Code 里面使用它的 my-coffee Skill 吧。希望后续可以打通定位服务，自己定位用户所在位置。&lt;/p&gt;&#xA;&lt;img src= &#34;https://cdn.kmoon.fun/2026/2026-06-18T03-54-20-618Z.png&#34; width=500/&gt;&#xA;&lt;img src= &#34;https://cdn.kmoon.fun/2026/2026-06-18T04-38-06-550Z.png&#34; width=500/&gt;&#xA;&lt;p&gt;我们将官网创建的 Token 手动复制过来，并告诉它在附近帮我点一杯新品冰茶：&lt;/p&gt;&#xA;&lt;img src= &#34;https://cdn.kmoon.fun/2026/2026-06-18T04-41-08-607Z.png&#34; width=500/&gt;&#xA;&lt;img src= &#34;https://cdn.kmoon.fun/2026/2026-06-18T04-54-50-192Z.png&#34; width=500/&gt;&#xA;&lt;img src= &#34;https://cdn.kmoon.fun/2026/2026-06-18T04-56-28-201Z.png&#34; width=500/&gt;&#xA;&lt;img src= &#34;https://cdn.kmoon.fun/2026/2026-06-18T04-57-40-940Z.png&#34; width=500/&gt;&#xA;&lt;p&gt;这里需要我们扫码支付一下，支付完成后会帮我们查询订单状态和取餐码。这里我们可以发现目前只支持自取，暂时不支持外卖配送。不过我相信不久的将来，当美团 CLI、淘宝闪购 CLI 出现的时候，是完全可以支持外卖配送的。&lt;/p&gt;&#xA;&lt;img src= &#34;https://cdn.kmoon.fun/2026/2026-06-18T04-59-52-774Z.png&#34; width=500/&gt;&#xA;&lt;p&gt;好啦，现在我们可以准备去门店取餐了。&lt;/p&gt;&#xA;&lt;img src= &#34;https://cdn.kmoon.fun/2026/2026-06-18T05-03-13-746Z.png&#34; width=500/&gt;&#xA;&lt;p&gt;打开手机的小程序，我们可以看到订单制作完成，等待取餐中：&lt;/p&gt;&#xA;&lt;img src= &#34;https://cdn.kmoon.fun/2026/2026-06-18T05-06-18-362Z.png&#34; width=300/&gt;&#xA;&lt;p&gt;也是成功喝到新品了，一直滋滋滋，跟小时候吃的跳跳糖一样。&lt;/p&gt;&#xA;&lt;img src=&#34;https://cdn.kmoon.fun/2026/2026-06-18T05-24-51-962Z.png&#34; alt=&#34;&#34; width=300/&gt;&#xA;&lt;h2 id=&#34;写在最后&#34;&gt;写在最后&lt;/h2&gt;&#xA;&lt;p&gt;这次折腾这么久，最后也确实成功完成了在终端里下单一杯咖啡。瑞幸这次不是简单整活，而是提供了完整的一套 MCP + CLI + Skills，同时也提供了工具文档，这体现了瑞幸选择拥抱 AI 这条路上迈出了第一步。&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Google 开源 Agent OKF 新标准</title>
      <link>https://blog.kmoon.fun/google-%E5%BC%80%E6%BA%90-agent-okf-%E6%96%B0%E6%A0%87%E5%87%86/</link>
      <pubDate>Wed, 17 Jun 2026 09:34:20 +0800</pubDate><author>hushan@kmoon.fun (Kmoon)</author>
      <guid>https://blog.kmoon.fun/google-%E5%BC%80%E6%BA%90-agent-okf-%E6%96%B0%E6%A0%87%E5%87%86/</guid>
      <description>&lt;blockquote&gt;&#xA;&lt;p&gt;Reference:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://cloud.google.com/blog/products/data-analytics/how-the-open-knowledge-format-can-improve-data-sharing/&#34;&gt;Introducing the Open Knowledge Format&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://mp.weixin.qq.com/s/nhF1cy_lIQukq_niVFvRCA&#34;&gt;AI 寒武纪：谷歌突然开源Agent OKF新标准！&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://github.com/GoogleCloudPlatform/knowledge-catalog/tree/main/okf&#34;&gt;GitHub：knowledge-catalog&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;Open Knowledge Format，简称 OKF，6 月 12 日发布，&lt;a href=&#34;https://github.com/GoogleCloudPlatform/knowledge-catalog/tree/main/okf&#34;&gt;GitHub 仓库&lt;/a&gt;三天冲到 3300+ stars。它要做的事情很简单：给 AI 知识库定一个通用的、可移植的格式规范。&lt;/p&gt;&#xA;&lt;h2 id=&#34;为什么需要统一格式&#34;&gt;为什么需要统一格式&lt;/h2&gt;&#xA;&lt;p&gt;我们平时给 AI 的文档大部分都是内部知识，来源方方面面：数据库表字段含义、接口定义规范、业务功能模块、平台操作手册。这些文档没有统一格式，不同部门关注的重点也不同。这就导致每次新开发一个 Agent，都得从头注入、清洗、梳理一遍知识库。知识没有流通，锁在创建它的那个平台里。&lt;/p&gt;&#xA;&lt;p&gt;更麻烦的是，每个人搭建知识库的方式都不同。有的全部放在一起靠目录区分模块，有的分模块放在不同知识库；有的用长串文件名标记属性，有的更习惯用 frontmatter。对人类来说这无所谓，自己写的自己找得到。但 Agent 需要的是一份格式稳定的&amp;quot;说明书&amp;quot;，不是每次都重新学习你的目录组织习惯。&lt;/p&gt;&#xA;&lt;h2 id=&#34;okf-是什么&#34;&gt;OKF 是什么&lt;/h2&gt;&#xA;&lt;p&gt;核心设计很简单：一个 OKF bundle 就是一个 Markdown 文件目录，每个文件代表一个概念（数据表、数据集、指标、操作手册、API 等），文件路径就是这个概念的唯一标识。&lt;/p&gt;&#xA;&lt;p&gt;目录结构长这样：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sales/&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── index.md&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── datasets/&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   └── orders_db.md&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── tables/&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   ├── orders.md&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   └── customers.md&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;└── metrics/&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    └── weekly_active_users.md&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;每个文件分两部分：顶部一小块 YAML frontmatter 存结构化字段，下面是 Markdown 正文，写什么完全自由。&lt;/p&gt;&#xA;&lt;p&gt;一个完整的概念文件：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;---&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;type: BigQuery Table&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;title: Orders&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;description: One row per completed customer order.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;resource: https://console.cloud.google.com/bigquery?p=acme&amp;amp;d=sales&amp;amp;t=orders&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;tags: [sales, revenue]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;timestamp: 2026-05-28T14:30:00Z&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;---&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gh&#34;&gt;# Schema&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;| Column        | Type      | Description                              |&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;|---------------|-----------|------------------------------------------|&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;| &lt;span class=&#34;sb&#34;&gt;`order_id`&lt;/span&gt;    | STRING    | Globally unique order identifier.        |&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;| &lt;span class=&#34;sb&#34;&gt;`customer_id`&lt;/span&gt; | STRING    | FK to [&lt;span class=&#34;nt&#34;&gt;customers&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/tables/customers.md&lt;/span&gt;). |&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gh&#34;&gt;# Joins&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Joined with [&lt;span class=&#34;nt&#34;&gt;customers&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/tables/customers.md&lt;/span&gt;) on &lt;span class=&#34;sb&#34;&gt;`customer_id`&lt;/span&gt;.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;概念之间用普通 Markdown 链接互引，整个目录变成一张关系图，比文件系统的父子层级丰富得多。&lt;/p&gt;&#xA;&lt;p&gt;合规条件就三条：每个非保留文件必须有可解析的 YAML frontmatter；frontmatter 必须包含非空的 &lt;code&gt;type&lt;/code&gt; 字段；保留文件名（&lt;code&gt;index.md&lt;/code&gt;、&lt;code&gt;log.md&lt;/code&gt;）遵循规定结构。其他一切随意。&lt;/p&gt;&#xA;&lt;p&gt;而且消费者被要求尽量宽容：不能因为缺少可选字段、遇到未知 type、多出额外 frontmatter key，甚至链接断了就拒绝解析。这设计哲学很有意思——宁可多读点废话，也别因为格式细节把合法内容挡在门外。&lt;/p&gt;&#xA;&lt;p&gt;整个&lt;a href=&#34;https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md&#34;&gt;规范文件&lt;/a&gt;才 451 行、14.7 KB。Google 自己说的：Read the spec, it&amp;rsquo;s short! 这话倒没骗人。&lt;/p&gt;&#xA;&lt;h2 id=&#34;karpathy-的影子&#34;&gt;Karpathy 的影子&lt;/h2&gt;&#xA;&lt;p&gt;OKF 不是凭空出来的。Karpathy 今年 4 月发了 &lt;a href=&#34;https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f&#34;&gt;LLM Wiki gist&lt;/a&gt;，两个月拿到 5000+ stars，核心思路就是&amp;quot;每个概念一个 Markdown 文件，LLM 负责维护，互链成图&amp;quot;。OKF 本质上是在标准化这个模式：把 Karpathy 的个人实践固化成一份开放规范，让不同团队、不同工具产出的知识库可以互相识别和消费。&lt;/p&gt;&#xA;&lt;p&gt;我之前分析 &lt;a href=&#34;https://blog.kmoon.fun/blog/rag-vs-llm-wiki/&#34;&gt;RAG vs LLM Wiki 的取舍&lt;/a&gt;时说过，编译好的 wiki 有错误滚雪球、写入成本膨胀、分布式一致性这些问题。OKF 解决的是另一个层面的问题：如果大家都觉得 wiki 模式是对的，那格式得统一，不然你的 wiki 我的 wiki 各玩各的，还是没法流通。&lt;/p&gt;&#xA;&lt;p&gt;Karpathy 估算过，维护得当的 Markdown 知识库相比直接灌原始文档，能减少高达 95% 的 token 消耗。OKF 想做的就是让这个&amp;quot;维护得当&amp;quot;有一个可遵循的底线。&lt;/p&gt;&#xA;&lt;h2 id=&#34;ai-知识的四个层次&#34;&gt;AI 知识的四个层次&lt;/h2&gt;&#xA;&lt;p&gt;参考文章里提了一个我觉得很有意思的分层框架，把 AI 获取知识的方式拆成四层：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;sitemap.xml&lt;/strong&gt; 告诉爬虫哪些 URL 存在&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;llms.txt&lt;/strong&gt; 告诉 agent 哪些页面最值得读&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;EntityMap&lt;/strong&gt; 声明实体和它们之间的关系&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;OKF&lt;/strong&gt; 把内容本身递到 agent 手里，每个页面是一个干净的概念，互链成图&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;这四层不是替代关系，是从索引到内容的递进。sitemap 回答&amp;quot;有什么&amp;quot;，llms.txt 回答&amp;quot;看什么&amp;quot;，EntityMap 回答&amp;quot;谁和谁有关&amp;quot;，OKF 回答&amp;quot;具体是什么&amp;quot;。OKF 补的是最后一公里，不是告诉你去哪找，而是直接把知识递给你。&lt;/p&gt;&#xA;&lt;h2 id=&#34;三个设计原则&#34;&gt;三个设计原则&lt;/h2&gt;&#xA;&lt;h3 id=&#34;极简主义&#34;&gt;极简主义&lt;/h3&gt;&#xA;&lt;p&gt;OKF 对每个文件只要求一个字段：&lt;code&gt;type&lt;/code&gt;。其他一切都留给内容创建者。存在哪些类型、包含哪些字段、正文写哪些部分，规范都不管。它定义的是互操作性接口，不是内容模型。&lt;/p&gt;&#xA;&lt;p&gt;说实话，&lt;code&gt;type&lt;/code&gt; 是唯一必填字段，意味着你可以把任何东西塞进去，只要标上 type。灵活，但也意味着两个 OKF bundle 可能长得完全不一样。&amp;ldquo;格式统一&amp;quot;只统一了最外层的壳，里面的内容组织还是各写各的。&lt;/p&gt;&#xA;&lt;h3 id=&#34;生产者消费者独立性&#34;&gt;生产者/消费者独立性&lt;/h3&gt;&#xA;&lt;p&gt;OKF 把知识编写者和使用者清晰分离。人手写的文件，AI agent 可以读。元数据流水线生成的 bundle，可视化工具可以浏览。一个 LLM 生成的 bundle，另一个 LLM 可以查询。格式是契约，两端工具可以独立替换。&lt;/p&gt;&#xA;&lt;h3 id=&#34;格式本身不是平台&#34;&gt;格式本身，不是平台&lt;/h3&gt;&#xA;&lt;p&gt;OKF 不绑定任何云服务、数据库、模型厂商或 agent 框架。读写不需要专有账号或 SDK。&lt;/p&gt;&#xA;&lt;p&gt;不过有意思的是，发布 OKF 的同一天，Google Cloud 也更新了 Knowledge Catalog，让它原生支持导入 OKF bundle。Knowledge Catalog 管的是 OKF 故意不碰的部分：存储、服务、查询、权限控制。开放格式，付费服务层。这策略眼不眼熟？&lt;/p&gt;&#xA;&lt;h2 id=&#34;3-个参考实现&#34;&gt;3 个参考实现&lt;/h2&gt;&#xA;&lt;p&gt;Google 随规范一起发布了 3 个参考实现：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&lt;strong&gt;enrichment agent&lt;/strong&gt;：工作在 BigQuery 数据集上的数据增强 Agent。先针对每个表和视图写 OKF 概念文件草稿，再跑一遍 LLM 爬取权威文档，补充 schema、引用和关联路径。基于 Google ADK 构建，Gemini 做后端模型。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;static HTML visualizer&lt;/strong&gt;：把任何 OKF bundle 转成单个自包含 HTML 文件里的交互式图形视图。无需后端，数据不会离开页面。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;3 个示例 bundle&lt;/strong&gt;：GA4 电商数据集、Stack Overflow、比特币公开数据集。都是用上面的 enrichment agent 生成的，放在 repo 里作为格式合规的示例。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;说点实在的&#34;&gt;说点实在的&lt;/h2&gt;&#xA;&lt;p&gt;OKF 的极简设计方向是对的。Markdown 是人机共读的最佳折中，用文件路径做概念 ID 很聪明，YAML frontmatter 兼顾了结构化查询和人类可读。规范本身短到 451 行，降低了采纳门槛。&lt;/p&gt;&#xA;&lt;p&gt;但社区也有不同声音。有人直接说&amp;quot;这不就是一个带 YAML frontmatter 的文件夹吗？&amp;ldquo;更尖锐的质疑是：如果目标消费者是 AI，为什么选 Markdown 而不是更结构化的 JSON 或 Protobuf？Markdown 嵌套表格渲染不好，复杂 schema 表达力有限。&lt;/p&gt;&#xA;&lt;p&gt;我觉得关键在于 OKF 不替代 RAG 和 MCP，它们是互补的。RAG 处理大规模动态文档档案，OKF 处理稳定的、精选的组织知识。MCP 管的是 agent 怎么连工具和实时数据，是&amp;quot;插座&amp;rdquo;；OKF 管的是 agent 对数据源知道什么，是&amp;quot;流过插座的知识&amp;rdquo;。一个 MCP server 完全可以把 OKF bundle 作为知识源暴露出来。三者不在一个层面上竞争。&lt;/p&gt;&#xA;&lt;p&gt;真正的顾虑是：OKF 还只是 v0.1。三天 3300 stars 说明社区有需求，但格式规范的真正考验不在发布而在采纳。需要多少生态工具跟上，多少团队真的用 OKF 格式出包，才能形成正循环？标准这东西，用的人多了才是标准，发布了没人用就只是一份文档。&lt;/p&gt;&#xA;&lt;h2 id=&#34;写在最后&#34;&gt;写在最后&lt;/h2&gt;&#xA;&lt;p&gt;OKF 定义的是知识的流通格式，不是知识的替代品。格式能打通孤岛，但填进去的内容还得靠人。&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>为我的 Chaos Pool 开发一个“卖报童”机器人</title>
      <link>https://blog.kmoon.fun/%E4%B8%BA%E6%88%91%E7%9A%84-chaos-pool-%E5%BC%80%E5%8F%91%E4%B8%80%E4%B8%AA%E5%8D%96%E6%8A%A5%E7%AB%A5%E6%9C%BA%E5%99%A8%E4%BA%BA/</link>
      <pubDate>Tue, 16 Jun 2026 13:14:34 +0800</pubDate><author>hushan@kmoon.fun (Kmoon)</author>
      <guid>https://blog.kmoon.fun/%E4%B8%BA%E6%88%91%E7%9A%84-chaos-pool-%E5%BC%80%E5%8F%91%E4%B8%80%E4%B8%AA%E5%8D%96%E6%8A%A5%E7%AB%A5%E6%9C%BA%E5%99%A8%E4%BA%BA/</guid>
      <description>&lt;h2 id=&#34;背景&#34;&gt;背景&lt;/h2&gt;&#xA;&lt;p&gt;我特别想喜欢飞书的 Link Preview 功能，就是在飞书群里发送一篇文章、一个 Github 仓库链接等等，会自动生成一个预览小卡片。&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&#xA;&#xA;&#xA;  &#xA;&#xA;&lt;figure&#xA;    class=&#34;image-caption image-zoom-container&#34;&#xA;&gt;&#xA;    &#xA;    &lt;input&#xA;        type=&#34;checkbox&#34;&#xA;        id=&#34;img-9cb89026&#34;&#xA;        class=&#34;image-zoom-toggle&#34;&#xA;        aria-label=&#34;放大图片：link preview 效果&#34;&#xA;    /&gt;&#xA;    &lt;label&#xA;        for=&#34;img-9cb89026&#34;&#xA;        class=&#34;image-zoom-label&#34;&#xA;    &gt;&#xA;        &lt;img&#xA;            src=&#34;https://cdn.kmoon.fun/2026/2026-06-16T05-22-50-379Z.png&#34;&#xA;            alt=&#34;link preview 效果&#34;&#xA;            loading=&#34;lazy&#34;&#xA;            class=&#34;zoomable-image&#34;&#xA;        /&gt;&#xA;    &lt;/label&gt;&#xA;    &#xA;    &lt;label&#xA;        for=&#34;img-9cb89026&#34;&#xA;        class=&#34;image-zoom-overlay&#34;&#xA;    &gt;&#xA;        &lt;img&#xA;            src=&#34;https://cdn.kmoon.fun/2026/2026-06-16T05-22-50-379Z.png&#34;&#xA;            alt=&#34;link preview 效果&#34;&#xA;            class=&#34;zoomable-image&#34;&#xA;        /&gt;&#xA;    &lt;/label&gt;&#xA;    &#xA;    &lt;figcaption&gt;link preview 效果&lt;/figcaption&gt;&#xA;&lt;/figure&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;这就很好地解决了我平时看到优秀的文章、知识、项目的时候，收藏了一堆链接，但是到后面看着一串 URL 无从下手，不知道每个链接是什么东西的问题。&lt;/p&gt;&#xA;&lt;p&gt;为了管理从四面八方看到的有趣内容，我建了一个飞书群，命名为“Chaos Pool”，中文译为“混沌池”，本意是希望我每天从互联网搜刮来的信息，先扔进这个混沌池子，督促我有时间一定要吸收学习掉，然后将“混沌”转为“稳定”。&lt;/p&gt;&#xA;&lt;p&gt;为此我专门用豆包为群聊生成了一个群头像，我最后选择了第一个：&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&#xA;&#xA;&#xA;  &#xA;&#xA;&lt;figure&#xA;    class=&#34;image-caption image-zoom-container&#34;&#xA;&gt;&#xA;    &#xA;    &lt;input&#xA;        type=&#34;checkbox&#34;&#xA;        id=&#34;img-571da84c&#34;&#xA;        class=&#34;image-zoom-toggle&#34;&#xA;        aria-label=&#34;放大图片：豆包&#34;&#xA;    /&gt;&#xA;    &lt;label&#xA;        for=&#34;img-571da84c&#34;&#xA;        class=&#34;image-zoom-label&#34;&#xA;    &gt;&#xA;        &lt;img&#xA;            src=&#34;https://cdn.kmoon.fun/2026/2026-06-16T05-20-41-586Z.png&#34;&#xA;            alt=&#34;豆包&#34;&#xA;            loading=&#34;lazy&#34;&#xA;            class=&#34;zoomable-image&#34;&#xA;        /&gt;&#xA;    &lt;/label&gt;&#xA;    &#xA;    &lt;label&#xA;        for=&#34;img-571da84c&#34;&#xA;        class=&#34;image-zoom-overlay&#34;&#xA;    &gt;&#xA;        &lt;img&#xA;            src=&#34;https://cdn.kmoon.fun/2026/2026-06-16T05-20-41-586Z.png&#34;&#xA;            alt=&#34;豆包&#34;&#xA;            class=&#34;zoomable-image&#34;&#xA;        /&gt;&#xA;    &lt;/label&gt;&#xA;    &#xA;    &lt;figcaption&gt;豆包&lt;/figcaption&gt;&#xA;&lt;/figure&gt;&#xA;&lt;/p&gt;&#xA;&lt;h2 id=&#34;需要一个卖报童&#34;&gt;需要一个“卖报童”&lt;/h2&gt;&#xA;&lt;p&gt;后面一段时间我都是这样的流程：平时逛 Github、微信公众号、V2EX、阮一峰网络周刊等等，遇到感兴趣、有意思、我能用上的东西，就长按复制链接、打开飞书、进入chaos pool群聊、粘贴链接、回车发送。这一套是不是看着还挺行云流水。&lt;/p&gt;&#xA;&lt;p&gt;后来我慢慢发现，这样其实还是有点麻烦，中间很多环节都可以简化或者省略掉，我期望最终形态是：我复制链接、自动调起一个发送框、回车发送，至少在移动端这样才是我希望的流程。&lt;/p&gt;&#xA;&lt;p&gt;而且还有一个问题，我经常看的社区、周刊、月刊，基本上都是定时发布，我每次还需要自己去对应的网站查看，我需要一个人（机器人）到点自动帮我推送到群里，有点像 RSS 订阅一样。&lt;/p&gt;&#xA;&lt;p&gt;因此，我需要在飞书群里添加一个机器人，来完成上面这些任务，我给他起名为“卖报童”，这个名字也是通俗易懂。&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&#xA;&#xA;&#xA;  &#xA;&#xA;&lt;figure&#xA;    class=&#34;image-caption image-zoom-container&#34;&#xA;&gt;&#xA;    &#xA;    &lt;input&#xA;        type=&#34;checkbox&#34;&#xA;        id=&#34;img-a133e919&#34;&#xA;        class=&#34;image-zoom-toggle&#34;&#xA;        aria-label=&#34;放大图片：添加飞书机器人&#34;&#xA;    /&gt;&#xA;    &lt;label&#xA;        for=&#34;img-a133e919&#34;&#xA;        class=&#34;image-zoom-label&#34;&#xA;    &gt;&#xA;        &lt;img&#xA;            src=&#34;https://cdn.kmoon.fun/2026/2026-06-16T05-22-15-325Z.png&#34;&#xA;            alt=&#34;添加飞书机器人&#34;&#xA;            loading=&#34;lazy&#34;&#xA;            class=&#34;zoomable-image&#34;&#xA;        /&gt;&#xA;    &lt;/label&gt;&#xA;    &#xA;    &lt;label&#xA;        for=&#34;img-a133e919&#34;&#xA;        class=&#34;image-zoom-overlay&#34;&#xA;    &gt;&#xA;        &lt;img&#xA;            src=&#34;https://cdn.kmoon.fun/2026/2026-06-16T05-22-15-325Z.png&#34;&#xA;            alt=&#34;添加飞书机器人&#34;&#xA;            class=&#34;zoomable-image&#34;&#xA;        /&gt;&#xA;    &lt;/label&gt;&#xA;    &#xA;    &lt;figcaption&gt;添加飞书机器人&lt;/figcaption&gt;&#xA;&lt;/figure&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;添加完飞书机器人后，我们得到了一个名为 webhook 的 https 链接，怎么用呢？&lt;/p&gt;&#xA;&lt;h2 id=&#34;webhook-是什么怎么用&#34;&gt;webhook 是什么？怎么用？&lt;/h2&gt;&#xA;&lt;p&gt;webhook 是什么？怎么用？我们点击查阅一下&lt;a href=&#34;https://open.feishu.cn/document/client-docs/bot-v3/add-custom-bot?lang=zh-CN&#34;&gt;官方使用指南&lt;/a&gt;。看完发现没啥，可以理解为一个发送消息的接口，通过 webhook 请求可以在飞书群里发送消息。&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&#xA;&#xA;&#xA;&lt;figure&#xA;    class=&#34;image-caption image-zoom-container&#34;&#xA;&gt;&#xA;    &#xA;    &lt;input&#xA;        type=&#34;checkbox&#34;&#xA;        id=&#34;img-8a587a8d&#34;&#xA;        class=&#34;image-zoom-toggle&#34;&#xA;        aria-label=&#34;放大图片&#34;&#xA;    /&gt;&#xA;    &lt;label&#xA;        for=&#34;img-8a587a8d&#34;&#xA;        class=&#34;image-zoom-label&#34;&#xA;    &gt;&#xA;        &lt;img&#xA;            src=&#34;https://cdn.kmoon.fun/2026/2026-06-16T05-37-54-159Z.png&#34;&#xA;            alt=&#34;&#34;&#xA;            loading=&#34;lazy&#34;&#xA;            class=&#34;zoomable-image&#34;&#xA;        /&gt;&#xA;    &lt;/label&gt;&#xA;    &#xA;    &lt;label&#xA;        for=&#34;img-8a587a8d&#34;&#xA;        class=&#34;image-zoom-overlay&#34;&#xA;    &gt;&#xA;        &lt;img&#xA;            src=&#34;https://cdn.kmoon.fun/2026/2026-06-16T05-37-54-159Z.png&#34;&#xA;            alt=&#34;&#34;&#xA;            class=&#34;zoomable-image&#34;&#xA;        /&gt;&#xA;    &lt;/label&gt;&#xA;    &#xA;    &#xA;&lt;/figure&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;那我们先简单调试一下，测试调用自定义机器人的 webhook 地址，向所在群组发送消息。：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;curl -X POST -H &lt;span class=&#34;s2&#34;&gt;&amp;#34;Content-Type: application/json&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    -d &lt;span class=&#34;s1&#34;&gt;&amp;#39;{&amp;#34;msg_type&amp;#34;:&amp;#34;text&amp;#34;,&amp;#34;content&amp;#34;:{&amp;#34;text&amp;#34;:&amp;#34;啦啦啦！啦啦啦！我是卖报的小行家。&amp;#34;}}&amp;#39;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    https://open.feishu.cn/open-apis/bot/v2/hook/****&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们可以看到群里收到了卖报童发来的卖报歌，：&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&#xA;&#xA;&#xA;&lt;figure&#xA;    class=&#34;image-caption image-zoom-container&#34;&#xA;&gt;&#xA;    &#xA;    &lt;input&#xA;        type=&#34;checkbox&#34;&#xA;        id=&#34;img-ee59ee56&#34;&#xA;        class=&#34;image-zoom-toggle&#34;&#xA;        aria-label=&#34;放大图片&#34;&#xA;    /&gt;&#xA;    &lt;label&#xA;        for=&#34;img-ee59ee56&#34;&#xA;        class=&#34;image-zoom-label&#34;&#xA;    &gt;&#xA;        &lt;img&#xA;            src=&#34;https://cdn.kmoon.fun/2026/2026-06-16T05-46-53-370Z.png&#34;&#xA;            alt=&#34;&#34;&#xA;            loading=&#34;lazy&#34;&#xA;            class=&#34;zoomable-image&#34;&#xA;        /&gt;&#xA;    &lt;/label&gt;&#xA;    &#xA;    &lt;label&#xA;        for=&#34;img-ee59ee56&#34;&#xA;        class=&#34;image-zoom-overlay&#34;&#xA;    &gt;&#xA;        &lt;img&#xA;            src=&#34;https://cdn.kmoon.fun/2026/2026-06-16T05-46-53-370Z.png&#34;&#xA;            alt=&#34;&#34;&#xA;            class=&#34;zoomable-image&#34;&#xA;        /&gt;&#xA;    &lt;/label&gt;&#xA;    &#xA;    &#xA;&lt;/figure&gt;&#xA;&#xA;&#xA;&#xA;&#xA;&#xA;&lt;figure&#xA;    class=&#34;image-caption image-zoom-container&#34;&#xA;&gt;&#xA;    &#xA;    &lt;input&#xA;        type=&#34;checkbox&#34;&#xA;        id=&#34;img-18d24d2a&#34;&#xA;        class=&#34;image-zoom-toggle&#34;&#xA;        aria-label=&#34;放大图片&#34;&#xA;    /&gt;&#xA;    &lt;label&#xA;        for=&#34;img-18d24d2a&#34;&#xA;        class=&#34;image-zoom-label&#34;&#xA;    &gt;&#xA;        &lt;img&#xA;            src=&#34;https://cdn.kmoon.fun/2026/2026-06-16T05-47-06-161Z.png&#34;&#xA;            alt=&#34;&#34;&#xA;            loading=&#34;lazy&#34;&#xA;            class=&#34;zoomable-image&#34;&#xA;        /&gt;&#xA;    &lt;/label&gt;&#xA;    &#xA;    &lt;label&#xA;        for=&#34;img-18d24d2a&#34;&#xA;        class=&#34;image-zoom-overlay&#34;&#xA;    &gt;&#xA;        &lt;img&#xA;            src=&#34;https://cdn.kmoon.fun/2026/2026-06-16T05-47-06-161Z.png&#34;&#xA;            alt=&#34;&#34;&#xA;            class=&#34;zoomable-image&#34;&#xA;        /&gt;&#xA;    &lt;/label&gt;&#xA;    &#xA;    &#xA;&lt;/figure&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;这里遇到一个问题，通过机器人发送的链接没有生成预览卡片，我自己手动发送的明明可以生成卡片呀。&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&#xA;&#xA;&#xA;&lt;figure&#xA;    class=&#34;image-caption image-zoom-container&#34;&#xA;&gt;&#xA;    &#xA;    &lt;input&#xA;        type=&#34;checkbox&#34;&#xA;        id=&#34;img-de57acbf&#34;&#xA;        class=&#34;image-zoom-toggle&#34;&#xA;        aria-label=&#34;放大图片&#34;&#xA;    /&gt;&#xA;    &lt;label&#xA;        for=&#34;img-de57acbf&#34;&#xA;        class=&#34;image-zoom-label&#34;&#xA;    &gt;&#xA;        &lt;img&#xA;            src=&#34;https://cdn.kmoon.fun/2026/2026-06-16T05-51-21-752Z.png&#34;&#xA;            alt=&#34;&#34;&#xA;            loading=&#34;lazy&#34;&#xA;            class=&#34;zoomable-image&#34;&#xA;        /&gt;&#xA;    &lt;/label&gt;&#xA;    &#xA;    &lt;label&#xA;        for=&#34;img-de57acbf&#34;&#xA;        class=&#34;image-zoom-overlay&#34;&#xA;    &gt;&#xA;        &lt;img&#xA;            src=&#34;https://cdn.kmoon.fun/2026/2026-06-16T05-51-21-752Z.png&#34;&#xA;            alt=&#34;&#34;&#xA;            class=&#34;zoomable-image&#34;&#xA;        /&gt;&#xA;    &lt;/label&gt;&#xA;    &#xA;    &#xA;&lt;/figure&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;了解后发现“自定义机器人”不支持链接预览功能，需要创建一个“应用机器人”：&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&#xA;&#xA;&#xA;&lt;figure&#xA;    class=&#34;image-caption image-zoom-container&#34;&#xA;&gt;&#xA;    &#xA;    &lt;input&#xA;        type=&#34;checkbox&#34;&#xA;        id=&#34;img-37306963&#34;&#xA;        class=&#34;image-zoom-toggle&#34;&#xA;        aria-label=&#34;放大图片&#34;&#xA;    /&gt;&#xA;    &lt;label&#xA;        for=&#34;img-37306963&#34;&#xA;        class=&#34;image-zoom-label&#34;&#xA;    &gt;&#xA;        &lt;img&#xA;            src=&#34;https://cdn.kmoon.fun/2026/2026-06-16T11-04-40-775Z.png&#34;&#xA;            alt=&#34;&#34;&#xA;            loading=&#34;lazy&#34;&#xA;            class=&#34;zoomable-image&#34;&#xA;        /&gt;&#xA;    &lt;/label&gt;&#xA;    &#xA;    &lt;label&#xA;        for=&#34;img-37306963&#34;&#xA;        class=&#34;image-zoom-overlay&#34;&#xA;    &gt;&#xA;        &lt;img&#xA;            src=&#34;https://cdn.kmoon.fun/2026/2026-06-16T11-04-40-775Z.png&#34;&#xA;            alt=&#34;&#34;&#xA;            class=&#34;zoomable-image&#34;&#xA;        /&gt;&#xA;    &lt;/label&gt;&#xA;    &#xA;    &#xA;&lt;/figure&gt;&#xA;&lt;/p&gt;&#xA;</description>
    </item>
  </channel>
</rss>
