祝你好运的技术博客

Published on

什么是大模型skill

Authors
  • avatar
    Name
    祝你好运
    Twitter

前面我自己做过coding-agent,这个是比较初级的Agent,能力也比较有限,比较高级的Agent需要具备更多的能力,而这些能力就是通过skill来实现的。这里我就深入地学习一下什么是skill。

什么是skill

我觉得skill最好理解的方式就是SOP(Standard Operating Procedure),就是标准操作程序。

企业招聘完员工,给员工分配的工作任务,这些任务的完成是有标准的,这个标准就是SOP。比如很多科技公司里面都有NOC(Network Operation Center),这个就是负责网络运维的团队,他们负责网络的稳定运行,网络的故障排查,网络的优化,网络的安全等。他们就是通过SOP来完成这些任务的。

他们有很多SOP,比如用户反馈优惠券无法使用,他们会按照SOP来排查问题,比如首先看问题规模,如果是大批量出问题,要赶紧拉人止损。具体什么算是大批量,都拉哪些人,SOP里面都是有规定的。如果是个别用户出问题,则需要按照SOP来排查问题,比如首先看优惠券是否过期,是否被使用,是否被冻结,是否被限制使用,是否被取消,是否被删除,是否被禁用,是否被封禁,是否被屏蔽,这些SOP也是有规定的。

所以我们可以看出,这些问题的应对策略是相对固定的,就是什么问题,按照什么流程来解决。

而大模型的skill也是类似的。大模型是通用的,他可以解决各种各样的问题,但他也有个弊端是他内部是随机的,就有可能会出现一些不稳定现象。比如今天按照123处理这个问题,明天类似问题来了,他按照132来处理,然后处理结果可能就不太正确了。而我们期望的是稳定的处理能力。而我们就通过skill来给大模型添加这种稳定的处理能力。

比如code review,我们总不能直接跟大模型说“给我review一下这些代码”,如果我们给他的输入是不明确的,那就不能指望他给我们期望的结果。所以我要通过prompt来明确的高数大模型,具体要怎么做code review。比如下面这个prompt,就是我给大模型输入的prompt,而且这还只是简化版本,我们省略不少我们仓库或者我们公司的特定要求。

---

# 审查流程


## 第一步:理解变更目的

在开始审查之前:

1. 阅读 Pull Request 描述。
2. 理解这次修改想解决的问题。
3. 确认影响的模块和功能。
4. 必要时阅读相关上下文代码。

不要只根据 Diff 中的几行代码进行孤立判断。


---

## 第二步:分析代码变更


请重点检查以下方面:

---

## 1. 正确性(Correctness)


检查:

- 是否存在逻辑错误。
- 是否存在错误的业务假设。
- 是否遗漏边界情况。
- 是否存在空值处理问题。
- 是否可能导致异常。
- 是否改变了原有行为。
- 是否存在状态管理错误。
- 是否存在并发或异步问题。


---

## 2. 安全性(Security)


检查:

- 是否存在认证绕过。
- 是否存在权限控制问题。
- 是否存在 SQL 注入风险。
- 是否存在 XSS 等输入安全问题。
- 是否泄露敏感信息。
- 是否错误处理用户输入。


---

## 3. 性能(Performance)


检查:

- 是否引入明显性能下降。
- 是否存在不必要的重复计算。
- 是否存在 N+1 查询问题。
- 是否存在不必要的数据加载。
- 是否可能导致内存泄漏。
- 是否影响高频调用路径。


不要提出没有实际影响的微优化建议。


---

## 4. 可维护性(Maintainability)


检查:

- 是否违反项目已有架构。
- 是否引入明显复杂度。
- 是否产生重复逻辑。
- 是否增加未来维护成本。
- 是否存在难以理解的实现方式。


---

## 5. 测试(Testing)


检查:

- 新功能是否有对应测试。
- Bug 修复是否包含回归测试。
- 是否覆盖重要边界情况。
- 是否可能导致已有功能回归。


---

# 审查规则


## 只关注本次修改引入的问题

不要报告:

- 修改前已经存在的问题。
- 与本次 PR 无关的问题。
- 个人代码风格偏好。
- 可以由代码格式化工具解决的问题。
- 没有证据支持的猜测。


---

## 问题质量优先

宁愿输出少量高价值问题,也不要输出大量低价值建议。


每一个问题必须满足:

1. 能明确指出问题位置。
2. 能解释为什么这是问题。
3. 能说明可能造成的影响。
4. 能提供合理的修改建议。


---

# 输出格式


请按照以下 JSON 格式输出:

```json
{
  "summary": "对本次代码变更的整体评价",

  "approval": true,

  "issues": [
    {
      "severity": "critical/high/medium/low",

      "file": "问题所在文件",

      "line": "问题所在代码行",

      "title": "问题标题",

      "description": "详细描述发现的问题",

      "impact": "说明可能造成的影响",

      "suggestion": "给出修改建议"
    }
  ]
}

有了Prompt为什么还需要skill

Prompt太长了

如果我们想要让大模型在特定任务上面比如code review表现又好又稳定,那我们肯定得给他一个超级完整的Prompt,然后大模型参考这个Prompt再去做这个任务,表现会更好一些。但这个Prompt太长了,大模型也不好理解重点(skill里面信息是逐步暴露的,这样大模型更容易理解重点)。

skill可以组合但prompt不行

Prompt的话我们就得一次性的把所有信息都给到他,这个对于复杂任务来说,信息量太大,大模型也不好处理。因为信息太多了,想要从里面提取重点,相比于最开始只知道这些内容的概括,然后逐步暴露细节,这个难度要大很多。因为Prompt里面的样例代码里面的上下文代码,相比于描述如何做code review的步骤,明显重要性要弱的多。但我们是一股脑的输入给大模型的,大模型本身是不知道这些信息的重要性的,他只能按照大模型的底层原理去执行,即便是有attention机制,效果也不如skill那种逐步暴露细节的方式。

而skill的话我们可以先告诉大模型都有哪些skill(通过提供简要描述),然后大模型判断需要用什么skill,然后再去详细的阅读相关材料,明白这个skill怎么用,哪些注意事项,等等细节。然后执行这个skill,这个过程可以重复多次,直到完成任务。

prompt无法做到skill的按需组装

比如我们有code review, test case writing, bug fixing, security review, performance optimization, etc.这些技能我们都可以拆分成一个个的skill,然后大模型可以按照需要选择使用哪些skill。

但如果用Prompt,我们就没办法这么做,要么我们把所有东西一股脑甩给大模型(prompt直接爆炸了),要么我们把东西拆开,然后告诉大模型他需要啥再找我们要(这大模型也比较迷惑,什么算他需要什么算不需要呢?),找我们要的话,我们再把对应问题的Prompt给他,这样我们还得准备大量的Prompt,这工作量也是非常大的。明显不切实际了。

prompt无法做到skill的渐进加载

比如我们让他做code review的时候,我们需要提前把所有的Prompt全部整理好一股脑甩给大模型,然后大模型按照他的理解一步一步来做。那比如中间做到性能检查的时候,他的上下文里面也是各种描述一箩筐,这就会有一个问题称为:

  • 上下文污染;
  • 指令稀释;
  • 注意力分散;
  • 指令冲突。

而我们如果用skill的话,他可以做到多步骤执行,只有在做性能检查的时候,才把性能检查的技能的描述和代码给到他,这样就能极大的减轻上下文污染的问题。

巨型Prompt有工程问题

我这里说工程问题是指,如果Prompt太长,大模型也不好理解重点,而且大模型也不好维护,而且大模型也不好调试。这不是一个系统化的工程应有的样子。我们期望这个大工程是可以一点一点拆解开的,模块尽量相互独立,可以单独测试。

那比如我们的code view的巨型Prompt,我们想优化中间的性能的某些点,那我们得把整个Prompt都重新整理一遍,这个工作量是非常大的。而我们如果用skill的话,我们只需要优化性能检查的skill,其他部分都不用动,这样就能极大的减轻工作量。 如果是用了巨型Prompt,你很难判断:

  • 是否影响 Bug Fix;
  • 是否和安全规则冲突;
  • 哪部分规则属于 Code Review;
  • 这一版为什么修改;
  • 如何单独回滚;
  • 如何单独做 A/B 测试;
  • 哪个团队负责维护。

那如果是拆成skill,就可以这样拆分开:

skills/
├── code-review/
│   └── SKILL.md
├── bug-fixing/
│   └── SKILL.md
├── security-review/
│   └── SKILL.md
└── test-writing/
    └── SKILL.md

如何搞一个skill?

skill本质上仍然是用Prompt告诉大模型什么时候做,什么时候不做,怎么做。所以我们可以把skill看作是一个特殊的Prompt,只不过这个Prompt不是一次性全部甩给大模型,而是先给一个大概介绍,这个skill是个啥,然后大模型自己判断这个skill是否需要执行。如果需要用,那大模型再去找对应的技能文档,然后执行这个skill。

skill/
├── SKILL.md
├── templates/
│   └── report-template.md
├── examples/
│   ├── good-example.md
│   └── bad-example.md
├── schemas/
│   └── output-schema.json
├── scripts/
│   └── validate_report.py
└── references/
    └── company-guidelines.md

其中最核心的往往是:

SKILL.md

它相当于这个 Skill 的说明书。

OpenAI 当前的 Skills 设计也使用 SKILL.md 作为主要工作流说明文件,它一般会描述 Skill 做什么、需要什么输入、执行步骤、输出格式以及最终检查项。Using skills from OpenAI

什么时候不需要skill?

当我们只需要让大模型做一次性的任务,比如生成一个简单的报告,或者做一次性的决策,比如选择一个最佳方案,等等。这个时候我们就不需要skill,直接用Prompt就可以了。

甚至说,我们作为开发人员,日常绝大部分的精细化的开发和测试工作,都不应该用skill来完成,而是应该用prompt来完成。因为prompt可以让我们更加精确的控制大模型的行为,而skill则需要我们提前定义好所有的技能,如果这种问题就出现那么两三次,投入产出比非常低,就不要折腾了。