Skill是什么?AI能力插件,就像给手机装个App一样简单
时间:2026-07-20 | 作者:星河游者 | 阅读:0一个让我失眠的夜晚
去年有个需求,让我熬了三个通宵。
业务方说要做一个“智能客服”。
但要求特别拧巴:必须能查订单和退换货;必须能根据历史行为做个性化推荐;还必须实时对接库存系统。
当时我们用的是某主流大模型的API。模型本身挺聪明,但一碰到“查库存”这种需要实时数据的活儿,就开始胡编乱造。
那会儿业内还没有特别成熟的Agent框架。我试了Function Calling,写了十几套prompt模板,甚至自己撸了一个简单的RAG流程。
结果呢?代码越写越臃肿,prompt越改越拧巴。每次加一个新能力,就跟重构整个系统似的。
直到我接触到“Skill”这个概念。
说白了,Skill就是把AI的某项“专项能力”打包成一个独立的插件。想让它查天气?装一个Weather Skill。想让它操作Jira?装一个Jira Skill。想让它拉取数据库里的实时报表?写一个SQL Skill就完事了。
就像给手机装App一样:装上就能用,不用了就卸掉,核心系统干干净净。
今天,我就把自己在这块踩过的坑、总结的经验,一次性倒给你。
Skill到底是什么?用一个例子说透
别被“Skill”这个花哨名字唬住。它的技术本质其实就三层:
- 一层接口:定义好输入输出规范(输入什么参数,输出什么格式)。
- 一层执行逻辑:内部干活的代码(调API、查数据库、跑算法都行)。
- 一层注册机制:让AI“知道”有这个能力存在,以及什么时候该调用它。
画个简单的对比,你就懂了:
对比项 |
传统Function Calling |
Skill插件 |
新增能力 |
改prompt + 改代码 + 重新部署 |
放一个Skill文件进去,热加载 |
复用性 |
每个项目重新写一遍 |
跨项目拷贝即用 |
调试难度 |
跟大段的系统代码混在一起 |
独立运行,日志隔离 |
团队协作 |
前后端、算法互相锁死 |
各写各的Skill,最后组装 |
打个你肯定懂的比方:传统方式是给汽车发动机舱里硬塞新零件,Skill是给车尾挂一个快拆拖斗。拖斗里装什么都可以,装错了摘下来换一个就行。发动机舱(核心系统)一根线都不用动。
手把手:10分钟写一个“查快递”Skill
光说不练假把式。下面我用Python写一个真实的Skill,让大模型能查询快递物流信息。
Step 1:定义Skill的“说明书”
每个Skill必须告诉AI三件事:我能干什么、我需要什么参数、我返回什么格式。
# skill_express.py
from typing import Optional, Dict, Any
from pydantic import BaseModel, Field
# 1. 定义输入参数的结构
class ExpressInput(BaseModel):
tracking_number: str = Field(description="快递单号,支持中通/圆通/顺丰")
carrier: Optional[str] = Field(default="auto", description="快递公司编码,可选:zto/yto/sf,默认自动识别")
# 2. 定义输出的结构(让AI知道能拿到什么信息)
class ExpressOutput(BaseModel):
status: str = Field(description="物流状态:已揽收/运输中/派送中/已签收")
location: str = Field(description="最新位置")
timestamp: str = Field(description="更新时间")
details: list = Field(description="完整物流轨迹列表")
Step 2:写执行逻辑(真正的“干活代码”)
注意,这里为了演示,用了Mock数据。真实场景下,对接的是快递100、菜鸟裹裹或顺丰开放平台的API。
import httpx
import re
from datetime import datetime
class ExpressSkill:
"""快递查询技能"""
def __init__(self):
self.api_key = "your_kuaidi100_api_key"
self.base_url = "https://api.kuaidi100.com/query"
def execute(self, input: ExpressInput) -> ExpressOutput:
carrier = input.carrier
if carrier == "auto":
carrier = self._detect_carrier(input.tracking_number)
raw_data = self._mock_query(input.tracking_number, carrier)
return ExpressOutput(
status=raw_data["status"],
location=raw_data["location"],
timestamp=datetime.now().isoformat(),
details=raw_data["traces"]
)
def _detect_carrier(self, tn: str) -> str:
if re.match(r'^d{12}$', tn):
return "sf"
elif re.match(r'^[A-Za-z0-9]{12}$', tn):
return "zto"
else:
return "yto"
def _mock_query(self, tn: str, carrier: str) -> dict:
return {
"status": "派送中",
"location": "广州市天河区体育西路营业点",
"traces": [
{"time": "2026-07-06 08:30", "content": "快递员正在派送中,预计今日送达"},
{"time": "2026-07-05 22:15", "content": "到达广州转运中心"},
{"time": "2026-07-05 14:20", "content": "已从深圳发出"},
]
}
Step 3:注册到AI(最关键的一步)
这一步决定了AI在什么时候、以什么方式调用你的Skill。我用LangChain的Tool装饰器来注册:
from langchain.tools import tool
from langchain.schema import Tool
@tool
def query_express(tracking_number: str, carrier: str = "auto") -> str:
"""查询快递物流信息。
tracking_number: 快递单号
carrier: 快递公司编码(zto/yto/sf),不填则自动识别"""
skill = ExpressSkill()
result = skill.execute(ExpressInput(
tracking_number=tracking_number,
carrier=carrier
))
return f"物流状态:{result.status}n最新位置:{result.location}n轨迹详情:n" + "n".join(
[f"{d['time']} {d['content']}" for d in result.details]
)
express_tool = Tool(
name="快递查询",
func=lambda tn, c="auto": query_express(tn, c),
description="用于查询快递物流信息,输入单号和可选快递公司编码"
)
Step 4:接入大模型(让AI“学会”用这个Skill)
from langchain.agents import initialize_agent, AgentType
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4", temperature=0)
tools = [query_express]
agent = initialize_agent(
tools=tools,
llm=llm,
agent=AgentType.OPENAI_FUNCTIONS,
verbose=True
)
response = agent.invoke({"input": "帮我查一下单号SF1234567890的快递到哪了?"})
print(response["output"])
运行结果:
物流状态:派送中
最新位置:广州市天河区体育西路营业点
轨迹详情:
2026-07-06 08:30 快递员正在派送中,预计今日送达
2026-07-05 22:15 到达广州转运中心
2026-07-05 14:20 已从深圳发出
看到没?AI自动识别了“查快递”的意图,提取了单号,调用了我们的Skill,然后把结果整理成可读的文字。全程没改一行核心系统代码。
进阶:Skill设计的3个“要命”细节
上面那个Demo能跑通,但离“生产级”还差得远。我在线上环境被这3个问题坑过不止一次,你最好提前知道。
细节1:超时控制 + 熔断
Skill调用外部API如果挂了,整个Agent会跟着卡死。必须加超时:
import asyncio
from functools import wraps
def with_timeout(seconds=10):
def decorator(func):
@wraps(func)
async def wrapper(*args, **kwargs):
try:
return await asyncio.wait_for(func(*args, **kwargs), timeout=seconds)
except asyncio.TimeoutError:
return "【系统提示】该Skill响应超时,请稍后重试或尝试其他方式"
return wrapper
return decorator
@with_timeout(5)
async def query_express_async(tn: str):
pass
细节2:输入校验的“防呆设计”
用户输入的快递单号千奇百怪,空格、换行、中文括号全都有。我吃过亏,用户输入“SF 1234567890”中间有个空格,正则直接匹配失败。
def sanitize_tracking_number(raw: str) -> str:
return re.sub(r'[^A-Za-z0-9]', '', raw.strip())
还有,Skill里一定要有fallback。识别不出快递公司就用“中通”兜底,查不到数据就返回明确的“未查询到”,而不是抛异常。
细节3:并发安全
如果你的AI同时处理多个用户的请求,Skill内部如果有共享状态(比如缓存、数据库连接池),必须注意线程安全。
import threading
class ExpressSkill:
_cache = {}
_cache_lock = threading.Lock()
def execute(self, input: ExpressInput):
with self._cache_lock:
if input.tracking_number in self._cache:
return self._cache[input.tracking_number]
# 查询逻辑...
with self._cache_lock:
self._cache[input.tracking_number] = result
return result
团队协作:Skill的“集市模式”
我们团队现在有6个人,分别维护不同的Skill。前端写“页面操作Skill”,后端写“数据查询Skill”,算法组写“推荐Skill”。大家互不干扰,最后通过一个统一的Skill Registry(注册中心)聚合起来。
目录结构长这样:
skills/
├── registry.yaml # 所有Skill的注册清单
├── express/
│ ├── skill.py
│ ├── config.yaml
│ └── tests/
├── jira/
│ ├── skill.py
│ └── README.md
├── sql_analytics/
│ ├── skill.py
│ └── queries/
└── weather/
├── skill.py
└── requirements.txt # 每个Skill可以有自己的依赖
每个Skill独立维护自己的版本、依赖、测试用例。集成测试只测“调用接口是否正常”,不管内部实现。
这是最像“App Store”的地方——各个Skill独立开发、独立发布,主系统只认接口契约。
写在最后:Skill不是银弹,但它是方向
老实说,Skill这套模式不是没有代价。它增加了系统整体的复杂度——你得维护注册中心、做热加载、处理版本兼容。如果你的业务只有两三个AI能力,硬编码比搞Skill架构快得多。
但当你的AI能力超过5个、团队超过3个人的时候,Skill带来的解耦收益会指数级增长。我们现在的系统里跑了17个Skill,涵盖客服、运维、数据分析三个领域。新增一个能力从“改核心代码+全量回归”变成了“写Skill+注册”,周期从2周压缩到2天。
如果你正准备在项目中引入AI能力,我的建议是:
- 前3个能力硬编码:先跑通业务,理解真实需求。
- 到第4-5个能力时:回头抽象出Skill接口,把前3个也迁过来。
- 第6个以后:所有新能力一律以Skill形式接入。
这样既不会过度设计,又能平滑过渡到插件化架构。
最后,送给你我写在团队Wiki首页的一句话:
下次有机会,我再写一篇《Skill的异步调度与分布式部署实战》,讲讲我们怎么把Skill跑在K8s上,以及如何用RabbitMQ做Skill的任务队列。
免责声明:文中图文均来自网络,如有侵权请联系删除,心愿游戏发布此文仅为传递信息,不代表心愿游戏认同其观点或证实其描述。
相关文章
更多-
- 阿里千问开放第三方Agent与Skill接入,瑞幸东航首批测试
- 时间:2026-08-21
-
- 将老员工经验沉淀为Agent可调用资产:Skill与MCP治理实践
- 时间:2026-08-21
-
- Microsoft Agent Framework 1.0发布:Agent开发迈入工程化时代
- 时间:2026-08-21
-
- 郑州GEO源码推荐指南:核心要点与靠谱选择技巧
- 时间:2026-08-18
-
- OpenSkill智能体自进化新范式:孙立超团队刷新多项基准SOTA
- 时间:2026-08-18
-
- 小红书上线RED Skill功能:AI应用深度嵌入社区笔记场景
- 时间:2026-08-18
-
- AI简历优化工具怎么选:校招社招ATS兼容与数据安全指南
- 时间:2026-08-17
-
- AI简历工具推荐:国内与海外及ATS和全流程能力区别
- 时间:2026-08-17
精选合集
更多大家都在玩
大家都在看
更多-
- 2026年9月17日小鸡庄园答案
- 时间:2026-09-16
-
- 蚂蚁庄园今日答案2026年9月17日
- 时间:2026-09-16
-
- 蚂蚁庄园小课堂今日最新答案2026年9月17日
- 时间:2026-09-16
-
- 蚂蚁庄园小鸡答题今日答案2026年9月17日
- 时间:2026-09-16
-
- 褪黑素主要由人体哪个器官分泌 蚂蚁庄园今日答案9.17
- 时间:2026-09-16
-
- 蚂蚁庄园今天答题答案2026年9月17日
- 时间:2026-09-16
-
- 蚂蚁庄园答题今日答案2026年9月17日
- 时间:2026-09-16
-
- 研学旅游指导师的核心服务对象是 蚂蚁新村今日答案2026.9.16
- 时间:2026-09-16
