ARTICLE · INTELLIGENCE

战地情报 · 详情页

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

Agent-Skills:可治理AI能力的契约化设计与工程实践

Agent-Skills:可治理AI能力的契约化设计与工程实践

1. “agent-skills”不是新词,而是能力建模的底层转向

最近在多个技术社区和内部分享中,频繁看到“agent-skills”这个组合词被单独拎出来讨论——它既不指代某个开源库,也不是某家公司的私有协议,更不是某个SDK的命名空间。我第一次在某跨平台系统的需求评审会上听到这个词时,还以为是拼写错误,结果发现前后五位工程师都在用它描述同一类设计意图:把原本散落在Agent主逻辑里的原子能力,显式地抽离、命名、注册、验证,并赋予可编排、可替换、可灰度的生命周期管理能力。

这背后其实是一次静默但深刻的范式迁移:过去我们说“做个智能体”,默认是搭一个LLM调用链+记忆模块+工具调度器;现在说“构建agent-skills”,意味着先回答三个问题:这个能力是否独立可测试?它的输入输出契约是否稳定?当它失效时,上层是否能无感降级?比如“查天气”这个动作,以前可能直接嵌在prompt里让模型自由发挥,现在必须定义成一个skill:输入是{city: string, unit?: 'c' | 'f'},输出是{temperature: number, condition: 'sunny' | 'rainy' | ...},失败时返回{error: 'LOCATION_NOT_FOUND'}而非空字符串或乱码。这种转变,本质上是从“提示工程驱动”走向“契约驱动”。

提示:不要把“agent-skills”理解为“给Agent加技能”,而要理解为“把Agent的能力拆解成可治理的软件单元”。就像微服务不是把单体拆小,而是把职责边界、部署粒度、故障域都重新定义了一遍。

这个词之所以突然密集出现,和最近半年几个关键实践拐点强相关:一是某高校实验室在模拟项目X中发现,当Agent需要对接17个异构API(从内部工单系统到第三方地图服务)时,硬编码的工具调用逻辑导致每次新增一个API都要重测全部32个对话路径;二是某公司上线的客服助手在灰度期间,因“查订单”skill临时不可用,整个Agent陷入静默,而用户根本没收到任何兜底提示——因为“查订单”和“推荐商品”两个skill共用同一个fallback机制,一损俱损。这些真实踩坑场景倒逼团队开始系统性地思考:能力不该是Agent的附属品,而应是与之对等的一等公民。

所以,“agent-skills”真正的价值锚点,从来不在“炫技”或“堆功能”,而在降低复杂系统的耦合熵值。它解决的不是“能不能做”,而是“出了问题能不能快速定位、隔离、修复、验证”。如果你正在设计一个需要长期演进、多人协作、对接多源系统的Agent,那么你现在就该开始规划skills的边界划分、注册协议、测试用例模板和版本兼容策略——而不是等第一个线上事故出现后再补课。

2. Skills不是函数,是带状态契约的可执行单元

很多开发者初接触“agent-skills”概念时,下意识把它等同于“封装好的工具函数”。这是最危险的认知偏差。我见过三支不同团队,在第一版实现中都犯了同样的错:把skill写成一个纯函数,输入参数,输出JSON,然后扔进Agent的tool_call列表。结果上线两周后,全部返工。原因很朴素:函数没有状态,而真实业务能力必然携带上下文依赖与副作用约束。

举个具体例子:“预约会议室”这个skill,表面看只需要{room_id, start_time, duration}三个参数。但实际运行中,它必须隐式依赖:

  • 当前用户的组织架构权限(能否预订VIP会议室?)
  • 日历服务的可用性(若下游503,是重试还是降级为“稍后提醒”?)
  • 历史冲突检测状态(是否已缓存了最近3小时的会议室占用快照?)
  • 甚至本地时区配置(传入的start_time是UTC还是本地时间?)

这些依赖项,如果全靠函数外部注入,就会导致skill调用方(Agent主逻辑)变成一个巨型胶水层,不断搬运context、处理error、做fallback决策。这恰恰违背了skills设计的初衷——解耦。

真正的skills,应该是一个带生命周期管理的可执行单元。我们团队在模拟项目X中最终采用的结构如下:

class MeetingBookingSkill(Skill): def __init__(self, calendar_client: CalendarClient, auth_service: AuthService, cache: RedisCache): # 所有外部依赖在初始化时注入,非调用时传入 self.calendar = calendar_client self.auth = auth_service self.cache = cache def spec(self) -> SkillSpec: # 显式声明能力契约:输入/输出/错误类型/超时/重试策略 return SkillSpec( name="book_meeting", description="预约指定会议室,自动检测时间冲突", input_schema={ "room_id": {"type": "string", "minLength": 3}, "start_time": {"type": "string", "format": "date-time"}, "duration_minutes": {"type": "integer", "minimum": 15} }, output_schema={"booking_id": "string", "status": "string"}, error_codes=["ROOM_UNAVAILABLE", "PERMISSION_DENIED", "CALENDAR_DOWN"], timeout_ms=8000, max_retries=2 ) async def execute(self, inputs: dict) -> SkillResult: # 执行体只关注核心业务逻辑,依赖已由构造器注入 user_perms = await self.auth.get_user_permissions(inputs["room_id"]) if not user_perms.can_book_vip: return SkillResult.error("PERMISSION_DENIED") cached_conflicts = await self.cache.get(f"conflicts_{inputs['room_id']}") if cached_conflicts and self._has_overlap(cached_conflicts, inputs): return SkillResult.error("ROOM_UNAVAILABLE") booking_id = await self.calendar.create_booking(inputs) return SkillResult.success({"booking_id": booking_id})

这个结构的关键突破在于三点:

  1. 契约前置化:spec()方法强制定义了能力的完整契约,包括schema、错误码、SLA指标。这使得Agent调度器能在运行前就做参数校验、路由决策、熔断配置,而不是等到执行中才抛异常。
  2. 依赖容器化:所有外部服务依赖在__init__中注入,而非每次execute都传参。这保证了skill实例的可复用性——同一个skill实例可以被多个Agent并发调用,只要其依赖服务本身是线程安全的。
  3. 状态可感知:skill内部可维护轻量级状态(如缓存句柄、连接池引用),但禁止持有业务状态(如用户session)。这划清了“能力状态”与“会话状态”的边界。

注意:skill绝不应该持有user_id、session_id这类会话级数据。这些必须作为inputs参数传入,由Agent主逻辑统一管理。否则skills将失去可测试性和可复用性——你无法用固定输入复现一个依赖随机session的skill行为。

我们实测过:当skills按此结构实现后,单个skill的单元测试覆盖率从平均42%提升至91%,而Agent主逻辑的代码量减少了37%。因为大量原本分散在各处的权限校验、错误分类、重试逻辑,都被收敛到了skill自身的execute方法内。这才是“解耦”的真实收益:不是代码行数变少,而是责任归属变得无比清晰。

3. 注册中心:skills的“交通指挥台”与“质量守门员”

当团队开始认真对待skills时,第二个必然出现的组件就是注册中心(Registry)。很多人以为这只是个简单的字典映射:{"book_meeting": BookMeetingSkill()}。但我们在某跨平台系统中踩过一次大坑:初期用内存字典注册,上线后发现skills的热更新、灰度发布、AB测试全部无法落地,最后不得不推翻重做。这才意识到:注册中心不是技能仓库,而是skills的治理中枢。

一个生产级的skills注册中心,必须同时承担三重角色:

3.1 路由指挥官:动态解析与精准分发

当Agent收到用户指令“帮我订明天下午三点的会议室”,NLU模块会解析出意图book_meeting和参数{"start_time": "2024-06-15T15:00:00Z"}。此时注册中心不能简单匹配skill名称,而要基于完整的契约信息做决策:

决策维度说明实际案例
版本路由同一skill名可注册多个版本,按语义化版本号或标签路由book_meeting@v1.2(灰度) vsbook_meeting@stable(全量)
环境路由根据当前运行环境(dev/staging/prod)选择不同实现dev环境用MockCalendar,prod环境用真实CalendarClient
能力路由基于输入参数特征选择最优skill当room_id以"VIP-"开头,路由到VIPMeetingBookingSkill而非通用版

我们团队开发的注册中心支持DSL式路由规则:

routes: - when: "input.room_id.startsWith('VIP-') && env == 'prod'" then: "book_meeting@vip-prod" - when: "input.duration_minutes > 120" then: "book_meeting@long-duration" - else: "book_meeting@default"

这种声明式路由,让业务逻辑彻底从Agent主流程中剥离。Agent只需说“我要执行book_meeting”,注册中心自动决定用哪个实例、传什么参数、设什么超时。

3.2 质量守门员:准入检查与健康巡检

注册中心绝不能无条件接纳所有skill。我们在模拟项目X中设置了四级准入卡点:

  1. 契约校验:强制spec()返回值必须包含完整schema、错误码列表、timeout。缺失任一项拒绝注册。
  2. 签名验证:所有skill类必须继承Skill基类,且execute方法签名必须为async def execute(self, inputs: dict) -> SkillResult。利用Python的typing.get_type_hints做静态检查。
  3. 冒烟测试:注册时自动触发预设的最小用例集(如{"room_id":"R101","start_time":"2024-01-01T10:00:00Z","duration_minutes":30}),要求100%通过才允许上线。
  4. 健康探针:注册后每30秒调用skill的health_check()方法(需skill自行实现),连续3次失败则自动标记为DEGRADED,路由时优先避开。

这套机制让我们在一次数据库主从切换中提前17分钟发现book_meetingskill的读库连接池异常——因为健康探针持续失败,而业务流量尚未涌入。如果没有注册中心的主动巡检,这个问题会等到用户真实预约失败后才被监控告警捕获。

3.3 治理仪表盘:可观测性与变更审计

注册中心必须提供实时视图,让所有人看清skills的运行状态。我们内置的仪表盘包含三个核心视图:

  • 拓扑图:展示skills之间的依赖关系(如book_meeting依赖auth_service和calendar_client),点击节点可查看最近1小时的成功率、P95延迟、错误分布。
  • 变更日志:记录每一次skill注册、注销、版本更新的操作人、时间、Git commit hash。某次线上故障回溯时,正是靠这条日志锁定是v1.3版本引入了未处理的时区转换bug。
  • 流量热力图:按小时统计各skill的调用量、错误率、平均耗时,用颜色深浅直观呈现瓶颈。我们曾据此发现get_weatherskill在每天上午9-10点出现周期性超时,最终定位到是第三方API的免费额度用尽。

提示:注册中心的API设计必须遵循“幂等注册”原则。同一skill多次注册(如因服务重启)不应产生重复实例,而应触发更新操作。我们用(name, version)作为唯一键,避免因重复注册导致内存泄漏。

真正成熟的注册中心,会让skills从“代码片段”升维为“可运营资产”。当你能随时回答“哪个skill最近一周错误率最高?”、“book_meeting的v1.2版本影响了多少用户?”、“如果下线legacy_paymentskill,哪些上游服务会受影响?”——你就拥有了Agent系统真正的治理能力。

4. 测试金字塔:从单元到混沌,构建skills可信度

Skills一旦被设计为独立可治理单元,其测试策略就必须彻底重构。我们团队在某图像处理Demo项目中做过对比实验:对同一组skills,分别采用传统“集成到Agent里测”和“skills专项测试”两种方式。结果发现,前者平均每个bug定位耗时47分钟,后者仅需6分钟;前者上线后平均每月发生2.3次skills相关故障,后者连续7个月零故障。差异根源就在于测试金字塔的根基是否扎实。

4.1 单元测试:契约驱动的穷举验证

skills的单元测试,核心不是“覆盖多少行代码”,而是“验证多少条契约”。我们强制要求每个skill必须包含四类测试用例:

  1. 正向流测试:验证标准输入下的成功路径
  2. 边界值测试:针对schema中定义的min/max/length做穷举
  3. 错误码测试:对spec().error_codes中每个错误码,构造对应触发条件
  4. 超时/重试测试:模拟依赖服务延迟或失败,验证重试逻辑与最终错误码

以book_meeting为例,其错误码测试用例必须覆盖:

  • PERMISSION_DENIED:当用户无权限预订VIP会议室时
  • ROOM_UNAVAILABLE:当缓存中存在时间冲突时
  • CALENDAR_DOWN:当calendar_client.create_booking()抛出网络异常时

我们使用pytest + pytest-asyncio编写,关键技巧是用dependency injection替换真实依赖:

# conftest.py 中预置mock fixtures @pytest.fixture def mock_auth_service(): service = MockAuthService() service.set_permission("R101", can_book_vip=False) # 预设权限 return service @pytest.fixture def mock_calendar_client(): client = MockCalendarClient() client.set_failure_rate(0.1) # 10%概率抛异常 return client # test_book_meeting.py @pytest.mark.asyncio async def test_book_meeting_permission_denied(mock_auth_service, mock_calendar_client): skill = MeetingBookingSkill( calendar_client=mock_calendar_client, auth_service=mock_auth_service, cache=MockCache() ) result = await skill.execute({ "room_id": "VIP-101", "start_time": "2024-06-15T10:00:00Z", "duration_minutes": 30 }) assert result.is_error() assert result.error_code == "PERMISSION_DENIED"

这种测试方式,让每个skill的单元测试都能在毫秒级完成,且100%隔离外部环境。我们要求单元测试覆盖率必须达到90%以上,且所有error_code必须有对应测试用例——这是保障skills可靠性的底线。

4.2 集成测试:端到端契约验证

单元测试确保skill内部逻辑正确,集成测试则验证它与真实依赖的交互是否符合契约。我们搭建了轻量级集成测试环境,特点如下:

  • 依赖沙盒化:每个测试用例启动独立的Docker容器运行mock服务(如MockCalendar、MockAuth),端口随机分配,避免端口冲突。
  • 契约快照比对:测试运行后,自动抓取skill的实际输入输出(含headers、query params、body),与预设的OpenAPI 3.0契约快照比对。任何字段缺失、类型不符、枚举值越界都会失败。
  • 性能基线校验:记录P50/P95/P99延迟,与历史基线对比。若P95增长超过20%,测试即告失败,防止性能劣化悄然上线。

集成测试不追求高并发,而追求精确复现生产环境的数据契约。我们曾用此方法捕获一个严重bug:book_meetingskill在处理start_time时,将ISO格式字符串错误解析为本地时间戳,导致跨时区用户预约时间偏移。这个bug在单元测试中无法暴露(因为mock输入是固定字符串),但在集成测试中,当mock calendar服务返回带时区的RFC3339时间时立刻暴露。

4.3 混沌测试:在故障中验证韧性

最高阶的测试,是主动制造混乱。我们在生产环境的预发布集群中,对skills实施混沌工程:

  • 网络混沌:随机注入500ms~2s网络延迟到calendar_client调用
  • 依赖混沌:随机返回503错误给auth_service.get_user_permissions
  • 资源混沌:限制skill进程的CPU配额至100m,观察OOM行为

混沌测试不期望100%成功,而是要验证:

  • skill是否在超时后正确返回预设error_code(而非抛出未捕获异常)
  • Agent是否能根据error_code做出合理fallback(如ROOM_UNAVAILABLE时推荐其他时段)
  • metrics是否准确上报失败类型与延迟分布

我们坚持每周执行一次混沌测试,每次持续15分钟。过去三个月,共发现并修复了7个韧性缺陷,其中3个涉及skills的错误码传播链断裂——比如skill内部捕获了ConnectionError,但返回了泛化的INTERNAL_ERROR,导致Agent无法区分是网络问题还是业务逻辑问题。

注意:混沌测试必须在受控环境中进行,且所有注入故障必须有自动恢复机制(如5分钟后自动清除延迟规则)。我们严禁在生产环境直接运行混沌实验。

测试金字塔的每一层,都在加固skills的可信度。当你的skills能通过这三层考验,它就不再是一个“能跑的函数”,而是一个“可信赖的契约实体”。这才是“agent-skills”范式真正的护城河。

5. 运维实战:从日志到告警,skills的可观测性落地

当skills规模超过20个、日均调用量破百万后,运维挑战会指数级上升。我们团队在某跨平台系统中经历过一次典型故障:用户反馈“预约会议室总是失败”,但监控显示book_meetingskill成功率99.8%,P95延迟仅120ms。排查耗时3小时,最终发现是auth_service的token刷新接口在凌晨2点批量失效,导致所有skills的权限校验失败,但错误被统一吞掉,只返回模糊的INTERNAL_ERROR。这个教训让我们彻底重构了skills的可观测性体系。

5.1 结构化日志:让每一行日志都可查询

skills的日志绝不能是print("booking started")这样的字符串。我们强制所有skill使用结构化日志框架(如Python的structlog),每条日志必须包含以下字段:

字段类型说明示例
skill_namestring技能名称"book_meeting"
skill_versionstring技能版本"v1.3"
request_idstring全局请求ID(透传自Agent)"req-abc123"
input_hashstring输入参数的SHA256哈希(脱敏)"a1b2c3..."
stagestring执行阶段"pre_check","calling_auth","parsing_response"
error_codestring错误码(仅错误时)"PERMISSION_DENIED"
duration_msfloat当前阶段耗时42.7

关键技巧是日志字段必须与metrics指标严格对齐。例如,当error_code为PERMISSION_DENIED时,对应的metrics计数器skill_errors_total{skill="book_meeting",error_code="PERMISSION_DENIED"}必须+1。这样就能用同一套标签在日志系统(如Loki)和监控系统(如Prometheus)中交叉查询。

故障复盘时,我们只需在Loki中执行:

{job="skills"} |~ `book_meeting` | json | __error_code="PERMISSION_DENIED" | line_format "{{.request_id}} {{.input_hash}}"

瞬间获取所有失败请求的ID和输入指纹,再用这些ID去追踪完整调用链。效率提升十倍不止。

5.2 指标体系:聚焦四个黄金信号

我们为每个skill定义了四个不可妥协的黄金指标(Golden Signals),全部通过OpenTelemetry自动埋点:

  1. 成功率(Success Rate):success_count / (success_count + error_count)
    阈值:生产环境≥99.5%,低于则触发P2告警

  2. 延迟(Latency):P95和P99分位延迟
    阈值:P95 ≤ 200ms,P99 ≤ 1500ms;超阈值持续5分钟触发P3告警

  3. 错误码分布(Error Code Distribution):按error_code分组的错误计数
    关键洞察:若CALENDAR_DOWN占比突增,说明下游服务异常;若PERMISSION_DENIED突增,可能是权限策略变更

  4. 饱和度(Saturation):技能实例的CPU/内存/连接池使用率
    阈值:连接池使用率≥90%持续10分钟,触发扩容建议

这些指标全部接入Grafana,我们为每个skill定制专属看板,包含:

  • 实时成功率热力图(按小时粒度)
  • 错误码TOP5排行榜(带同比变化)
  • 延迟分布直方图(对比上周基线)
  • 依赖服务健康度雷达图(显示所依赖的auth/calendar/cache的当前状态)

5.3 告警策略:从“通知”到“可行动”

告警不是越多越好,而是要确保每一条告警都附带可立即执行的诊断步骤。我们为skills告警设计了三级响应机制:

告警级别触发条件响应动作附带信息
P1(立即响应)成功率<95% 或 P99延迟>5s 持续2分钟电话告警+自动创建Jira包含最近10个失败request_id、错误码分布、关联的依赖服务状态
P2(高优处理)成功率95%~99.5% 或 P95延迟>200ms 持续10分钟企业微信告警+自动Runbook包含标准排查Checklist:
1. 检查auth_service健康探针
2. 查询book_meeting最近1小时错误码TOP3
3. 查看calendar_client连接池使用率
P3(低优关注)错误码INTERNAL_ERROR占比>5% 持续30分钟邮件汇总+每日简报包含错误堆栈关键词提取(如"TimeoutError"、"KeyError")、关联的Git提交记录

最关键的创新是告警自动附带Runbook链接。当P2告警触发时,企业微信消息中直接给出:

🔧 排查指南:https://runbook.internal/skills/book_meeting/p2 ✅ 已执行:检查auth_service健康探针 → OK ✅ 已执行:查询错误码TOP3 → PERMISSION_DENIED占82% ⚠️ 待执行:检查权限策略变更记录(最近3次部署)

这个Runbook页面由CI/CD流水线自动生成,每次skill部署都会更新。它把“经验”固化为“可执行代码”,让初级工程师也能快速响应高级故障。

提示:所有告警必须设置“静默期”和“抑制规则”。例如,当auth_service整体宕机时,所有依赖它的skills的P1告警应被抑制,只保留auth_service自身的告警。否则会引发告警风暴。

可观测性不是锦上添花,而是skills生产化的生命线。当你能用一条命令查清“为什么这个skill在特定输入下返回了错误码X”,当你能用一张图表说清“这个错误码的增长是否与某次部署强相关”,你就真正掌握了skills的运维主动权。

6. 进阶实践:skills的版本演进、灰度与AB测试

当skills体系稳定运行后,真正的挑战才开始:如何在不中断服务的前提下,持续迭代skills?我们团队在模拟项目X中摸索出一套经过千次线上验证的演进策略,核心思想是把skills当作独立服务来治理,而非Agent的内部模块。

6.1 语义化版本:从v1到v1.2.3的演进哲学

skills的版本号不是随意递增的,而是严格遵循语义化版本(SemVer)规范,并赋予每一级数字明确的业务含义:

版本层级变更类型对Agent的影响示例
主版本(MAJOR)破坏性变更:修改input_schema、删除error_code、改变output_schema结构Agent必须同步修改调用代码,否则启动失败v1→v2:start_time从string改为timestamp integer
次版本(MINOR)向后兼容增强:新增error_code、扩展input_schema(非必填字段)、优化算法Agent无需修改,可自动受益v1.1→v1.2:新增error_code="TIMEZONE_MISMATCH"
修订版本(PATCH)向后兼容修复:修正bug、提升性能、调整日志粒度完全透明升级,Agent无感知v1.2.1→v1.2.2:修复时区转换精度丢失

关键实践是版本升级必须伴随契约快照比对。我们开发了一个CI检查脚本,每次提交skills代码时:

  1. 自动提取新旧spec()返回值
  2. 使用JSON Schema Diff工具计算变更类型
  3. 若检测到破坏性变更(如required字段删除),强制要求PR标题包含[BREAKING]前缀,并附带迁移指南

这套机制让我们在半年内完成了127次skills升级,零次因版本不兼容导致的线上故障。

6.2 灰度发布:从1%到100%的渐进式验证

skills的灰度不是简单按流量比例切分,而是结合多维权重的精细化控制。我们注册中心支持的灰度策略包括:

  • 用户分群灰度:按用户ID哈希,将VIP用户100%切到新版本,普通用户按比例切分
  • 地域灰度:先在华东区100%发布,验证通过后再推向全国
  • 设备灰度:iOS用户先上,Android用户后上(因iOS客户端更新更快)
  • 行为灰度:对高频使用book_meeting的用户(周均>5次)先灰度,低频用户后灰度

灰度配置以YAML形式管理,支持动态加载:

book_meeting: v1.3: weight: 0.05 # 全局5%流量 rules: - when: "user.tier == 'VIP'" weight: 1.0 # VIP用户100%走v1.3 - when: "user.region == 'shanghai'" weight: 0.2 # 上海用户20%走v1.3

灰度期间,我们重点关注三个指标:

  1. 成功率对比:v1.3成功率是否显著低于v1.2(P值<0.01)
  2. 错误码漂移:v1.3是否引入新的错误码,或原有错误码分布是否异常
  3. 业务指标影响:预约成功率、平均预约时长等终端业务指标是否恶化

只有当这三项全部达标,才推进到下一阶段灰度。我们曾用此方法在v1.3中发现一个隐蔽bug:新版本在处理duration_minutes=0时会无限循环,但因灰度只开5%,且duration_minutes=0是极低概率输入,该bug在灰度期就被捕获,未影响任何真实用户。

6.3 AB测试:用数据驱动技能决策

当需要评估两个skills方案的优劣时(如“用规则引擎vs用ML模型做会议室推荐”),我们启用AB测试框架。与常规AB测试不同,skills的AB测试有两大特性:

  1. 多层嵌套:AB测试可嵌套在灰度策略内。例如,先对上海VIP用户灰度v1.3,再在其中50%用户中AB测试recommender_rulevsrecommender_ml。
  2. 指标联动:AB测试结果不仅看skills自身指标(成功率、延迟),更要看终端业务指标。例如,recommender_ml版本虽然成功率略低(98.2% vs 98.5%),但用户最终预约成功率提升了3.7%(因推荐更精准),这就成为上线决定性依据。

AB测试报告自动生成,包含:

  • 统计显著性分析(T检验、卡方检验)
  • 影响用户数与业务价值估算(如“预计每月多成交XX笔预约”)
  • 失败根因推测(如“recommender_ml在雨天推荐准确率下降,因训练数据缺乏雨天样本”)

最后分享一个血泪教训:某次AB测试中,我们只监控了skills的P95延迟,发现recommender_ml版本慢了15ms,于是判定为“性能劣化”而放弃。但上线后发现,该版本因推荐更准,用户平均只需1.2次交互就完成预约,而规则版需1.8次。这意味着总用户体验延迟反而降低了。从此我们规定:AB测试必须包含“端到端用户旅程指标”,不能只看单点性能。

skills的演进,本质是产品思维在技术组件上的投射。当你能把一个skill当作一个独立产品来规划版本、设计灰度、运行AB测试,你就真正理解了“agent-skills”的终极意义:让AI能力的交付,像互联网产品一样敏捷、可衡量、可进化。

RELATED READING

延伸阅读

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