V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Zaptain
V2EX  ›  Claude Code

为了让 Claude Code 不再重复踩坑,我给它补了一层经验系统

  •  
  •   Zaptain · 1 天前 · 1102 次点击

    编程 Agent 会分析/解决问题,但不会积累经验。它们有印象,但没有笔记。RadioHeader 给 Claude Code 补上了这一层。


    先说个真事儿

    我用 Claude Code 做 iOS 的时候,遇到过一次 app 启动白屏几十秒的问题。Claude 一路查日志、翻文件、试各种排查,折腾了很久都没定位到。最后还是我想起来,另一个项目以前也出过差不多的事,让它去翻那个项目的旧记录,才找到根因——Xcode 的 scheme 设置问题。

    那一刻我就很确定一件事:像 Claude Code 这样的编程 Agent ,分析问题、写代码都很强,但它们不会共享项目经验。后来 Claude Code 虽然也加了 memory ,但本质问题没变——它记得方向,记不住关键细节,更别说跨项目复用了。

    项目之间的记忆完全隔离,就意味着项目 A 踩过的坑,项目 B 根本不知道。如果我自己记得”我好像遇到过这个问题”,还能手动指路,要是我也忘了呢?

    现有的工具几乎都是在做"规则"层面的事。规则当然有用,但规则无很难达到“这个坑我真的踩过,而且已经知道怎么修"这种程度。做硬件产品的时候我也经常遇到这类"认知型经验"——不是文档里写了你就会的,得自己撞上、解决了,才真正印象深刻。

    在没找到做编程 agent”经验"层面的工具的情况下,我自己做了一个。


    RadioHeader 不是一开始设计好的,是被真实问题一步步逼出来的。

    第一步:让 Agent 学会记笔记

    起点是单项目内的记忆缺失。Claude Code 在一个项目里工作久了,早期的经验就开始模糊。它记得"之前遇到过类似问题",但记不住具体怎么解决的。

    换句话说:Agent 需要的是笔记,不是印象。 自带的 memory 记的是大致印象,而能被精确搜索到的结构化笔记才有复用价值。

    我的想法很朴素:让 Claude 每次解决完问题后,主动把经验记下来。具体分两种:一种是经验条目,写进 memory/ 目录——根因、修法、注意事项,按主题组织,方便以后检索;另一种是任务日志,写进 logs/ 目录——以一个问题的解决为单位,记录背景、过程、结论,保留完整上下文。日志的文件名经过设计:日期-主题-撰写者,Agent 和人类都要署名,标清楚方便追溯。起初我会在关键节点手动提醒 Claude"同步一下项目信息",后来逐渐做成了自动化。

    我把这个机制叫经验回流——完成一个任务后,经验自动流回记忆系统。每次修完 bug 、做了架构决策、踩了非直觉的坑,Claude 都把经验写回去。用 Claude Code 的 hook 机制让这个过程自动:PostToolUse hook 在写入 memory 时触发检查,Stop hook 在会话结束时提醒有没有新经验遗漏。

    同一个项目里,以前要重新排查的问题,现在翻笔记就能解决。

    但很快就遇到了开头那个场景:项目 A 的笔记,项目 B 搜不到。

    第二步:打通项目之间的壁垒

    于是我在所有项目之上建了一个全局经验中枢:~/.claude/radioheader/

    名字的由来——我喜欢 Radiohead 这个乐队,而这个全局中枢又像一个信号塔,各个项目需要的时候就从里面接收信息。RadioHeader ,就这么出现了。

    架构变成了三层:

    ┌─────────────────────────────────┐
    │  RadioHeader (全局经验中枢)      │  ← 所有项目共享
    ├─────────────────────────────────┤
    │  项目 memory/(项目专属记忆)     │  ← 当前项目
    ├─────────────────────────────────┤
    │  会话上下文(临时)               │  ← 当前对话
    └─────────────────────────────────┘
    

    每次经验回流时,Claude 会顺手判断一下:这条经验是不是跨项目通用的?如果是,写入全局层,标注来源项目。之后任何项目遇到类似问题,先搜这里。有了 RadioHeader 这个信号塔的隐喻之后,我把经验回流叫做 Echo(回波)——经验像信号的回波一样,从项目返回信号塔。

    装了之后再遇到白屏问题:

    你:App 启动白屏 10 秒以上
    
    Claude:RadioHeader 中有来自 ProjectA 的经验:
            "Xcode scheme 的 Launch 配置导致 iOS app 启动白屏,
            检查 scheme 设置中的相关选项……"
    
            验证一下是否适用…… ✓ 同样的模式。正在应用修复。
    

    不用我手动指路了。同一类问题从第二次开始,解决时间从分钟级掉到秒级。不是 AI 变聪明了,是答案已经在那里了。

    精炼:从项目经验到通用知识

    跨项目共享之后冒出一个新问题:经验一旦放到全局以后,原始条目里保留的项目上下文太多,搜索噪音和 token 消耗都上来了。比如一条经验写着 [来源:DarkWriting] iCloud I/O 阻塞主线程,另一个项目用的是 CoreData 不是 iCloud——但根因相同。项目名和具体技术细节反而成了搜索障碍。

    于是我加了一层精炼:短波( Shortwave )——去掉项目名、文件路径、框架细节,只保留通用知识。这不光是为了降噪,也是为了保护隐私——经验条目在精炼之前可能包含项目路径、内部命名甚至 API key ,短波会把这些全部剥离。

    这样三层就接上了:经验先通过 Echo 回到 RadioHeader,再由 Shortwave 去掉项目噪音,变成可广播的通用知识。

    ---
    id: sw-ios-task-inherits-mainactor
    domain: iOS, SwiftUI, Concurrency
    tags: 白屏 | 启动慢 | white screen | slow launch | 10s+ | Main Actor | Task
    ---
    ### Task {} 在 @MainActor 上下文中继承主线程,I/O 阻塞导致白屏
    
    symptoms: 应用启动后 10s+ 白屏,首次加载卡死
    cause: Task {} 在 @MainActor 标记的上下文中创建时继承主线程
    fix: 使用 Task.detached(priority:) 将 I/O 操作移出主线程
    

    注意 tags 里的"白屏"、"启动慢"、"slow launch"——这些是开发者实际会搜的词。如果只保留 "Task.detached" 这种解法关键词,这条经验就搜不到了。症状关键词比解法关键词重要得多。 经验条目删掉了症状词就等于不存在。

    比搜不到更烦的,是搜到了也不用

    到这里遇到了另一个让人头疼的问题:Claude 搜到了经验,但不用。

    早期我在 CLAUDE.md 里写:"遇到技术问题时先搜索 RadioHeader"。Claude 确实搜了,也找到了相关结果——然后完全忽略,直接跳进独立分析。就像你给新同事一本 wiki ,他打开看了一眼,还是选择自己摸索。

    后来搞明白了:行为指令比知识描述有效得多。CLAUDE.md 里写"这里有个东西可以查"没用,得写"你必须搜,搜到必须引用,禁止搜到不用"才行。这两种写法在 Agent 系统中效果差很远。

    最终方案是"搜→用→追"三步强制规则:

    1. :遇到技术问题,先搜 RadioHeader
    2. :搜到相关经验,必须引用并验证
    3. :需要更多细节,追溯到来源项目的 memory

    外加一句禁令:"禁止搜到相关经验却不引用、不应用,直接跳过去做独立分析"——这句话比前面三条都管用。

    第三步:从个人记忆到社区共享

    前两步解决了自己不重复踩坑的问题,但我的经验仍然是一座孤岛。我遇到的问题,世界上某个人在开发中一定早就有经验了;反过来,我踩过的坑可能也正好能帮到别人。

    能不能把精炼好的短波共享出去?难题不在技术,在质量治理——不能什么都往池子里丢,但我一个人也做不了人工审核。

    当时我想到试试从生物学里找找灵感,结果还真找到了一个概念——Stigmergy (痕迹协作)。这是蚁群行为学里的东西:蚂蚁在路径上留信息素,走的越多越浓,没蚂蚁走的自然蒸发。不需要谁来管理,好路径自己就显现出来了。

    用这个思路做知识共享的质量治理:

    • 自动投票:Claude 用了社区短波解决问题后,自动判断这条经验是不是真帮上忙了,+1 或 -1
    • 时间衰减:分数随时间下降(半衰期约 125 天),过时的经验自然淘汰(需要验证一下效果)
    • 每周清洗:GitHub Actions 聚合投票,高分标记 verified,低分归档

    发布也有门槛——质量评分(≥6/8 )、隐私扫描(确保没泄露路径和密钥)、去重检查。不需要管理员,好经验自己浮上来,差经验自己沉下去。

    目前的状态

    我不是做完一个 demo 就拿出来讲故事,这套东西已经在我自己手里滚了几个月。13 个项目,覆盖 iOS/SwiftUI 、Rust 、后端部署、网络代理、AI API 、Claude Code 、硬件产品 7 个技术领域。205 条原始经验,120 条精炼短波,114 条发布到社区池。(截止发稿时)

    试试看

    不用先研究完整设计,找一个你最近最常重复踩坑的项目,装上跑一周就知道它有没有用。

    git clone https://github.com/ZaptainZ/radioheader.git
    cd radioheader
    ./install.sh
    

    之后在任何项目中启动 Claude Code 就生效了。

    # 开启社区共享
    radioheader community on
    radioheader sync
    

    GitHub:ZaptainZ/radioheader


    RadioHeader 还在继续打磨,但它已经在我自己的真实项目里跑出价值了,所以我把它公开出来。开源社区帮了我很多,这次也算把自己真用出来的一套东西拿出来回馈。

    MIT 协议。你要是也受不了重复踩坑,直接装上试试。有用欢迎 star ,没用也欢迎来 issue 吐槽。

    11 条回复    2026-03-12 20:43:31 +08:00
    bytesfold
        1
    bytesfold  
       21 小时 5 分钟前 via iPhone
    很好的想法,其实就是提供问题定位上下文
    Zaptain
        2
    Zaptain  
    OP
       19 小时 48 分钟前
    @bytesfold 总结得好🍻
    McVander
        3
    McVander  
       18 小时 48 分钟前
    思路很棒
    akatquas
        4
    akatquas  
       18 小时 28 分钟前
    搜索不在 memory , 不在 context 的旧知识,是否可以用 RAG ?
    XTTX
        5
    XTTX  
       18 小时 4 分钟前
    这些具体的动作可以写成一个 skill.
    ---
    name: skill-name
    description: "Use when the user wants to xxxx:
    ---
    所有的 skills 只有名字和描述是加载在每个对话里。 你只要简单描述,CC 会找到这个 skill 并执行。CLAUDE.MD 的所有东西都会加载。 skill 是 可以有其他程序,写出 pipe in 接口,CC 可以按需调用。
    Corrots
        6
    Corrots  
       17 小时 6 分钟前
    大佬,有没有 github copilot 版本的
    Zaptain
        7
    Zaptain  
    OP
       14 小时 16 分钟前
    @akatquas 之前想过 rag ,但体积会大很多,不太值得,所以初期就先放弃了
    Zaptain
        8
    Zaptain  
    OP
       14 小时 13 分钟前
    @XTTX 转述 cc 的回复:“他的理解部分对,但忽略了 RadioHeader 架构中几个关键设计选择的原因。

    他说对的部分

    - Skills 确实轻量:只有 name + description 常驻上下文,正文按需加载
    - 对于离散的操作动作(比如 radioheader search 、radioheader
    publish ),写成 skill 是合理的

    他忽略的核心问题

    1. Skills 是按需触发的,Hooks 是自动触发的

    RadioHeader 的 PostToolUse hook 在 memory/ 被写入时自动触发 Echo
    检查,不需要任何人记得调用。这用 skill 做不到——skill 必须由 agent
    或用户主动调用。

    2. RadioHeader 最大的教训恰恰是"可选 = 不用"

    你文章里写得很清楚:早期版本告诉 Claude "可以搜
    RadioHeader",结果搜了也不用。修复方案是强制行为规则写在 CLAUDE.md
    里,每个会话都加载,不可跳过。

    如果把"搜→用→追"做成 skill ,它就从 MUST 降级成了 CAN 。Agent
    需要先判断"我要不要调用这个 skill"——而你已经验证过,给它选择权 =
    它选择跳过。

    3. PostToolUse 的 additionalContext 是系统级注入

    Hook 的 additionalContext 被 Agent
    视为系统级指令,优先级高于普通对话内容。Skill 的内容是作为 prompt
    注入的,权重不同。这是你在 projectBasicInfo 里记录过的关键经验。

    总结

    ┌──────────────────────────┬──────────────┬──────────────────────────┐
    │ 机制 │ 适合做 skill │ 必须用 hook/CLAUDE.md
    ├──────────────────────────┼──────────────┼──────────────────────────┤
    │ 搜→用→追规则 │ ✗ │ ✓ 强制行为,不可降为可选 │
    ├──────────────────────────┼──────────────┼──────────────────────────┤
    │ Echo 自动触发 │ ✗ │ ✓ PostToolUse 自动 fire │
    ├──────────────────────────┼──────────────┼──────────────────────────┤
    │ Stop 提醒 │ ✗ │ ✓ 会话结束自动 fire │
    ├──────────────────────────┼──────────────┼──────────────────────────┤
    │ radioheader search 操作 │ ✓ │ — │
    ├──────────────────────────┼──────────────┼──────────────────────────┤
    │ radioheader publish 操作 │ ✓ │ — │
    ├──────────────────────────┼──────────────┼──────────────────────────┤
    │ 新项目初始化引导 │ ✓ │ — │
    └──────────────────────────┴──────────────┴──────────────────────────┘

    他的建议不是错的,但适用于操作层而非行为规则层。RadioHeader
    的核心价值恰恰在后者——如果行为规则变成可选
    skill ,就回到了你已经踩过的坑。

    可以回复他:具体操作确实可以做成 skill ,但 RadioHeader
    的核心是强制行为规则 + 自动触发的 hooks ,这两个必须常驻而非按需加载——这正
    是踩了"搜到但没用"这个坑之后的设计决策。”
    Zaptain
        9
    Zaptain  
    OP
       14 小时 12 分钟前
    @Corrots 感谢建议,我研究一下哈
    sunnysab
        10
    sunnysab  
       8 小时 19 分钟前
    似乎有点像 AI 去写博客?
    XTTX
        11
    XTTX  
       7 小时 27 分钟前
    @Zaptain 你多问问它不就得了, 还整个贴过来. 当我没有说过
    关于   ·   帮助文档   ·   自助推广系统   ·   博客   ·   API   ·   FAQ   ·   Solana   ·   957 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 20:10 · PVG 04:10 · LAX 13:10 · JFK 16:10
    ♥ Do have faith in what you're doing.