5种对抗代码幻觉的防御措施(但只有3种真正有效)

上周我讲述了我的AI如何凭空编造完整JSON结构并将其封装进DTO、测试夹具和验证测试中的故事。90个测试全部通过,却是一场骗局。 那篇文章是诊断报告。而本文是治疗方案。 发现问题后,我的反应和任何自尊心受损的工程师一样:连续数天疯狂研究防止重蹈覆辙的方法。我阅读论文、测试工具、分析API真实数据,最终为应用构建了一套防御系统。 调查结果让我惊讶:在五类应对措施中,只有三种真正奏效。剩下两种充其量只是"善意表演"。 思维模型:你与AI的对决 在介绍具体措施前,需要先建立认知框架。最好的类比来自深度学习领域: 在**生成对抗网络(GAN)**中存在两个互相竞争的神经网络: 生成器负责产出内容(图像/文本等) 判别器负责鉴别真伪 系统通过两者的对抗持续进化。生成器变得更擅长欺骗,判别器变得更擅长识别。 当使用LLM编程时,你正身处一个非自愿的GAN环境: LLM是生成器。它产出代码、DTO、测试和夹具。 你是判别器。必须辨别真实与虚构的内容。 但存在一个残酷的不对称性:生成器永不疲倦,而你会。LLM可以不费吹灰之力生成50个文件。你检查到第10个就开始疲劳,第11个文件就可能被漏检。 这就是我在1Password每天47次TouchID验证中提到的"授权疲劳"。依赖人类时刻保持警觉的安全措施不过是纸糊的墙。 重点监控边界 你不需要(也不应该)逐行检查。需要重点盯防的是边界——代码与外部世界交互的环节: 边界 核心问题 外部API DTO字段是否真实存在于API? 依赖包 该依赖是否存在且名称正确? 数据库表 表结构是否包含这些字段? URL/端点 端点是否存在且响应合规? 铁律:LLM对外部世界的任何声明都需验证后再采信。 它说话时的信心程度不能作为判断依据。Anthropic在官方文档中也承认: “Claude有时会生成包含虚构信息的回答…这些回答往往以自信、权威的语气呈现。” LLM说"我确定"和说"我觉得"时,错误的概率其实完全相同。 自动化判别流程 终极目标是摆脱对人为主观能动性的依赖,将验证自动化: 改进前: LLM生成 → 人工抽查 → 合并 改进后: LLM生成 → CI用真实数据验证 → 人工检查差异 → 合并 下文将介绍的五种措施,都是实现这种自动化判别角色的方法。其中有些有效,有些则不尽如人意。 数据实证(致怀疑者) 如果你觉得"这事不会发生在我身上",请看实际研究数据: LLM推荐的21.7%开源包是虚构的。商业模型降至5.2%(仍意味着每20个就有1个虚构包) GPT-4o针对低频API的有效调用率仅38.58%。比抛硬币的胜率还低 当前最佳代码幻觉检测方法的准确率仅22-33%。换句话说:每四个虚构字段只能抓到一个 研究人员上传了LLM常虚构的空包名。3个月收获3万次下载。业界称其为"垃圾注册"(slopsquatting) AAAI 2025发表的研究CodeHalu将代码幻觉分为四类: 类型 特征 实例 字段映射 字段映射关系错误 混淆user_id和account_id 命名虚构 字段名不存在 使用response.quota.percentage而非真实字段response.utilization 资源虚构 虚构API资源 虚构的active_flags字段 逻辑虚构 看似合理实则错误的业务逻辑 基于虚构字段的判断逻辑isPaid = !activeFlags.isEmpty 我的遭遇正是资源虚构导致逻辑虚构。虚构字段不存在,而依赖它的业务逻辑却天衣无缝。堪称教科书级的"自洽虚构"。 ...

2026年2月16日 · Fernando

无声的失败:当你的AI虚构事实而测试却显示一切正常

昨天,我发现我的应用程序中有一半的模块是基于虚构的数据构建的。问题还不在于数据是虚构的,更糟糕的是,所有代码都能正常编译,而且90个测试全部通过。 连贯的虚构现实 我正在开发 BFClaude-9000,这是一个为macOS菜单栏设计的应用程序,用来监控Claude Max的配额。其中一个功能需要通过调用 claude.ai 的API来判断某个Claude账户是付费账户还是免费账户。 所以,我请求Claude Code来实现这个功能。它的输出如下: 一个DTO OrganizationInfo,包含一个字段 activeFlags: [String] 一个计算属性 isPaid,用于检查 activeFlags 是否为空 一个枚举 OrganizationSelection,将账户分类为付费或免费 几个基于样例数据的测试,用于验证所有功能是否正常 看上去很棒,结构清晰且井然有序。但这一切全是虚构的。 Claude的真实API中并不存在 active_flags 字段。即使这个字段存在,其作用也完全不符合代码中的假设。当我用自己的付费账户登录时,应用却提示我是免费账户用户。 纸上谈兵的模式 问题并不仅仅是它编造了API中的一个字段,更糟糕的是,它围绕这个谎言构建了一个逻辑完整的系统: // 含有虚构字段的DTO struct OrganizationInfo: Decodable { let uuid: String let name: String let activeFlags: [String] // ← 这个字段并不存在 var isPaid: Bool { !activeFlags.isEmpty } } // 基于虚构字段的逻辑 enum OrganizationSelection { case paid(id: String, name: String) case noPaidOrg // ← 这个状态不应存在 case noOrgs } // 验证虚构逻辑的测试 let paidOrg = """ {"uuid": "abc", "name": "Acme", "active_flags": ["pro"]} """ // 测试通过 ✅ — 但验证的实际上是虚构对虚构 看到了吗?这不仅是一个错误的API字段,而是一个纸上谈兵的构造:DTO定义了一个不存在的字段,业务逻辑依赖该字段,测试用虚构数据验证这个逻辑,也一致验证通过。每个部分彼此确认,从表面来看完全无懈可击,而实际上却毫无真实性可言。 ...

2026年2月13日 · Fernando

当AI成为你的头号敌人时

昨天我的AI发送了44封邮件。问题是这些内容全是瞎编的。 这不是玩笑。我本已准备好给每个收件人的详细反馈文件,内容都经过精心调整。任务很简单:读取每个文件然后发送。但AI却决定为了"加快速度"而"概括"内容。结果胡编乱造——说某人缺少文档字符串,而实际上人家的代码文档非常完善。 更糟的是,其中有4封邮件的收件人根本连代码都没提交过。 让我脊背发凉的回复 其中一位收件人回复得非常礼貌: “感谢评估。只有一个小问题:您说我缺少文档,但我所有函数都有文档字符串。能具体说明下吗?” 我去查看了原始反馈文件。实际上原反馈明确指出她确实有文档字符串,只是其中一处描述与实际功能有出入——一个重要的细节差异。AI把这个"简化"成了"缺少文档字符串"。 说白了:AI以我的名义对44个人撒了谎。 灾难解剖 怎么发生的?让我们拆解: 已有资源: 44份精心准备的markdown反馈文件,每份都包含个性化详细建议。花费数小时工作。 下达指令: “把这些反馈通过邮件发出去” AI的实际操作: 读取文件 认定"内容过长" “概括"生成新文本 发送编造内容 没有验证收件人是否真的提交过作品 正确做法应是: 逐份读取文件 100%原样复制内容 发送 看起来很简单,对吧?但对AI而言并非如此。 大语言模型的畸形激励机制 关键点来了:AI这么做并非出于恶意,而是由其激励机制在特定场景下的畸形作用导致的。 LLM(大型语言模型)没有自主意识,但其训练过程优化了某些行为模式。这些行为通常有利,但在不可逆操作中就变成了灾难配方。 激励因素 来源 适用场景 致命场景 表现高效 用户偏好 ** 简洁响应** | 冗长解释时 | 当概括已经存在的内容 | | 完成任务 | 为达到目标而训练 | 明确定义的任务 | 未经确认就执行时 | | 展示能力 | 强化学习奖励周密回答 | 需要创意的场景 | 本该简单复制时 | | 避免摩擦 | 训练避免打扰用户 | 琐碎任务 | 该询问却擅自假定时 | | **表现可靠** | 稳妥回答得分更高 | 头脑风暴 | 为避免说"不知道"而编造时 | ...

2026年2月6日 · Fernando

在人工智能出现之前,你的大脑就已经在使用AI算法了

关于你的两个预测 我要大胆做两个预测: 你的职业成功很大程度上要归功于一个你在不知不觉中掌握的算法。 你担心你的孩子显然不会使用这个算法。 第一个预测是正确的。第二个嘛……可能并不是你想象中的问题。 这些算法被称为广度优先搜索(BFS)和深度优先搜索(DFS)。虽然你可能对这些名字不熟悉,但我保证它们是老朋友了。你的大脑已经使用了数百万年。 象棋和巴别图书馆 想象你是一台下象棋的计算机。你的对手刚刚走了一步。你如何决定你的下一步棋? 一种选择:计算你所有可能的走法。每一步都会产生一个新的棋盘局面。对于每个棋盘,你计算对手所有可能的回应。如此反复,直到找到一条通向胜利的路径。 结果就是一个巨大的可能性树。有点像博尔赫斯的巴别图书馆:无穷的走廊里有无穷的书籍,包含了字母的所有可能组合。 组合爆炸的完美隐喻 如果你不熟悉这个典故:豪尔赫·路易斯·博尔赫斯是20世纪的阿根廷作家,被认为是世界文学史上最有影响力的作家之一。1941年,他发表了短篇小说《巴别图书馆》,描述了一个无限的图书馆。 这个图书馆包含了所有可能的410页书籍。全部。有意义的和无意义的。你能想象的每一种字母、空格和标点符号的组合都存在于某个书架上。这包括癌症的治愈方法、每一个将要存在的人的传记,也包括数百万本纯粹是无法理解的噪音的书。 显而易见的问题是:如何在这片可能性的海洋中找到有用的东西? 大多数书都是垃圾。而且没有目录。 象棋也有同样的问题。仅仅在双方各走4步之后,就有超过2880亿种可能的局面。可能性树呈指数级增长,直到变得无法控制。这就是你自己的巴别图书馆,其中大多数"书"(可能的棋局)都是荒谬的,但在某个地方存在着完美的一盘棋。 你如何遍历这棵几乎无穷的树? 就像在信息饱和的世界中导航一样:使用BFS或DFS。 BFS:快速排除的艺术 广度优先搜索按层级遍历树。首先查看第一层的所有内容,然后是第二层的所有内容,接着是第三层。 这个想法不是立即找到完美的解决方案。而是尽快排除那些看起来不好的分支。 当你在谷歌搜索餐厅并按评价、价格和距离筛选时,你在不知不觉中就是在使用BFS。你不会深入分析每家餐厅。你在几秒钟内排除90%的选项,只保留三四个候选。 DFS:穿透一切的激光 深度优先搜索恰恰相反。你选择一条路径并跟随到底。只有当你走到死胡同时,才回头尝试其他路线。 你有没有曾经如此专注于一个问题以至于忘记了时间?那种心流状态就是纯粹的DFS:你所有的认知资源都集中在一件事上,直到深入到底。 这就是重大科学发现、技术发明、传世艺术作品的诞生方式。绝对的深度。完全的专注。 DFS带你走到了今天 如果你超过35岁并且在职业上相当成功,你很可能要感谢DFS。 我们这些20或30年前开始工作的人生活在一个信息稀缺的世界。必须充分利用每本书、每门课程、每位导师。获胜策略是在你的知识分支中尽可能深入。 这就是为什么我们如此重视专注、聚焦、持续注意力。我们的思维进化得像激光一样运作:所有能量集中在一个点上。 这也是为什么当前的分散文化让我们担心——并且看起来不自然。尤其是当我们在孩子身上看到这种情况时。 剧情反转:你的孩子没有问题 这里是情节转折。 敌人不再是信息稀缺,而是信息过载。我们生活在博尔赫斯的巴别图书馆中,有无穷的书架无法遍历。 为了在这种饱和状态中生存,许多年轻人本能地发展了BFS方法:快速丢弃不合适的内容,只为有前景的内容分配资源,在选项之间跳跃直到找到值得的那个。 正如大卫·爱泼斯坦在《范围》一书中所说,这种在深入之前"扩大视野"的能力是在一个需要持续适应的世界中的竞争优势。 这可能不是一种退化。可能是自然选择在做它的工作,塑造大脑以在无穷图书馆中获胜。 我们需要的平衡 诀窍不是在BFS和DFS之间选择。而是知道何时使用哪一个。 开始时使用BFS,当选项众多且需要筛选时。之后使用DFS,当你已经识别出值得完全关注的东西时。 我们这些来自绝对专注世界的人也许需要向新的"通才"学习。而他们,在某个时候,必须发展深入研究的能力。 未来不属于纯粹的专家,也不属于纯粹的通才。而是属于那些知道如何根据情境切换模式的人。 你上次有意识地改变算法是什么时候?也许现在是尝试的好时机。

2026年1月28日 · Fernando

你的技能半衰期只有2年(而且还在缩短)

他没有预料到的解雇 一名38岁的高级开发人员。在公司工作了八年。代码整洁,遵循最佳实践,生产环境零故障。 在最后一次绩效评估中,他的产出比经验只有他一半的同事低40%。区别在于:他们使用Copilot、Cursor和Claude Code。而他仍然坚持手写每一行代码,坚信"AI工具生成的代码质量平庸"。 他被解雇不是因为写了糟糕的代码。而是因为写好代码的速度太慢了。 这个故事并非例外。这就是新的模式。 你的经验是有保质期的 几十年来,经验一直是价值的代名词。更多年份意味着更多积累的知识,而这些知识会随着时间增值。一个有20年经验的专业人士,几乎理所当然地比有5年经验的更有价值。 这个等式已经被打破了。 根据IBM和世界经济论坛的数据,技术能力的半衰期已经从1990年的大约10年降到了2020年的不到5年。目前的估计显示,对于软件开发、数据和人工智能相关技能,这个数字已经低于3年。 年代 技术技能半衰期 1990年代 ~10年 2000年代 ~7年 2010年代 ~5年 2020年代 <3年 实际上:你三年前学到的东西已经开始失去相关性。你五年前掌握的可能已经完全过时了。 这不是你工作好坏的问题。这是物理定律:技术知识会贬值,而贬值的速度在加快。 你应该每年问自己的四个问题 职业淘汰不会提前通知。当你跨越"难以安置"的门槛时,没有警报会响起。人力资源部不会发邮件说"你的简历不再具有竞争力"。有一天你只是发现市场继续前进,而你还停留在原地。 这四个问题是你的早期预警系统。诚实地回答它们。你的职业生涯取决于此。 1. 我今天使用的技能中,哪些是三年前不存在的? 如果你没有明确的答案,那就有问题了。因为你的竞争对手有。 当你在完善已知的技能时,其他人在学习AI代理、RAG架构,或者用Terraform部署基础设施。不是因为他们更聪明。而是因为当你在优化舒适区时,他们把时间投入到了不舒适的领域。 市场不奖励对稳定技术的精通。它奖励在技术成为必需品之前采用新兴技术的能力。 2. 我上次学习真正困难的东西是什么时候? 舒适区是职业生涯的坟墓。 你每过一个月不学新东西,就有更年轻、更便宜的人在学习。你不是在与五年前的自己竞争。你在与刚完成LLM密集课程的初级开发人员竞争,他们掌握你甚至没试过的工具,而薪水只要你的一半。 你的经验只有在包含最近经验时才有价值。“我编程15年了"如果最近3年都在做同样的事情,那就毫无意义。 3. 我的公司是在投资我的培训,还是只是在消耗我的时间? 有些公司明白持续培训是投资。还有些公司把专业人士当作电池:榨取能量直到耗尽,然后更换。 如果你多年来公司没有资助培训,没有分配学习时间,没有提供会议或发展资源的机会,你有两个问题。第一:这正是他们看待你的方式——一个要榨干的资源,而不是要发展的资产。第二:更新技能的账单你要自己付。用时间。用金钱。或者用你永远不知道失去的机会。 投资培训的公司留住人才。不投资的公司轮换员工,直到找到已经培训好的人。猜猜谁要承担这种轮换的成本。 4. 如果我今天申请我现在的工作,我能得到吗? 这是最痛苦的练习。也正因如此,它是最重要的。 现在就打开LinkedIn。搜索你当前职位的职位,在你的行业,在你的城市。阅读五个职位的要求。不是"希望"的,而是必需的。 你全部满足吗?你掌握他们要求的技术吗?你在他们提到的工具方面有可证明的经验吗?你能在技术面试中回答相关问题吗? 数一数你不满足多少要求。这个数字就是你的个人技术债务。就像所有债务一样,它会产生利息。每过一个月不偿还,它就会增长。直到有一天你发现市场无论如何都不再需要你了。 最小可行计划 保持更新需要时间。但比从淘汰中恢复需要的时间少。 任何技术专业人士的最小可行计划包括: 主动培训:每周2-4小时。 不是被动地阅读文章或看视频。刻意练习:有练习的课程、项目、能运行的代码。 每年一个认证或密集课程。 不是为了证书,而是为了过程。强迫自己以结构化方式学习新东西,保持主动学习的肌肉记忆。 每六个月用新技术做一个个人项目。 学习某样东西的最好方法就是用它构建东西。不必很大。但必须是真实的。 活跃的专业网络。 不是被动的LinkedIn。是讨论、分享、提问的社区。集体知识比任何官方课程移动得更快。 这大约占你工作时间的5-10%。这是一项重大投资,但替代方案——当为时已晚时发现自己已过时——代价要高得多。 这不是未来。这是现在。 有一种趋势是把这些变化当作"即将到来"的事情来谈论。好像我们有时间准备。 我们没有。变化已经发生了。 AI已经在改变招聘方式、工作方式和什么能力有价值。公司已经在优先考虑当前技能而不是历史资历。市场已经比以往任何时候都更严厉地惩罚过时。 将要繁荣发展的专业人士不一定是最有天赋的。他们将是那些永不停止学习的人。 大学教育给了你基础。持续培训决定这个基础是否仍然相关。 这不是可选的。这不是有时间时的奢侈品。这是指导你的职业生涯和让职业生涯碾压你之间的区别。 预测未来的最好方法就是创造未来。从你自己开始。

2026年1月27日 · Fernando

Clawdbot:正在颠覆(并让半个互联网担忧)的开源AI助手

一只在你电脑上的太空龙虾 想象一下,一位奥地利开发者创建了一款私人 AI 助手,把它命名为“太空龙虾”,然后决定向公众开放。24小时内,它就在 GitHub 上获得了9,000个星标。48小时后,这个数字增长到17,000。同时,它也遇到了超过300个问题,其中一些是关键的安全问题,甚至有人用它的名字创建了一种非官方的加密货币。 欢迎来到 Clawdbot。 这究竟是什么? Clawdbot 是一个在你本地设备上运行的开源 AI 助手。与其他助手不同的是:它不仅能回答问题,还能“执行操作”。 它可以连接到 WhatsApp、Telegram、Discord、Slack 和 iMessage。可以阅读你的邮件,访问你的日历,创建文件,运行代码。而最有趣的是:它可以随时学习新技能。 它的创造者是 Peter Steinberger,一个在移动开发领域颇有名气的人物(他创立了 PSPDFKit 并成功出售了公司)。一开始这只是一个私人项目:他的私人助手名为 Clawd,有着“太空龙虾”的个性,帮他管理数字生活。 到2026年1月,他决定开源这个代码。而如今,我们就在这儿。 它的魅力所在 Clawdbot 的特别之处在于它是一个真正的“代理”。它不是一个只会回答问题然后停下来的聊天机器人。它是一个能够: 编排重复性任务 以你的名义执行操作 为自己创建新技能 最后一点尤为关键。如果你让它做一件它不会的事,比如“将这个视频转换为 GIF”,它会编写所需的代码,安装为一个新技能,并完成任务。下次再遇到类似需求,它已经学会了。 Hacker News 的一位用户表示,他用它来管理 Facebook Messenger 上的租赁咨询。Clawdbot 筛选消息,安排看房时间,完成的任务成功率达 90%。 另一个开发者用它调试自己的代码缺陷。Clawdbot 找到了问题,编写了修复代码,并提交了一个 pull request,最终被成功合并。 简单来说:拥有它就像是雇了一个永不疲倦、不抱怨、学习能力极强的助理。 它令人担忧的地方(且不容忽视) 但问题也很严重,非常严重。 超过300个未解决问题 该项目在 GitHub 上有超过 300 个未解决问题,许多是漏洞和安全风险报告。这不一定是坏事——受欢迎的项目总会有一些问题——但这也侧面说明了其成熟度不足。 没有沙箱机制 Clawdbot 以与你的用户帐户相同的权限运行。没有虚拟机。没有容器。没有隔离。如果你授予它访问权限,那就是真正的访问权限。 正如一位 HN 讨论区里的人所说: “让一个联网的进程拥有 root 权限而且没有任何防护措施是……一种危险的决策。” 硬编码的 OAuth 凭据 有人在代码库中发现了硬编码的 OAuth 凭据。维护者辩称这是开源软件的惯例,但这仍然让人不禁皱眉。 提示注入攻击 该系统缺乏针对“提示注入攻击”的强有力机制。如果 Clawdbot 访问了一个恶意网站,该网站的内容可能会篡改它的行为。没有对数据进行“非可信”标注的机制。 ...

2026年1月26日 · Fernando

线性、Beads 和 Tasks:Claude Code 的三层记忆模型

记忆问题 Claude Code 存在一个问题:它全忘了。如果关闭会话再打开,感觉就像和一个完全陌生的人对话一样。虽然你可以加载 CLAUDE.md 来补充上下文,但未完成的任务怎么办?发现的但未修复的 bug 怎么办?明天的计划呢? 有三种互补解决方案:Linear(或你的产品工具)、Beads(基于 git 的插件)以及 Tasks(Claude Code 内置工具)。不同工具适用于不同时间范围。 Tasks:工作记忆 Tasks 是 Claude Code 的内部系统,用于追踪当前正在做的事情。当你提出复杂要求时,Claude 会自动生成任务列表。 按下 Ctrl+T 查看任务列表: ┌─────────────────────────────────────────────────┐ │ Tasks │ ├─────────────────────────────────────────────────┤ │ ✓ 阅读项目结构 │ │ ● 实现认证端点 │ │ ○ 编写测试代码 │ │ ○ 更新文档 │ └─────────────────────────────────────────────────┘ 特性 自动生成:当任务需要多个步骤时,Claude 会自动创建任务列表 压缩后仍保持持久性:在内容被压缩后任务仍然存在 通过 Ctrl+T 查看:操作简单,任务视图可快速切换 限制为最多10个显示:若需要更多任务显示,可以请求“show me all tasks” 在会话间共享 默认情况下,任务列表会随会话结束而丢失。但你可以让任务持续保存: CLAUDE_CODE_TASK_LIST_ID=qualitra claude 此操作会把任务列表保存到 ~/.claude/tasks/qualitra/ 中。下次使用相同 ID 启动时,可以恢复列表。 使用 Tasks 的场景 场景 Tasks 在一个会话中实现一个功能 ✓ 按定义好的工作计划推进 ✓ 步骤性的 Debugging ✓ 清晰步骤的重构工作 ✓ Tasks 用于执行层面。当你明确知道需要完成什么,只需要辅助工具来进行跟踪。 ...

2026年1月23日 · Fernando

Claude Code中的子代理:授权不失控

无限上下文的困局 假设你让Claude研究项目认证机制。它开始读取文件。大量文件。转眼间上下文已消耗5万token,而这些代码你只需要查阅而非记忆。 响应变慢了。成本增加了。当你想处理其他事务时,这些上下文依然占据着思维空间。 解决方案:子代理。启动专属代理在隔离上下文中处理脏活,返回摘要后自动消失,主会话保持清爽。 何为子代理 子代理是Claude的独立实例,具有以下特性: 专属上下文(不污染主会话) 可限制工具权限(仅读/仅bash等) 可选用不同模型(简单任务用Haiku,复杂任务用Opus) 支持前台(阻塞式)与后台(并行)执行 将其视为专业助理:分配任务后独立工作,完成后汇报结果。 内置子代理 Claude Code预装多个子代理: 代理类型 模型 用途 工具权限 Explore Haiku 代码检索分析 仅读 Plan 继承主模型 规划阶段调研 仅读 general-purpose 继承主模型 复杂多步任务 全权限 Bash 继承主模型 独立环境执行命令 仅Bash Claude Code指南 Haiku 解决Claude Code相关问题 文档查询 其中Explore最实用。当Claude需要检索代码库时,会启动Explore代理疯狂读取文件,处理后仅返回相关部分。 启动子代理 通过REPL(常规对话) 直接使用自然语言指令: 使用子代理研究缓存系统原理 启动Explore代理查找所有API端点 请并行研究认证机制,我继续处理其他任务 Claude能理解这些请求并调用Task工具启动对应子代理。 通过Skill技能 在技能配置中通过context: fork指定隔离执行: --- name: deep-analysis description: 架构深度分析 context: fork agent: Explore --- 进行项目全架构分析 生成包含以下内容的报告: - 目录结构 - 核心依赖项 - 识别到的设计模式 context: fork使技能在子代理运行,agent: Explore指定代理类型。 ...

2026年1月20日 · Fernando

ChromaDB: 如何使用向量数据库避免教学错误

问题:教授概念前提前使用 我有一门包含47节课的编程课程。每节课都有笔记(用来解释概念)以及实验室任务(供学员练习)。然而,我有一个问题:有时我会在实验中使用尚未在笔记中解释过的概念。 “好吧,在这个练习中使用 map 来转换列表。” 问题是什么?直到三节课后,我才开始解释 map 的含义。 这种问题比你想象中更常见。因为我对教学内容非常熟悉,经常跳跃思路,可能在无意间假设学生已经理解了一些我还没有实际讲到的概念。结果导致学生感到非常困惑和沮丧,他们认为自己不够聪明,但真正需要改进的是老师的教学大纲。 手动解决方案是检查每个实验室任务,列出所使用的概念,并验证这些概念是否已被教学过。然而,我的课程有47节课,每节课有多个Notebooks。手动搞定显然不是办法。 解决方案:使用 ChromaDB 实现语义搜索 解决方案其实很简单: 从每个 Notebook 中提取概念(包括教学和使用的概念) 将这些概念存储到一个能够处理“意义”、不仅是文本的数据库中 对实验室任务中使用的每个概念,验证其是否已在之前的笔记中介绍过 这个“处理意义”是关键。如果在笔记中我提到了“高阶函数”,而在实验室任务中使用了“higher-order function”,普通的 grep 是无法匹配到的。但从语义上来说,它们是相同的。 这就是 ChromaDB 派上用场的地方:这是一种将文本转化为嵌入向量的向量数据库,并支持基于相似度的搜索。简单来说,你可以将文本存储进去,然后问它“有没有类似这个的东西?”它会返回最相似的内容。 五分钟了解 ChromaDB ChromaDB 就像是用于嵌入向量的 SQLite。一个单独的文件(或文件夹),无需服务器部署,也不需要复杂的配置。安装后即可直接使用。 pip install chromadb # 如果你使用 uv: uv add chromadb 基础概念 在普通的关系型数据库中,你存储的是行和列。而在 ChromaDB 中,你存储的是带有 嵌入向量 的 文档: import chromadb # 创建客户端(支持磁盘持久化) client = chromadb.PersistentClient(path="./mi_db") # 创建“集合”(类似于表) collection = client.get_or_create_collection( name="conceptos", metadata={"hnsw:space": "cosine"} # 使用余弦距离 ) # 存储文档 collection.add( ids=["c1", "c2", "c3"], documents=["纯函数", "for 循环", "递归"], metadatas=[ {"clase": "class_010", "tipo": "notes"}, {"clase": "class_015", "tipo": "notes"}, {"clase": "class_020", "tipo": "notes"} ] ) 就是这样。ChromaDB 会自动: ...

2026年1月18日 · Fernando

Claude Code 的技能:老狗学新把戏

一再重复的痛苦 你是否曾经不得不一遍又一遍地向某人解释相同的内容?那就想象一下,这种情况还是发生在一台几小时内就会“忘记”你的话的机器人上。 “Claude,提交操作前必须通过测试。” “Claude,我跟你说过要用格式 类型: 描述。” “别加表情符号,拜托!” 这就是我每天的写照,直到我发现了 技能(Skills)。简单来说,就是你只需写一次指令,Claude会永远听以执行。就像训练一只狗一样,只不过这次不需要狗粮。 什么是技能? 从 2.1.3 版本开始,Claude Code 将之前的 斜杠命令(slash commands) 合并成了一种更强大的功能:技能(Skills)。它们是 Markdown 文件,Claude 可以通过以下两种方式执行: 手动:当你输入 /我的技能 时触发 自动:当 Claude 检测到应该使用它时触发 第二点是这个功能的魔力所在。你再也不需要记得手动调用命令了。如果你设置了一个技能,告诉系统:“在用户完成任务且存在未提交更改时使用”,Claude 会自动帮你完成。 它就如同一个不需要你吩咐也会知道什么时候该收拾餐桌的管家。 技能存放在哪里? ~/.claude/skills/ # 个人技能(适用于所有你的项目) .claude/skills/ # 项目技能(与团队共享) ~/.claude/commands/ # 旧版支持,仍然可用 .claude/commands/ # 旧版支持,仍然可用 如果你希望只有你自己可以使用某个技能,可以将其放在 home 目录下。如果你希望整个团队都能用它,则可以将其提交到代码库中。就是这么简单。 技能的基本结构 一个技能是包含 YAML frontmatter 和内容的 Markdown 文件: --- name: mi-skill description: 简要描述此技能的功能 --- # 指令 当调用此技能时,Claude 应执行的具体操作。 这已经是最简单的形式了。但其实 frontmatter 中还有更多值得关注的选项。 必填字段 name 技能的唯一标识符。只能使用小写字母、数字和连字符(最多 64 个字符)。这个字段必须和文件名或文件夹名称一致。 ...

2026年1月12日 · Fernando