ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

让 Coding Agent 讲清代码:show-me Skill 的设计与实现

让 Coding Agent 讲清代码:show-me Skill 的设计与实现 Coding Agent 写完代码后最让人头疼的往往不是代码跑不起来而是它讲不清楚自己到底做了什么以及为什么这么做。这个问题的本质不是模型能力不足而是 Agent 缺少一套稳定的表达范式。Matt Pocock 这类长期和 TypeScript、开发效率工具打交道的技术人之所以会认可 show-me 这类 Agent Skill正是因为它的切入角度很实际先让 Agent 把代码讲明白再去讨论优化和重构。本文会围绕 show-me 的设计思路拆解 Skill 和 Agent 的边界并给出一份可以直接落地的 SKILL.md 实现让 Coding Agent 从“只给结论”变成“讲解过程”。show-me 不是一个复杂框架它本质上是给 Coding Agent 加了一条“输出纪律”在展示代码之前先交代它理解到的需求、选择的设计方案、关键代码的作用以及验证方法。这样做的价值在多人协作、代码评审、接手旧项目和学习开源代码时尤其明显。只需要一个结构良好的指令文件就能让 Claude、Cursor、Codex 或自建 Agent 在回答代码问题时输出质量明显更接近一个有经验的开发者。1. Agent Skill 到底是什么和 Agent 的边界在哪里1.1 Skill 不是 Agent而是 Agent 的“行为规范包”先把基础概念对齐。Agent 是一个能接收任务、规划步骤、调用工具、生成代码并执行验证的完整运行体。它由模型、工具、上下文策略和指令组成。Skill 则是插入到 Agent 上下文中的一组结构化能力描述通常是一个 Markdown 文件或文件目录内容包括触发条件、执行流程、输出模板、边界说明和示例。用工程类比来理解Agent 是“工人”。Skill 是“工作手册”。工具如 grep、read、终端是“工具箱”。Model 是“工人大脑”。工人可以在没有手册的情况下干活但干出来的结果不稳定遇到复杂任务时容易漏步骤。Skill 存在的意义就是让 Agent 在特定场景下按约定顺序输出不靠运气。show-me 就是一个典型的表达类 Skill它不改变 Agent 的编码能力只改变 Agent 的沟通方式。1.2 Skill 和 Agent 的区别一张表说清维度AgentSkill定义能感知任务、规划、执行、验证的完整系统一段供 Agent 调用的行为规范和知识包是否可独立运行是缺 Skill 也能工作只是表现不稳定否必须依赖 Agent 加载执行内容形态配置、工具、模型调用、状态管理组合通常是 Markdown 文件可附带参考示例关注点完成目标规范“如何完成”尤其是输出方式变更影响影响整个执行链路只影响加载了该 Skill 的任务生命周期长期运行、持续对话按触发条件介入任务结束即退场这个边界在实际使用中非常重要。如果团队里通常说“Agent 做项目是不是需要很多个 Skill”答案往往是不需要刻意追求多2 到 5 个核心 Skill 覆盖主要工作流即可。Skill 太多会导致互相抢触发、上下文膨胀、输出结构冲突。show-me 这类 Skill 的特点是通用性强适合作为基础 Skill 常驻。1.3 为什么通用提示词不够需要把“讲代码”固化成 Skill有人会问我已经在 Prompt 里写了“请解释代码”为什么还要单独做一个 Skill原因有四点通用提示词没有输出结构。只说“解释代码”Agent 可能回一段话、一个表格、几段注释形式完全随机后续不好复用。通用提示词容易被任务覆盖。当任务里同时有“修改代码”和“解释代码”时Agent 通常会优先完成任务修改解释被压缩成一句“已按要求完成”。质量基线无法统一。同样一段代码这次讲得详细下次讲得敷衍团队协作时很难形成稳定文档。跨工具迁移成本高。每个工具都有自己的主 Prompt但如果把 skill 写成独立文件换工具时可以直接迁移。show-me 的价值就在这里它把“如何讲清楚一段代码”这件事固化成模板Agent 只要命中触发条件就必须按模板输出。结果就是每次讲解的质量都有最低保障。2. show-me 的设计逻辑不直接给代码而是交替给“解释”和“证据”2.1 普通 Agent 回复和 show-me 回复的差异先看一个最典型的场景。用户给出一个 Python 脚本要求理解它的工作方式。普通 Agent 回复通常是这个脚本是一个文件监控程序使用 watchdog 监听目录变化发现新文件后调用 process_file 处理。这句话没错但信息密度极低读者无法知道它依据什么得出这个结论也无法判断结论是否可靠更无法把这段理解和实际代码对应起来。show-me 模式的回复会是另一种结构。下面是一个实际输出的骨架一句话结论 这是一个基于 watchdog 的目录监听脚本核心职责是发现新 CSV 文件后自动清洗并写入 SQLite 数据库。 关键假设 1. 监听目录是 ./data/incoming递归监听子目录。 2. 只处理后缀为 .csv 的文件。 3. 处理失败时不会删除原文件方便重试。 分块讲解 1. configure_watcher() 对应第 12-20 行。它创建 Observer 并调度 monitor_handler。 这里选择 Observer 而不是 loops 的原因是... 2. monitor_handler 对应第 22-35 行。它继承 FileSystemEventHandler覆盖了 on_created。 注意这里没有覆盖 on_moved因此重命名文件不会触发处理。 关键证据 - 第 28 行的后缀判断是核心过滤逻辑修改它会直接影响监听范围。 - 第 40 行 catch 到异常后只写日志不终止程序所以单文件失败不会拖垮整个进程。 建议的验证方式 - 在 ./data/incoming 下放一个 1.csv观察日志出现 start handle 1.csv。 - 连续放两个坏文件确认进程不退出。两相对比差距不是文采而是可验证性和可审计性。show-me 把 Agent 的结论和代码行号、关键分支、异常策略绑定在一起读者可以直接跳过去检查而不是无条件相信。2.2 show-me 的核心输出结构五要素一个成熟的 show-me Skill 输出模板通常包含五个固定要素。这个结构会直接影响 Agent 的讲解顺序所以模板设计要先于实现。要素解决什么问题必须包含的内容一句话结论先让读者建立整体认知避免一开始陷入细节这段代码是什么、做什么、用什么技术关键假设说明讲解基于哪些前提防止误读运行环境、目录约定、输入格式、分支策略分块讲解把代码拆成可对齐的功能块函数名/类名、对应行号、功能职责关键证据证明讲解结论来自代码而非猜测具体行号、判断条件、异常处理分支验证方式告诉读者怎么确认自己的理解构造输入、运行命令、观察日志、预期结果2.3 为什么“先结论、后证据、再验证”这个顺序不能乱这个顺序是 show-me 最重要的纪律。它的原理是认知负荷管理。如果 Agent 一上来就直接逐行讲代码读者要先记住每行代码的作用然后在最后才能拼图出整体功能。这对复杂函数来说负担很大。反过来如果先给结论读者脑子里会建立一个先行模型后面阅读每个代码块时会主动把代码映射到结论上理解速度和准确率都会提升。同理证据部分必须在“讲解”之后不能混在一起写。混写会导致两个问题一是段落层次不清晰读者分不清哪些是结论、哪些是代码事实二是 Agent 容易在长篇输出中遗漏行号导致引用失真。show-me 强制把证据抽出来就是为了产生“可校验的引用”。2.4 指令要写“为什么”而不是只写“做什么”很多 Skill 文件失败是因为整篇都是祈使句“请解释代码”“请给出行号”“请总结”。Agent 执行时会困惑于优先级和边界。show-me 之所以有效是因为它在关键位置写清了“目的”。例如模板里不能只写“请给出验证方式”要补充一句“验证方式用于帮助读者确认讲解没有跑偏因此必须给出可执行的输入或命令”。这一句解释了该要素存在的意义Agent 就能自己判断“如果用户给的是抽象代码片段我应该建议用最小示例跑一遍”。真正可用的 SKILL.md是在指令文件和心理模型之间搭桥。3. 动手实现一个 show-me Skill从 SKILL.md 开始3.1 Skill 的文件结构与加载方式目前主流的 Coding Agent 工具都支持通过目录加载 Skill。以通用做法为例一个 skill 在仓库里通常是这样的结构skills/ ├── show-me/ │ ├── SKILL.md │ └── examples/ │ ├── python-basic.md │ └── refactor-diff.mdSKILL.md 是入口负责描述触发条件和执行流程。examples 目录存放少量示例目的是给 Agent 提供参考格式。不要放太多示例2 到 4 个足够否则上下文会被大量无关内容占用。3.2 一份可直接使用的 SKILL.md 示例下面这份 SKILL.md 可以按自己的 Agent 工具调整。它覆盖了触发条件、执行步骤、输出模板和注意事项适合作为 show-me 的基础版本。--- name: show-me description: 当用户要求理解代码、解释代码、讲解代码时使用本 Skill 输出成体系的讲解内容而不是只给结论。 --- # show-me ## 触发条件 - 用户要求“解释这段代码”“讲讲这个文件”“这个函数什么意思”。 - 用户要求“review 这段代码的改动逻辑”。 - 用户要求“给新人讲一下这个模块”。 - 用户贴出代码并提问“它是怎么工作的”。 以上任意一条命中则进入 show-me 模式。如果用户只要求改代码不要主动长篇讲解。 ## 执行步骤 1. 先读取并理解用户提到的文件或代码块。 2. 如果上下文信息不足先检查仓库内是否有相关文件不要凭空猜测。 3. 按下方模板组织输出每一部分都要有实际代码引用。 4. 输出结束后可以额外补充一句提示建议用户用哪些方式验证。 ## 输出模板 ### 一句话结论 用不超过两句话说明这段代码是什么、做什么、用了什么核心依赖。 ### 关键假设 列出你讲解时依赖的假设条件至少包括 - 运行环境 - 输入限制 - 主要副作用 - 失败策略 ### 分块讲解 按函数或类拆分每个块包含 - 名称和行号 - 职责 - 内部关键逻辑 - 与相邻代码块的协作关系 ### 关键证据 引用具体证据时必须给出引用位置例如“第 28 行的后缀判断”不要只写“代码里有判断”。 ### 验证方式 给出至少一种可执行验证方式例如 - 构造一个最小输入 - 运行某个命令 - 观察某个日志输出 - 检查某个返回值 ## 注意事项 - 不要编造行号行号必须与实际读取的代码一致。 - 如果代码过长优先讲结构再挑关键分支细讲。 - 不要只复述代码要解释“为什么这样设计”。 - 如果一段代码没有明显上下文不要强行总结可以直接说明缺失信息。 - 讲解和证据是并列关系不是复述关系。关键点解释触发条件为什么要列这么细。不列细Agent 无法判断“什么时候该触发”。触发条件列得越明确误触发和漏触发越少。为什么要有“如果用户只要求改代码不要主动长篇讲解”。这条是为了防止 Skill 干扰正常编码任务。Skill 是增强不是替代。输出模板为什么要覆盖“关键假设”。这个要素能显著减少错误讲解。没有假设Agent 会把默认运行路径当作唯一真相有了假设读者知道哪些结论是依赖外部条件的。为什么强调“不要编造行号”。这是 show-me 类 Skill 最容易翻车的点。大模型在上下文很长时会对行号产生幻觉必须通过检查工具确认。3.3 在 Cursor、Claude 和自建 Agent 中接入接入方式取决于工具。常见做法有两种目录式 Skill 加载。将 skill 目录放到.cursor/skills/、.claude/skills/或自建 Agent 的 skills 路径下由工具自动扫描。主 Prompt 引用。在 Agent 系统提示词或项目级 CLAUDE.md/CURSOR RULES 中写入加载 skills/show-me/SKILL.md 内容当用户请求解释代码时按此执行。以 Cursor 为例可以在项目根目录下创建.cursor/rules/show-me.mdc内容是指向 SKILL.md 的完整引用。以 Claude 为例可以在项目 CLAUDE.md 中追加一行当用户要求解释或讲解代码时先读取 skills/show-me/SKILL.md并严格按其中的模板输出。自建 Agent 更灵活可以在工具调度层为 show-me 增加一个 Tool触发时把 SKILL.md 读取进上下文。3 Member 验证让 Agent 讲解一个最小 Python 脚本完成 skill 接入后用下面这个脚本做验证。import os import json def load_config(pathconfig.json): if not os.path.exists(path): raise FileNotFoundError(f{path} not found) with open(path, r, encodingutf-8) as f: return json.load(f) def safe_size(path): try: return os.path.getsize(path) except FileNotFoundError: return 0 def main(): cfg load_config() for f in cfg.get(files, []): print(f{f}: {safe_size(f)}) if __name__ __main__: main()用户对 Agent 说“请用 show-me 方式解释这个脚本”。符合预期的输出应该包含一句话结论这是一个读取 JSON 配置并打印文件大小的工具脚本、关键假设默认 config.json 在当前目录、文件不存在时返回 0、分块讲解load_config 负责配置读取并抛出异常、safe_size 负责容错获取文件大小、关键证据第 8 行抛 FileNotFoundError第 14 行捕获 FileNotFoundError 返回 0、验证方式新建 config.json 和任意文件运行脚本观察打印结果。如果你的 Agent 输出缺少“分块讲解”和“关键证据”两部分说明 SKILL.md 模板没有被完全加载或者工具版本不支持目录式 Skill 扫描。4. 在真实工程中怎么用四个高频场景4.1 接手不熟悉的仓库按模块讲别让它一次性讲完接手一个老项目时最忌讳让 Agent“把整个仓库讲一遍”。上下文窗口承载不了Agent 会越讲越含糊最后只能输出流水账。正确用法是把仓库拆成模块分批调用 show-me批次输入目标第一批入口文件和路由配置建立整体调用链第二批核心业务模型和数据库访问层理解数据流第三批接口层和事件处理理解对外交互第四批测试和部署脚本理解运行保障每次只让 Agent 讲解一个模块并要求它给出与相邻模块的协作关系。这样积累出来的理解是可以逐段验证的不会出现“整体看似懂了、细节全没懂”的假象。4.2 复查自己的改动show-me diff 模式代码评审前可以用 show-me 检查自己的 diff。指令可以写成请以 show-me 模式审查当前分支相比 main 的改动。 对每一个改动文件输出 1. 改动意图 2. 删除了什么、新增了什么 3. 有没有破坏原有行为 4. 潜在风险点这个模式的输出比普通“请 review 一下”强很多。普通 review 只会给“都通过了”或“有小问题”而 show-me 会强制 Agent 按文件、按逻辑块解释改动的因果链。4.3 给团队成员做代码说明输出可直接沉淀成文档团队里经常出现一个问题代码写完了没人知道怎么维护。show-me 的输出天然适合二次整理成文档。如果 skill 输出严格遵循五要素成员只要把“分块讲解”和“关键证据”合并再补充目录和变更历史就能得到一份可用的模块说明文档。这样就避免了“让开发者自己写文档”和“让 Agent 凭空写文档”两端都不靠谱的情况。4.4 学习开源项目让它挂到具体 commit 或 tag 上讲学习开源项目时代码会不断变化直接让 Agent 实时搜索主分支很容易处理到不稳定的中间状态。更稳妥的方式是让 Agent 先 checkout 一个稳定 tag再按 show-me 方式讲解。git clone https://example.com/project.git cd project git checkout v1.2.0然后把仓库路径交给 Agent要求它说明入口文件、初始化流程、核心数据结构以及 v1.2.0 这个版本里模块间的依赖关系。这种“锁定版本 show-me 讲解”的组合比直接看最新代码更适合新手学习。5. 常见失败现象和排查链路5.1 现象一输出里还是只有代码没有讲解可能原因Skill 没有被加载Agent 没有识别到 show-me 指令。触发条件太窄用户的表述没有命中。工具版本不支持目录式 Skill 扫描。排查顺序# 第一步查看是否存在 Skill 目录 ls -la .cursor/skills/show-me/ # Cursor 场景 ls -la .claude/skills/show-me/ # Claude Code 场景 # 第二步确认工具版本是否扫描到 skill # 查看启动日志或运行 /skills 类似命令工具不同命令不同 # 第三步手动读取 skill 内容确认无格式损坏 head -40 skills/show-me/SKILL.md如果确认 skill 已存在但未触发就扩大触发条件把“解释一下”“讲讲”“这个函数是干嘛的”等常用说法都加进去。5.2 现象二解释很长但完全没对上代码这种情况通常是模型不存在代码检索能力时直接按记忆生成讲解。最常见于 Agent 没有调用读取工具、只凭用户贴出的一小段代码就开始总结。修复办法在 SKILL.md 开头加一句“执行前先读取目标文件不得仅凭对话历史判断代码结构”。检查 Agent 的工具配置确保 read 和 grep 可用。增加“关键证据”强制要求比如“必须给出函数名、对应行号和具体分支条件”。5.3 现象三只讲“是什么”不讲“为什么”很多 Agent 的默认输出是复述代码比如“这行代码调用了 requests.get”。这没有给读者带来增量价值。处理方式是在 SKILL.md 中明确强调“设计意图”在“分块讲解”中每个函数至少要回答一个问题 - 为什么存在这个函数 - 为什么用这种实现方式 - 如果不这样做会产生什么后果这三问是 show-me 的灵魂。它迫使 Agent 从“翻译代码”转向“讲解设计决策”。5.4 现象四行号对不上引用错误行号幻觉是大模型处理长文件时的高发问题。原因在于模型并不真正“看文件”它只在检索上下文后才生成文本。排查与预防方案问题检查方法处理建议引用行号不存在手动跳到对应行在 SKILL.md 中强制“行号必须通过工具确认不能估算”函数名拼错搜索函数定义位置要求在输出前用 grep 定位函数声明上下文截断导致遗漏查看工具日志拆分文件一次讲解不超过 500 行5.5 排查顺序总结遇到 show-me 输出质量不符合预期按这条链路排查1. 输入是否明确用户到底想理解什么 2. Skill 是否加载检查路径、启动日志、触发词。 3. 工具是否可用read、grep 是否能读目标代码。 4. 模板是否执行输出是否包含五要素。 5. 上下文是否完整代码是否被截断关键函数是否缺失。 6. 模型是否足够超长文件建议拆解后再讲解。排查时不要一开始就怀疑模型能力先检查工程配置再谈模型表现。6. 最佳实践把 show-me 从 Demo 变成团队资产6.1 命名与触发词要稳定输出模板要可复用Skill 的 name 建议短且稳定例如show-me、explain-code。不要经常改因为团队所有提示词、文档和示例都会依赖这个名称。触发词要保持敏感宁可多覆盖常见提问表述也不要只写“解释代码”四个字。输出模板的字段顺序一旦定下来就不要频繁调整。团队成员只有不断看到同样的结构才能形成“一看输出就知道下一步做什么”的默契。6.2 给 Agent 保留足够判断空间不要写成死骨架模板不能写成填空式表单。如果每一条都精确到字数Agent 会为了满足格式要求而编造内容。正确做法是保留足够自由度接受 Agent 用“关键假设”覆盖三种以上情况。允许在验证方式中使用“最小示例”而非真实命令。允许对极端复杂的代码块进行抽象总结。模板的价值在于约束结构和底线而不是删除模型的推理能力。6.3 学习环境和生产环境要分开对待场景学习/个人项目团队生产环境Skill 文件位置用户级配置目录仓库级共享目录跟随代码库版本输出用途帮助个人理解可沉淀为模块文档、评审材料上下文大小可放宽追求细节完整控制长度追求结构化摘要权限与隐私非敏感代码即可确认代码可进入 Agent 上下文处理敏感配置时脱敏错误处理允许 Agent 猜测并注明禁止猜测必须给出可验证证据生产环境还要考虑Skill 文件变更需要走代码评审别让任何成员悄悄改触发词敏感仓库要明确哪些目录禁止 Agent 读取团队文档要记录 Skill 的结构变更历史。6.4 扩展方向show-me 不只是讲解还能做 Review、Diff 和文档生成show-me 的核心模式可以迁移到多个场景show-me diff讲解两个 commit 之间改动的前后差异和影响范围。show-me review按设计意图、风险点、测试建议审查代码而不是只找语法问题。show-me docs从代码结构生成模块级说明文档输出到 docs/ 目录。show-me why反向解释“为什么之前这样实现”帮助新成员理解历史决策。每个扩展方向都只是替换 SKILL.md 中的输出模板和执行步骤基础加载机制完全复用。这正是一个好的 Agent Skill 该有的特征改动成本低复用价值高。可以按下面的检查清单确认自己的 show-me 是否合格[ ] 用户说“解释代码”时Agent 输出包含一句话结论 [ ] 输出中的函数名、行号与代码实际内容一致 [ ] 每个关键函数都回答了“为什么存在” [ ] 关键假设单独成段没有埋在正文中 [ ] 至少给出一种验证方式不全是空泛建议 [ ] 代码过长时会自动拆分而不是一次性硬講解决 Coding Agent 讲不清代码的问题不需要等模型升级也不需要换更贵的工具。把一个 show-me Skill 写清楚让 Agent 按“结论、假设、分块、证据、验证”的顺序输出就能显著提升代码理解效率。团队协作时这种稳定输出比偶然的“讲得好”更值钱因为它可以被复制、被检查、被沉淀成文档。后续再接入 diff review、文档生成这些扩展也只是在现有骨架里换模板。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进