为了让 Claude Code 不再重复踩坑,我给它补了一层经验系统 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Zaptain
V2EX    Claude Code

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

  •  
  •   Zaptain 10 天前 1607 次点击

    编程 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  
       9 天前 via iPhone
    很好的想法,其实就是提供问题定位上下文
    Zaptain
        2
    Zaptain  
    OP
       9 天前
    @bytesfold 总结得好
    McVander
        3
    McVander  
       9 天前
    思路很棒
    akatquas
        4
    akatquas  
       9 天前
    搜索不在 memory , 不在 context 的旧知识,是否可以用 RAG ?
    XTTX
        5
    XTTX  
       9 天前
    这些具体的动作可以写成一个 skill.
    ---
    name: skill-name
    description: "Use when the user wants to xxxx:
    ---
    所有的 skills 只有名字和描述是加载在每个对话里。 你只要简单描述,CC 会找到这个 skill 并执行。CLAUDE.MD 的所有东西都会加载。 skill 是 可以有其他程序,写出 pipe in 接口,CC 可以按需调用。
    Corrots
        6
    Corrots  
       9 天前
    大佬,有没有 github copilot 版本的
    Zaptain
        7
    Zaptain  
    OP
       9 天前
    @akatquas 之前想过 rag ,但体积会大很多,不太值得,所以初期就先放弃了
    Zaptain
        8
    Zaptain  
    OP
       9 天前
    @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
       9 天前
    @Corrots 感谢建议,我研究一下哈
    sunnysab
        10
    sunnysab  
       9 天前
    似乎有点像 AI 去写博客?
    XTTX
        11
    XTTX  
       9 天前
    @Zaptain 你多问问它不就得了, 还整个贴过来. 当我没有说过
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     916 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 29ms UTC 22:57 PVG 06:57 LAX 15:57 JFK 18:57
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86