AI 系统该用 Skill 还是 Sub-Agent:用复杂度和维护成本做决策

2026-08-04 64 预计阅读时间: 1 分钟
来源: infoq.com AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:8 分钟

在 AI 应用里,把一段能力封装成 Skill,还是交给独立的 Sub-Agent,并不只是命名问题。这个选择会直接影响系统的上下文管理、调试难度、复用方式和长期维护成本。Azure 架构实践提出的核心判断标准很务实:优先考虑可复用性、简单性和长期可维护性,而不是默认把所有复杂任务都拆成多个 Agent。

Skill 和 Sub-Agent 解决的是不同问题

可以把 Skill 理解为主 Agent 可直接调用的一项受控能力。它通常有清晰输入和输出,执行边界稳定,不需要独立维护长期上下文。例如:

  • 查询订单状态
  • 生成 SQL 并执行只读查询
  • 从文档中提取结构化字段
  • 按固定规则检查代码或配置

Sub-Agent 则更接近一个被委派任务的独立执行者。它可以拥有自己的提示词、工具集合、上下文和执行循环,适合需要多步规划、反复验证或专业隔离的任务。例如,一个代码审查 Sub-Agent 可能需要读取多个文件、运行测试、分析差异,再汇总风险。

两者的关键差异不是“能力强弱”,而是自治程度。Skill 通常完成一次边界明确的调用;Sub-Agent 需要在目标约束下自行决定下一步行动。

先问三个工程问题

1. 能力是否具有稳定、可复用的接口

如果多个工作流都会以相同参数调用这项能力,而且结果格式可以稳定定义,优先封装为 Skill。稳定接口便于测试、版本管理和替换实现。

例如,“根据客户 ID 查询最近五笔订单”很适合做成 Skill。调用方不必知道数据库结构,也不需要为它创建一个能够自主规划的 Agent。

2. 任务是否真的需要独立规划

只有当任务必须分解步骤、选择工具、检查中间结果并根据结果调整计划时,Sub-Agent 的额外复杂度才可能合理。

如果主 Agent 已经知道应该调用哪个工具、传入什么参数,以及如何消费结果,再增加一层 Sub-Agent 往往只会引入更多提示词、消息传递和失败状态。

3. 团队能否承担它的运行与维护成本

Sub-Agent 不只是多一个模型调用。工程上还要处理:

  • 独立上下文的构造和裁剪
  • 工具权限与数据访问边界
  • 超时、重试和循环终止条件
  • 多 Agent 之间的追踪与日志关联
  • 模型升级后的回归测试
  • Token、延迟和并发成本

如果这些机制没有明确收益,保持单 Agent 加 Skills 的结构通常更容易维护。

一个可执行的选择器

下面是一个可以直接运行的最小决策示例。它不是 Azure 指南的原始 API 或官方评分公式,而是根据“复用、简单和维护性优先”的原则整理出的工程化实践。团队可以修改阈值,并把实际生产指标接入评分过程。

将代码保存为 choose_component.py,然后运行 python choose_component.py

from dataclasses import dataclass
from enum import Enum


class Component(str, Enum):
    FUNCTION = "plain function or deterministic workflow"
    SKILL = "skill"
    SUB_AGENT = "sub-agent"


@dataclass(frozen=True)
class TaskProfile:
    reusable: bool
    needs_planning: bool
    needs_isolated_context: bool
    chooses_between_tools: bool
    deterministic: bool


def choose_component(task: TaskProfile) -> Component:
    # 不需要模型推理时,普通函数或确定性工作流更简单。
    if task.deterministic and not task.needs_planning:
        return Component.FUNCTION

    autonomy_signals = sum(
        [
            task.needs_planning,
            task.needs_isolated_context,
            task.chooses_between_tools,
        ]
    )

    # 多个自治信号同时存在时,独立 Agent 才更可能值得。
    if autonomy_signals >= 2:
        return Component.SUB_AGENT

    # 可复用且边界明确的模型能力适合封装为 Skill。
    if task.reusable:
        return Component.SKILL

    return Component.FUNCTION


examples = {
    "extract_invoice_fields": TaskProfile(
        reusable=True,
        needs_planning=False,
        needs_isolated_context=False,
        chooses_between_tools=False,
        deterministic=False,
    ),
    "investigate_repository_failure": TaskProfile(
        reusable=False,
        needs_planning=True,
        needs_isolated_context=True,
        chooses_between_tools=True,
        deterministic=False,
    ),
    "validate_email_address": TaskProfile(
        reusable=True,
        needs_planning=False,
        needs_isolated_context=False,
        chooses_between_tools=False,
        deterministic=True,
    ),
}

for name, profile in examples.items():
    print(f"{name}: {choose_component(profile).value}")

预期输出如下:

extract_invoice_fields: skill
investigate_repository_failure: sub-agent
validate_email_address: plain function or deterministic workflow

这个例子还强调了一个容易忽略的选项:并非所有能力都需要 Skill 或 Agent。格式校验、权限判断、字段转换等确定性逻辑,应优先使用普通代码。让模型执行可由规则准确完成的任务,会增加成本和不确定性。

把组件边界写进契约

无论最终选择 Skill 还是 Sub-Agent,都应该定义可测试的输入输出。可以这样实践:为每个组件维护一份简短契约。

name: investigate_repository_failure
kind: sub-agent
objective: "定位测试失败的根因,并给出带证据的修复建议"
inputs:
  required:
    - repository_path
    - failing_command
outputs:
  schema:
    root_cause: string
    evidence: array
    suggested_changes: array
tools:
  allowed:
    - read_file
    - search_code
    - run_tests
limits:
  max_steps: 12
  timeout_seconds: 180
  can_modify_files: false

对于 Skill,同一份契约通常可以更窄:减少可用工具,取消自主步骤,并要求稳定的结构化结果。契约越清楚,调用方越不依赖内部提示词,后续替换模型或实现方式也越容易。

采用前的检查清单

准备引入 Sub-Agent 时,可以快速检查以下问题:

  • 普通函数、工作流或现有 Skill 是否已经足够?
  • 任务是否至少包含两个明确的自治需求,例如规划、工具选择和上下文隔离?
  • 是否定义了停止条件、超时和最大步骤数?
  • 是否限制了它能访问的工具、数据和写操作?
  • 是否能单独评估其结果质量、延迟和成本?
  • 出错时,日志能否还原主 Agent 与 Sub-Agent 之间的调用链?

更稳妥的演进路径是从普通代码开始,在需要模型能力时提升为 Skill,只有在独立规划带来可测量收益时再拆出 Sub-Agent。架构的目标不是让 Agent 数量更多,而是让每个组件拥有足够且不过量的自治能力。


相关推荐