调试Agent的时候,我经常遇到一种尴尬:日志太长、上下文不够、Agent抓不住重点。于是有人提出,与其让Agent读完一大段文本,不如让它把关键内容画出来。这个思路并不新,但当我在Hacker News上看到/show-me这个 agent skill 的时候,还是觉得它的命名点破了一个被严重低估的问题——Agent需要的不是更多文字,而是更友好的表示。
/show-me想做的并不是一个画图命令,而是把Agent消化复杂信息的成本压缩到一条斜杠命令里。往深了说,它背后是一种信息表示方式的设计:当模型上下文越来越贵、任务链路越来越长,如何把“项目结构、依赖关系、调用链、统计分布”这类信息,从几千字的文本压缩成一张人机都能快速读取的紧凑视觉表示。这篇文章想聊的是,为什么这类 skill 值得被单独提出来,以及如果要动手实现类似能力,应该从哪些环节开始。
1. 为什么Agent越来越需要“给我看一眼”
1.1 一个最常见的“看不懂”场景
我一直觉得,Agent 开发里最消耗耐心的不是模型能力不够,而是它经常把时间浪费在“读一篇很长的东西”上。
举个例子。你让Agent分析一次线上调用的失败原因,它拿到的是几十条堆栈日志、三个服务模块的部署目录、一张配置文件里涉及的连接项。纯文本状态下,Agent需要反复在上下文里翻找“哪个服务调了哪个服务”“哪条日志对应哪个模块”。模型确实能做,但代价是大量token消耗,而且顺序一长,前面的关键信息就容易被稀释。
这时候如果有一个/show-me这样的能力,它可以把同样的信息转成一张调用链示意图,或者一张标注了异常位置的流程图。Agent不需要在文字迷宫里来回走,它可以从图里直接获得结构关系。
这不是“好看”的问题,而是信息密度的问题。
1.2 紧凑视觉表示压缩的到底是什么
很多人觉得“视觉表示”就是把文字变成图片,其实压缩的不只是篇幅。
它真正压缩的是这三类信息:
- 关系信息:谁依赖谁、谁调用了谁、节点之间是什么连接方式。
- 层次信息:哪些内容属于同一个模块、父级和子级的关系怎么划分。
- 状态与路径:流程走到哪一步失败,故障发生在哪个环节。
这三类信息如果用文本表达,通常需要大量描述性句子:“服务A在收到请求后调用服务B,服务B再查询数据库,如果超时则返回错误码……”这样的表述,Markdown列表可以拆,但读起来依然很散。
而视觉表示可以在一屏之内把这些关系稳定呈现出来。比如一个 Mermaid 时序图,事件顺序、参与对象、失败节点一目了然。对于Agent来说,这种表示还有一个额外好处:它的注意力不会被大段文本里的无关细节带走。
1.3 为什么要单独做成一个 skill
既然LLM本身可以画Mermaid、可以生成图表,为什么还需要show-me这样一个独立的agent skill?
原因在于,画图不是难点,画对才是。一个独立的 skill 可以把“判断要展示什么—抽取关键信息—选择表示类型—生成渲染—回填上下文”这一整条链路固定下来。
不定制skill的话,Agent每次都要重新思考:用户说“看看这个项目结构”,到底是要目录树、依赖图还是模块关系图?是从当前文件位置开始扫,还是要递归扫描全部子目录?输出是要SVG文件,还是直接在对话里返回Mermaid代码?
这些决策看起来小,但每次都从头推理,不仅慢,而且不稳定。把它封装成/show-me这样的斜杠命令,等于给Agent预装了一条“遇到这类需求就用这个流程”的路径。
这里可以先把判断说清楚:
/show-me这类 skill 的价值,不是画图能力,而是把“信息怎么被快速理解”这件事流程化了。
2./show-me到底封装了什么能力
2.1 表层看,输入和输出是什么
先从最外面看。按照项目标题的语义,/show-me是一个 agent skill,核心产出是紧凑视觉表示。那它接收什么、返回什么?
常见输入类型是:
- 一组日志片段或筛选后的诊断信息
- 一个目录路径或仓库地址
- 一段调用链、依赖列表、配置文件
- 用户直接提出的“展示一下这个模块的边界”“把这个流程可视化”
常见输出类型则取决于表示方式:
- Mermaid 代码块,可以直接被Agent理解或渲染
- 渲染后的 SVG / PNG 图片文件
- ASCII 风格的目录树或流程图,适合放回纯文本上下文
- 一个自包含的单文件 HTML,方便在浏览器里打开
需要注意,这并不一定是我上面列的某种确定实现。原始标题没有描述具体支持哪些输入输出格式,所以更合理的理解是:它定义了一套“如何把信息变成紧凑视觉表示”的通用范式,具体细节可以按环境扩展。
2.2 底层看,它走的是四步流程
不管具体实现用什么语言、什么模型,这类 skill 的内部流程基本可以拆成四步:
第一步:信息抽取。从原始输入里去掉噪声,抽取出关键实体、关系、事件顺序。这一步最关键,因为后面图的质量完全取决于抽取结果。如果日志里有大量重复异常,抽取时要考虑去重和聚合。
第二步:表示选择。根据抽取结果判断该用什么图。是流程类信息,就选流程图;是调用关系,就选时序图;是模块归属,就选架构图;是数据分布,就选小型统计图。
第三步:生成与渲染。生成对应的图定义代码,比如Mermaid,然后调用渲染器转成图片。如果Agent不需要看图片,也可以直接把代码作为输出,让它自己理解结构。
第四步:上下文回填。把视觉表示放回对话上下文,或者存储到指定路径,让后续任务可以继续引用。
这四步听起来不复杂,但真正落地时每一步都有不少细节。
2.3 为什么一定要强调“compact”
标题里有一个词很容易被忽略:compact。
这个词意味着输出必须克制,而不是把信息铺满一整张图。Agent的上下文窗口是有限的,如果每次展示都生成一张几千节点的大流程图,那这个能力反而成了负担。
更合理的策略是:只突出用户当前最需要看到的局部。比如分析线上故障时,调用链可能很长,但/show-me应该只展示“出错的这条路径”以及相邻节点,而不是把整个服务拓扑全部画出来。
信息密度的取舍,是这类 skill 和“一次性可视化脚本”之间最大的区别。
3. Agent Skill 和 MCP 不是一回事
3.1 MCP 是连接层,解决的是“怎么碰到外部资源”
聊/show-me的时候,一定避不开agent skill和MCP的区别。这两个概念很容易被混在一起,因为它们在很多Agent框架里同时出现。
MCP,即 Model Context Protocol,解决的是模型如何以稳定的方式连接到外部工具和数据源。它定义了一套标准化的工具发现方式、调用格式和返回结构。一个MCP Server可以暴露各种工具,比如读取文件、查数据库、调用某个API。Agent通过MCP Client去发现和调用这些工具。
MCP更接近“协议层”。它不关心任务怎么做得好,只关心调用是否规范、连接是否可靠、返回是否符合约定。
3.2 Agent Skill 是能力层,解决的是“怎么把一件事做得像样”
Agent Skill 则不一样。它封装的是“完成某类任务所需的完整方法论”。它可能包含提示词模板、多步骤的编排逻辑、使用的工具组合、输出规范、甚至领域经验。
回到/show-me:一个视觉表示能力如果只是提供一个“生成Mermaid”的工具调用,那它只是有了一个工具。但show-me作为 skill,意味着它需要自己决定从哪一层开始做信息抽取,用什么图类型,输出内容控制在多大范围,以及在渲染失败时怎么降级。
这就是能力层和协议层的区别。
3.3 对比一下就能看清
| 维度 | MCP | Agent Skill |
|---|---|---|
| 定位 | 标准化连接协议 | 任务级能力封装 |
| 关注点 | 工具发现、调用规范、返回格式 | 任务理解、流程编排、领域经验 |
| 典型载体 | Server/Client、工具定义、协议消息 | 提示词模板、执行流程、工具组合 |
| 是否独立存在 | 可以被多个Agent复用 | 通常运行在一个Agent框架之内 |
| 与工具的关系 | 直接暴露工具 | 自己决定调用哪些MCP工具 |
| 失败的粒度 | 一次调用失败 | 整个任务流程可能需要降级 |
一个直观类比:MCP是传输管道和插座标准,Agent Skill是电器本身。你要用电,需要有插座,但没有电器,插座就是空壳。反过来,电器再好,如果插座标准不统一,换一个环境就要重接。
/show-me作为一个 agent skill,可以依赖一个或多个MCP工具来读取文件和渲染图片,但实际的判断逻辑、抽取规则、输出控制,都发生在skill这一层。
3.4 实际协作时怎么分工
在落地时,它们的关系通常是协作的:
- Agent 接收到用户指令“展示一下这个模块的调用关系”。
- Skill 层开始工作:解析指令,确定要展示的边界。
- Skill 调用 MCP 工具读取文件目录、解析依赖列表。
- Skill 内部用LLM抽取关键节点和边。
- Skill 生成图表定义,再调用渲染工具输出图片。
- 返回视觉表示,或者把图片路径回填给Agent继续处理。
也就是说,MCP让skill“够得着”外部世界,skill让调用这些工具的方式“有脑子”。
4. 从零实现一个紧凑视觉表示 skill
4.1 先定义输入边界,不要一开始就追求万能
动手实现类似/show-me的能力时,我的建议是先从单一场景开始,不要一开始就设计成一个通用可视化引擎。
比如先只处理三类输入:
- 一个文件目录,输出目录树式架构图
- 一段调用日志,输出时序图
- 一份配置文件,输出依赖关系图
每类输入单独定义数据格式。目录扫描用不到LLM,直接遍历文件系统即可;日志解析则可能先用规则提取时间、事件、服务名,再把无法归类的文本交给LLM抽取。
输入边界清晰,后面的答案才是可调试的。
4.2 信息抽取环节,LLM 只做两件事
很多人做这类 skill 时,习惯把整份日志或整个目录树都塞给LLM,让它直接生成图。这是最大的坑。
正确的做法是先压缩再交给LLM。把原始数据分成两段处理:
- 规则负责看得见的压缩:去掉重复行、排除干扰目录、统计日志频率,把百万字的数据缩到几千字。
- LLM负责看得懂的抽取:从压缩后的文本里提取实体、关系、事件路径,输出为结构化的JSON。
比如“服务A调用服务B失败”这件事,LLM应该输出:
{ "type": "sequence", "participants": ["ServiceA", "ServiceB"], "steps": [ { "from": "ServiceA", "to": "ServiceB", "action": "request", "status": "failed" } ] }这个JSON再进入表示选择环节,而不是让LLM直接写图表代码。中间加一层结构化数据,能显著提升后续生成的稳定性和可调试性。
4.3 表示选择,靠一张判断表就可以
表示选择不需要复杂模型,一组规则就能解决大部分需求:
| 内容类型 | 合适的表示 | 说明 |
|---|---|---|
| 调用顺序、事件时间线 | 时序图 | 适合展示谁先谁后、谁调用谁 |
| 模块层级、目录结构 | 树形图 / 架构图 | 父子关系明确 |
| 流程分支、决策路径 | 流程图 | 适合展示条件分支和异常路径 |
| 实体间多对多关系 | 关系图 / 依赖图 | 适合依赖、数据流向 |
| 数值分布、统计摘要 | 小表格或条形图 | 数据量少时表格更紧凑 |
规则可以写成:
- 有
from/to/action结构,优先时序图。 - 有路径层级,优先树形结构。
- 有大量条件判断,优先流程图。
- 其他情况,默认返回一个精简表格。
这样“紧凑”的含义,在规则层面就保证了——它不会把一个流程图硬生生画成架构图。
4.4 生成、渲染与回填上下文
生成层建议直接输出Mermaid或其他文本图表语言。原因很简单:方便回填。Agent可以直接“读”Mermaid代码,不需要额外图片解析。
如果用户需要图片,再调渲染器生成SVG或PNG。输出路径要约定好,建议统一放到artifacts/show-me/下,并按时间戳命名,避免覆盖。
artifacts/show-me/20250101_103000_call_graph.mmd artifacts/show-me/20250101_103000_call_graph.svg生成完成后,把Mermaid代码放回上下文,把图片路径附在response里。这样Agent既能看到整个图的结构,也能知道图片存在哪里,便于后续引用。
4.5 验证时先小样本再批量扩
这个环节我想多说几句。很多人在第一次跑通之后,马上就往真实环境里塞大批数据,结果各种抽风。
更稳妥的顺序是:
- 先拿一个最小样本跑通,比如两个服务、一次调用。
- 验证生成的JSON是否符合预期结构。
- 再验证Mermaid能否被正确渲染。
- 拿一个常见但稍复杂的样本,比如十次调用带一次失败分支。
- 确定稳定后再做目录级别的批量输入。
不要一上来就把批量数和并发数拉满。先用一条样例确认输入、抽取、生成、渲染、回填全链路正常,再逐步加数据。
5. 适用边界与容易踩的坑
5.1 适合谁,不适合谁
/show-me这类 compact visual representation skill 并不是万能的。它有清晰的使用边界。
适合的场景:
- Agent开发调试:让Agent快速理解项目结构、调用链、运行状态。
- 内部文档生成:快速把模块关系变成示意图,插入团队文档。
- 故障定位:把日志压缩成带失败标记的时序图,辅助人机共同分析。
- 学习理解:面对一个陌生仓库时,先生成一张架构图再深入代码。
不适合的场景:
- 对外交付的规范图:需要公司标准、统一风格、严格配色,这类skill做不到。
- 精确数据报表:需要精确到小数点、严格口径的统计图,不适合用LLM做抽取。
- 超大复杂系统的完整拓扑:图能做到可视化,但一旦节点数量过大,就偏离了“compact”的初衷。
5.2 排查链路,从现象倒推问题
如果发现生成结果不对,建议按照这个顺序排查:
- 看输入:原始数据有没有被截断?路径对不对?编码是不是UTF-8?日志是不是只取了一部分?
- 看抽取结果:中间产生的JSON是否丢失了关键节点?有没有把“错误日志”误当成“正常事件”?
- 看表示选择:是不是把本该画成时序图的内容,硬画成了流程图?
- 看渲染:Mermaid代码语法有没有问题?渲染器版本是否支持你用的图类型?
- 看回填:图片路径是否正确?Agent是不是引用了过期的上下文内容?
在这五层里,最常出问题的是第二层的抽取规则。因为规则会不断遇到新数据形态,需要持续补充过滤条件和聚合策略。
5.3 长期使用,还需要补齐工程化能力
如果想把这个能力长期放在Agent工作流里,前面说的最小实现还不够。
至少还要补上三块:
- 日志与可观测性:打印每次抽取的JSON、渲染耗时、输出路径,出了问题才能复盘。
- 缓存与幂等:同一份目录、同一组日志,如果短时间内重复请求,不应该反复扫描和渲染。
- 权限与路径安全:如果skill允许访问文件系统,必须限制扫描范围,避免读取敏感目录或泄露路径信息。
这些工作在早期很容易被忽略,因为它们不会影响单次demo的效果。但一旦进入真实任务,文件权限、输出目录冲突、缓存失效、上下文更新不及时,都会变成日常麻烦。
6. 回到最开始的问题
/show-me让我重新想了一遍Agent真正缺的是什么。
很多人以为Agent缺的是更长的上下文、更强的推理、更多的工具。但一条调试链路的真实瓶颈,往往在信息表示:一旦关键信息被淹没在无关文本里,再长的上下文也只是让模型“能找到却不一定看得清”。
compact visual representation的提出,等于给了Agent一个“先抓重点、再看细节”的工作方式。它把复杂的目录、日志、调用链,压缩成人和模型都能快速理解的结构化视觉语言。这个过程需要信息抽取的能力、表示选择的判断、渲染工具的配合——它值得被设计成一个独立的agent skill,而不是每次临时拼凑。
如果你也想实现类似能力,我的建议只有一句:不要想着一次做完整,先从最小样本、单一类型、单条链路跑通,再慢慢加规则。过程中会不断遇到新的数据形态,每一次都是对抽取规则和表示规则的补充。
这类能力真正的长期价值,不是让Agent“会画图”,而是让Agent在信息爆炸的时候,依然知道该看什么。而这个判断力,才是未来所有Agent工程都绕不开的核心问题。