回顾解决该问题的会话。生成两个文件:LEARNED.md 和 learned_quiz.py(一个终端测验程序)。
- 识别会话。 使用最近的聊天记录找到与问题匹配的会话。如果有多个可能的会话,询问用户选择哪一个。如果该会话属于某个项目,还需审查该项目中的其他聊天记录。
- 读取整个会话,而不仅仅是摘要。 记录人类和AI在问题解决前各自遗漏的地方。同时记录人类不得不凭信任接受、询问超过一次或理解错误的概念:这些概念需要深入探讨。
- 在撰写前研究链接。 每条经验教训至少找到一个链接。针对每条人类教训以及步骤2中的每个概念,找到1到3个深入阅读链接,从基本原理解释背景。优先顺序为:官方文档或规范、供应商应用说明或手册、知名教程或教科书,然后是信誉良好的博客或问答。使用WebSearch,然后通过WebFetch打开每个链接以确认其可访问且涵盖要点。丢弃任何失败或离题的链接。切勿虚构URL。
- 编写LEARNED.md,包含以下部分,按此顺序:
- 发生了什么: 3到5句话,加上状态(已解决或未解决)。如果未解决,列出未完成项。
- 经验教训: 分为人类、AI和共享三类。每条教训给出要点、遗漏的内容、一句总结的教训,以及一个链接(注明来源)。对于需要背景知识的每条人类教训,在其下添加“深度阅读”子列表:每项为 标题、来源以及一行说明它教授了什么以及为何在此处有用。
- 测验问题: 3到5个关键问题,标题为“测验问题”,后附答案。注意完整的问题集在 learned_quiz.py 中。
- 链接: 使用的所有链接,按教训分组,注明来源。说明链接在运行日期已验证,使用前应再次确认。
- 建议的一次性提示: 一个简洁的提示,如果当初使用,本可避免本会话中的问题。
- 标记断言。 将未经验证的断言标记为“未验证”。将从搜索结果中获取的断言标记为“已报告”,并链接来源。
- 不要将猜测作为发现呈现。 如果问题的原因未确认,请如实说明。
- 根据以下模板编写 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,并修复任何错误。检查每个答案索引指向正确的选项。
- 保持LEARNED.md简洁。 两个文件中均不要使用长破折号。
- 通过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()