Community编程与开发github.com

erikvallow-qt/不要让我滑倒

在AI辅助解决问题后,运行本技能可回顾会话、记录经验教训(供人类和AI参考),并就关键点对用户进行测验。

不要让我滑倒 是什么?

这是一个智能回顾与学习技能,专为AI辅助开发后的复盘场景设计。当用户通过AI解决了一个问题后,该技能会识别并读取相关聊天会话,分析人类和AI在解决过程中各自遗漏的信息、误解的概念或需要深入理解的知识点。它基于分析结果生成两个核心文件:LEARNED.md(经验教训文档)和 learned_quiz.py(终端测验脚本)。LEARNED.md包含问题过程描述、分为人类、AI和共享三类经验教训(每个教训附有经过验证的参考资料链接和深度阅读建议)、测验问题、链接清单以及一个可避免该问题的建议一次性提示。测验脚本则根据文档内容生成10-25道涵盖所有知识点的题目,支持回忆、首选检查步骤和找错等多种题型,并可在MacOS、Linux和Windows终端上运行。此技能适用于Claude Code等支持技能运行的AI平台,能有效将单次问题解决经验转化为可复用的学习资料。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/erikvallow-qt/dont-let-me-slide/tree/HEAD/dont-let-me-slide

Installed? Explore more 编程与开发 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

回顾解决该问题的会话。生成两个文件:LEARNED.md 和 learned_quiz.py(一个终端测验程序)。

  1. 识别会话。 使用最近的聊天记录找到与问题匹配的会话。如果有多个可能的会话,询问用户选择哪一个。如果该会话属于某个项目,还需审查该项目中的其他聊天记录。
  2. 读取整个会话,而不仅仅是摘要。 记录人类和AI在问题解决前各自遗漏的地方。同时记录人类不得不凭信任接受、询问超过一次或理解错误的概念:这些概念需要深入探讨。
  3. 在撰写前研究链接。 每条经验教训至少找到一个链接。针对每条人类教训以及步骤2中的每个概念,找到1到3个深入阅读链接,从基本原理解释背景。优先顺序为:官方文档或规范、供应商应用说明或手册、知名教程或教科书,然后是信誉良好的博客或问答。使用WebSearch,然后通过WebFetch打开每个链接以确认其可访问且涵盖要点。丢弃任何失败或离题的链接。切勿虚构URL。
  4. 编写LEARNED.md,包含以下部分,按此顺序:
    • 发生了什么: 3到5句话,加上状态(已解决或未解决)。如果未解决,列出未完成项。
    • 经验教训: 分为人类、AI和共享三类。每条教训给出要点、遗漏的内容、一句总结的教训,以及一个链接(注明来源)。对于需要背景知识的每条人类教训,在其下添加“深度阅读”子列表:每项为 标题、来源以及一行说明它教授了什么以及为何在此处有用。
    • 测验问题: 3到5个关键问题,标题为“测验问题”,后附答案。注意完整的问题集在 learned_quiz.py 中。
    • 链接: 使用的所有链接,按教训分组,注明来源。说明链接在运行日期已验证,使用前应再次确认。
    • 建议的一次性提示: 一个简洁的提示,如果当初使用,本可避免本会话中的问题。
  5. 标记断言。 将未经验证的断言标记为“未验证”。将从搜索结果中获取的断言标记为“已报告”,并链接来源。
  6. 不要将猜测作为发现呈现。 如果问题的原因未确认,请如实说明。
  7. 根据以下模板编写 learned_quiz.py。规则:
    • 仅使用Python 3标准库。必须在macOS、Linux和Windows终端上运行。无GUI。
    • 涵盖每个概念,不仅仅是3到5个测验问题:每条人类教训至少2题,每条AI和共享教训至少1题,每个深度阅读概念至少1题。通常10到25题。混合回忆题、“首先检查什么”题和“找出错误”题。
    • 每个问题:主题(Human、AI、Shared或简短概念名)、4个选项(含合理的干扰项)、正确答案索引、1到2句解释,以及最相关的已验证链接。
    • 仅填充 TITLE、SOURCE 和 QUESTIONS。不要更改引擎。
    • 在发送前,运行 python3 -c "import ast,sys;ast.parse(open(sys.argv[1]).read())" learned_quiz.py,然后运行 python3 learned_quiz.py --list,并修复任何错误。检查每个答案索引指向正确的选项。
  8. 保持LEARNED.md简洁。 两个文件中均不要使用长破折号。
  9. 通过SendUserFile发送两个文件。 在回复中给出运行命令:python3 learned_quiz.py(选项:-r 闪卡复习,-t TOPIC 主题过滤,-n N 限制数量,--list 打印所有,--seed N 固定顺序)。

测验模板(精确保留,替换占位符和示例问题):

#!/usr/bin/env python3
"""LEARNED 测验:<主题>。运行:python3 learned_quiz.py [-r] [-t TOPIC] [-n N] [--list]"""
import argparse, random, sys, textwrap

TITLE = "<主题>"
SOURCE = "LEARNED.md,<日期>"
QUESTIONS = [
    {"topic": "Human", "q": "示例问题?",
     "choices": ["正确答案", "错误答案1", "错误答案2", "错误答案3"], "answer": 0,
     "why": "一两句解释原因。", "link": "https://example.com"},
]

def wrap(s, ind="   "):
    return textwrap.fill(s, 78, initial_indent=ind, subsequent_indent=ind)

def ask(prompt, valid):
    while True:
        try:
            a = input(prompt).strip().lower()
        except (EOFError, KeyboardInterrupt):
            print(); sys.exit(0)
        if a in valid:
            return a

def run(qs, review):
    missed = []
    for i, q in enumerate(qs, 1):
        order = list(range(len(q["choices"])))
        random.shuffle(order)
        letters = "abcdefgh"[:len(order)]
        print(f"\n[{i}/{len(qs)}] ({q['topic']})")
        print(wrap(q["q"], ""))
        for L, idx in zip(letters, order):
            print(wrap(f"{L}) {q['choices'][idx]}"))
        right = letters[order.index(q["answer"])]
        if review:
            if ask("   按回车显示答案,q退出:", {"", "q"}) == "q":
                sys.exit(0)
            ok = True
        else:
            a = ask(f"   答案 [{letters}],q退出:", set(letters) | {"q"})
            if a == "q":
                break
            ok = a == right
            print("   正确。" if ok else f"   不对。答案是:{right}")
        if review or not ok:
            print(wrap(f"{right}) {q['choices'][q['answer']]}"))
        print(wrap(q["why"]))
        if q.get("link"):
            print(wrap("更多:" + q["link"]))
        if not ok:
            missed.append(q)
    return missed

def main():
    p = argparse.ArgumentParser(description=f"测验:{TITLE}")
    p.add_argument("-r", "--review", action="store_true", help="闪卡模式,不计分")
    p.add_argument("-t", "--topic", help="仅限该主题(Human, AI, Shared, ...)")
    p.add_argument("-n", type=int, help="最多问N个问题")
    p.add_argument("--list", action="store_true", help="打印所有问答并退出")
    p.add_argument("--seed", type=int, help="固定随机顺序")
    a = p.parse_args()
    random.seed(a.seed)
    qs = [q for q in QUESTIONS if not a.topic or q["topic"].lower() == a.topic.lower()]
    if not qs:
        sys.exit(f"未找到主题 {a.topic!r} 的问题。")
    if a.list:
        for i, q in enumerate(qs, 1):
            print(f"{i}. ({q['topic']}) {q['q']}\n{wrap('答:' + q['choices'][q['answer']])}\n{wrap(q['why'])}")
            if q.get("link"):
                print(wrap("更多:" + q["link"]))
        return
    random.shuffle(qs)
    qs = qs[:a.n] if a.n else qs
    print(f"{TITLE}\n来源:{SOURCE}\n共{len(qs)}个问题。")
    while qs:
        missed = run(qs, a.review)
        if a.review:
            break
        print(f"\n得分:{len(qs) - len(missed)}/{len(qs)}")
        if not missed or ask("重做错题?[y/n]:", {"y", "n"}) == "n":
            for q in missed:
                print(wrap(f"复习:{q['q']}", "- ") + ("\n" + wrap(q["link"]) if q.get("link") else ""))
            break
        qs = missed

if __name__ == "__main__":
    main()

相关技能