芥末
发布于 2025-12-08 / 0 阅读
0
0

Claude Agent 架构:MCP、PTC、Skills 与 Subagents 的分层协同

Claude 生态里的 Agent 能力,可以拆成三个层次理解:

  • MCP + PTC:解决“怎么连接外部系统、怎么高效调用工具”的问题。
  • Skills:解决“遇到某类任务时,大模型应该按什么流程做”的问题。
  • Subagents:解决“一个复杂任务怎么拆给不同角色分别处理”的问题。

这三者不是互相替代的关系,而是分别位于 Agent 系统的不同位置。

flowchart TB
    User[用户任务] --> MainAgent[主 Agent]

    MainAgent --> Subagents[组织层:Subagents<br/>拆分任务、隔离上下文、分配角色]
    Subagents --> Skills[认知层:Skills<br/>注入领域流程、模板、脚本、示例]
    Skills --> Tools[连接层:MCP + PTC<br/>访问外部系统、批量编排工具调用]

    Tools --> DB[(数据库)]
    Tools --> Files[(文件系统)]
    Tools --> API[业务 API]
    Tools --> SaaS[第三方服务]

    Subagents --> MainAgent
    MainAgent --> Result[最终结果]

一个成熟的 Agent 系统通常不会只靠一个大 Prompt 解决所有事情。Prompt 负责定义目标和边界,MCP 负责连接外部世界,Skills 负责提供任务知识,Subagents 负责把复杂工作组织起来。理解这几个机制的分工,才能设计出可维护、可扩展的 Agent 应用。


MCP:把外部系统标准化暴露给 Agent

MCP(Model Context Protocol,模型上下文协议)可以理解为 Agent 访问外部资源的一套标准接口。

没有 MCP 时,如果希望大语言模型访问数据库、读取本地文件、调用企业内部服务,通常要给每一种资源单独写适配代码。例如:

  • 查询订单数据库,需要写一套数据库查询工具;
  • 读取代码仓库,需要写一套文件读取工具;
  • 调用客户系统 API(Application Programming Interface,应用程序编程接口),又要写一套 HTTP 封装;
  • 换一个 Agent 框架,这些工具还可能需要重新接一遍。

MCP 的作用,是把这些外部能力封装成 MCP Server,再由具备 MCP Client 能力的 Agent 统一接入。

flowchart LR
    Agent[Agent / LLM 应用] --> MCPClient[MCP Client]

    MCPClient --> ServerA[MCP Server:文件系统]
    MCPClient --> ServerB[MCP Server:数据库]
    MCPClient --> ServerC[MCP Server:业务系统]
    MCPClient --> ServerD[MCP Server:第三方 API]

    ServerA --> File[(本地文件)]
    ServerB --> DB[(企业数据库)]
    ServerC --> Biz[内部服务]
    ServerD --> ThirdParty[外部平台]

MCP 的价值不在于“多了一个工具调用格式”,而在于它把 Agent 和外部系统之间的连接方式标准化了。开发者只要把某个系统封装成 MCP Server,其他支持 MCP 的 Agent 就可以复用这套能力。

常见的 MCP Server 可以暴露三类能力:

类型作用示例
Tools让 Agent 执行动作查询数据库、写文件、调用接口、运行命令
Resources让 Agent 读取资源文档、配置、日志、代码文件
Prompts提供可复用提示模板代码审查模板、报告生成模板、分析流程模板

MCP 解决的是“能不能连接”和“怎么标准化连接”的问题。但当 Agent 需要连续调用很多工具时,只靠普通工具调用循环还不够。


普通工具调用的问题:LLM 和工具之间来回“乒乓”

传统 Agent 工具调用通常是这样的:

sequenceDiagram
    participant U as 用户
    participant L as LLM
    participant T as 工具

    U->>L: 提出复杂任务
    L->>T: 调用工具 A
    T-->>L: 返回大量中间结果
    L->>L: 读取结果并推理下一步
    L->>T: 调用工具 B
    T-->>L: 返回中间结果
    L->>L: 再次推理
    L->>T: 调用工具 C
    T-->>L: 返回结果
    L-->>U: 输出答案

这种模式适合需要大语言模型逐步判断的任务,但在确定性流程里会带来两个明显问题。

延迟高。
每调用一次工具,都要经历一次模型推理、一次工具执行、一次结果回填。复杂任务里如果有几十次调用,响应时间会被放大。

Token 成本高。
工具返回的中间结果往往会被塞进上下文。数据量越大,占用的 Token 越多,后续推理还可能被无关细节干扰。

例如,“查询所有订单,再按地区汇总销售额,最后生成图表”这个任务本质上是一个确定性数据处理流程。让大语言模型每一步都参与决策,反而浪费。


PTC:让模型写程序来编排工具调用

PTC(Programmatic Tool Calling,程序化工具调用)的核心思路是:让大语言模型生成一段完整程序,由安全沙箱执行,程序里直接调用多个工具并处理结果。

也就是说,Agent 不再是“想一步、调一步、再想一步”,而是把可确定的流程写成代码一次执行。

sequenceDiagram
    participant U as 用户
    participant L as LLM
    participant S as 沙箱运行环境
    participant T as MCP 工具

    U->>L: 提出数据处理任务
    L->>S: 生成并提交程序
    S->>T: 调用工具 A 查询数据
    T-->>S: 返回数据
    S->>S: 过滤、聚合、计算
    S->>T: 调用工具 B 生成图表
    T-->>S: 返回图表
    S-->>L: 返回精简结果
    L-->>U: 输出最终答案

对比普通工具调用,PTC 的关键变化在于:中间数据尽量留在沙箱里处理,只把最终结果或必要摘要返回给模型。

一个简化示例:

orders = await toolA.query_orders(
    start_date="2026-01-01",
    end_date="2026-01-31"
)

region_sales = {}

for order in orders:
    region = order["region"]
    amount = order["amount"]
    region_sales[region] = region_sales.get(region, 0) + amount

chart = await toolB.generate_bar_chart(
    title="January Sales by Region",
    data=region_sales
)

return {
    "summary": region_sales,
    "chart": chart
}

在这个流程里,大语言模型只需要规划代码逻辑;查询、循环、聚合、生成图表都在程序中完成。这样可以减少多轮模型调用,也避免把完整订单列表反复塞进上下文。


PTC 适合什么,不适合什么

PTC 并不是替代所有 Agent 循环的方案。它适合“流程明确、判断规则清楚、可以写成程序”的任务,不适合“每一步都需要语义理解和开放式判断”的任务。

任务类型是否适合 PTC原因
批量查询数据后聚合统计适合查询、过滤、分组、计算都能写成代码
读取多个文件并提取固定字段适合规则明确,适合循环处理
调用多个 API 后拼装报告数据适合工具调用顺序和数据转换逻辑确定
根据合同内容判断法律风险不太适合风险判断依赖语义理解和专业推理
根据用户反馈动态改变调查方向不太适合下一步取决于模型对上下文的判断
多轮谈判、写作、审稿不太适合过程本身需要持续推理和语言判断

判断标准可以很简单:如果任务能被清楚写成伪代码,大概率适合 PTC;如果下一步必须依赖大语言模型理解内容再决策,更适合传统 Agent 循环。

flowchart TD
    A[任务需要调用多个工具] --> B{流程是否基本固定}
    B -- 是 --> C{中间结果是否主要用于计算/过滤/转换}
    C -- 是 --> D[优先考虑 PTC]
    C -- 否 --> E[普通 Agent 循环]
    B -- 否 --> F{是否需要 LLM 每步做语义判断}
    F -- 是 --> E
    F -- 否 --> G[可混合使用:部分步骤用 PTC]

Skills:给 Agent 按需加载的任务知识

MCP 解决的是“工具在哪里”,PTC 解决的是“怎么高效调用工具”。但 Agent 还需要知道“某类任务应该怎么做”。

例如:

  • 处理 PDF(Portable Document Format,便携式文档格式)时,应该用哪些库、按什么流程提取文本;
  • 生成项目报告时,应该遵循什么模板;
  • 创建 React 项目时,目录结构、配置文件、命名规范应该怎么安排;
  • 执行代码审查时,应该重点检查哪些风险。

如果把所有任务指南都写进系统 Prompt,上下文会很快膨胀。Skills 的设计目标,就是把这些可复用的任务知识模块化,并按需加载。

一个 Skill 通常是一个目录,里面包含说明文件、脚本、模板和示例资源:

pdf-processing/
├── SKILL.md
├── scripts/
│   ├── extract_text.py
│   └── split_pages.py
├── templates/
│   └── extraction_report.md
└── examples/
    ├── scanned_pdf_notes.md
    └── table_extraction.md

其中最关键的是 SKILL.md。它通常包含两类信息:

  1. 元数据:名称、描述,用来让模型判断什么时候应该使用这个 Skill。
  2. 完整指南:任务步骤、注意事项、可用脚本、输入输出格式、示例。

一个简化版 SKILL.md 可以这样写:

---
name: pdf-processing
description: Extract text, tables, and metadata from PDF files. Use this skill when the user asks to read, convert, summarize, or analyze PDF documents.
---

# PDF Processing Skill

Use this skill when the task involves PDF files.

## Workflow

1. Check whether the PDF is text-based or scanned.
2. For text-based PDFs, use `scripts/extract_text.py`.
3. For scanned PDFs, run OCR before extracting content.
4. Preserve page numbers in the output.
5. If tables are detected, export them separately as CSV.

## Available scripts

- `scripts/extract_text.py`: extract text page by page.
- `scripts/split_pages.py`: split a large PDF into page images.

## Output format

Return:

- document title if available
- page count
- extracted text
- table files if generated
- warnings for unreadable pages

Skills 的关键点不是“给模型增加一个工具按钮”,而是“给模型一份可复用的操作手册”。模型在识别到任务类型后,读取对应 Skill,再按 Skill 中的流程执行。


Skills 的核心机制:渐进式披露

Skills 不能把所有内容一次性塞进上下文,否则会回到上下文爆炸的问题。它采用的是渐进式披露(Progressive Disclosure):模型一开始只看到每个 Skill 的简短描述,真正需要使用某个 Skill 时,再加载完整说明和相关资源。

flowchart TD
    A[会话开始] --> B[加载所有 Skills 的 name 和 description]
    B --> C[LLM 判断当前任务匹配哪个 Skill]
    C --> D{是否需要某个 Skill}
    D -- 否 --> E[按普通方式处理]
    D -- 是 --> F[加载对应 SKILL.md 全文]
    F --> G{是否需要额外资源}
    G -- 否 --> H[执行任务]
    G -- 是 --> I[按需读取脚本、模板、示例、文档]
    I --> H

这种机制把 Skill 分成了三层:

层级加载内容目的
技能发现namedescription让模型知道有哪些技能可用
技能理解完整 SKILL.md让模型理解任务流程和约束
资源加载脚本、模板、示例、文档任务执行时按需读取具体材料

这样做的好处很直接:系统可以拥有很多 Skills,但每次任务只加载少量相关内容。上下文里保留的是当前任务需要的信息,而不是所有可能用到的知识。


Skills 与工具的区别

Skills 很容易和工具混在一起,但两者定位不同。

对比项Tool / MCP ToolSkill
核心作用执行一个外部动作告诉模型某类任务怎么做
典型形式函数、API、命令文件夹、说明文档、脚本、模板
调用方式模型请求执行工具模型读取技能指南后规划执行
解决问题“能不能操作外部系统”“应该按什么流程操作”
示例查询数据库、读文件、发请求PDF 处理流程、报告模板、代码规范

一个 Skill 内部可以使用工具,也可以包含脚本。比如 PDF Skill 可以告诉模型调用文件读取工具获取 PDF,再使用目录里的 Python 脚本提取文本。这样比完全依赖模型临时生成代码更稳定,也更容易维护。


Subagents:把复杂任务拆给多个专门 Agent

当任务足够复杂时,一个 Agent 同时承担多个角色会变得难以控制。

例如,“给一个项目生成完整技术报告”可能包含这些子任务:

  • 阅读代码结构;
  • 检查安全风险;
  • 运行测试;
  • 分析提交历史;
  • 更新文档;
  • 汇总最终报告。

如果把所有指令、工具、文件内容、测试日志、安全审计结果都塞进同一个上下文,模型很容易出现两个问题。

角色混乱。
同一个 Agent 既要像架构师一样做设计判断,又要像测试工程师一样关注失败日志,还要像文档工程师一样整理表达。多个角色的目标可能互相干扰。

上下文污染。
测试日志、工具输出、代码片段、审查意见混在一起,主任务目标会被稀释。模型可能在后续步骤里过度关注某个中间细节,忘记整体交付目标。

Subagents 的做法是把复杂任务拆开,由不同子 Agent 分别处理。每个 Subagent 可以拥有独立的系统 Prompt、工具权限、模型、Skills 和上下文。

flowchart TB
    Main[主 Agent:拆解任务与整合结果]

    Main --> Review[Review Subagent<br/>代码审查]
    Main --> Test[Test Subagent<br/>运行测试]
    Main --> Docs[Docs Subagent<br/>更新文档]
    Main --> Data[Data Subagent<br/>查询项目数据]

    Review --> ReviewCtx[(独立上下文)]
    Test --> TestCtx[(独立上下文)]
    Docs --> DocsCtx[(独立上下文)]
    Data --> DataCtx[(独立上下文)]

    Review --> R1[返回审查摘要]
    Test --> R2[返回测试结果]
    Docs --> R3[返回文档变更]
    Data --> R4[返回数据摘要]

    R1 --> Main
    R2 --> Main
    R3 --> Main
    R4 --> Main

    Main --> Final[最终报告]

Subagents 带来的主要收益有三点。

能力解释
上下文隔离子 Agent 可以处理大量中间信息,只把精简结果返回给主 Agent
专业化配置不同子 Agent 使用不同 Prompt、工具、模型和 Skills
权限收敛安全审计 Agent 可以只读,测试 Agent 可以运行命令,文档 Agent 才能写文件

权限收敛很关键。不是所有 Agent 都应该拥有写文件、执行命令、调用生产接口的权限。把权限绑定到具体 Subagent,可以降低误操作风险。

一个 Subagent 配置可以抽象成这样:

subagents_config = {
    "security-auditor": {
        "description": "Review code for security vulnerabilities.",
        "prompt": """
You are a security auditor.
Focus on SQL injection, XSS, authentication bypass, and insecure secrets.
Do not modify files. Return findings with file path, risk level, and suggested fix.
""",
        "tools": ["read_file", "grep"],
        "skills": ["secure-code-review"],
        "model": "claude-sonnet"
    },

    "test-runner": {
        "description": "Run test suites and summarize failures.",
        "prompt": """
You are a QA engineer.
Run tests, analyze failure logs, and report pass/fail status.
Do not change source code unless explicitly asked.
""",
        "tools": ["bash", "read_file"],
        "skills": ["test-log-analysis"],
        "model": "claude-haiku"
    },

    "docs-writer": {
        "description": "Update technical documentation.",
        "prompt": """
You are a technical writer.
Convert implementation details into clear Markdown documentation.
Preserve existing document style.
""",
        "tools": ["read_file", "write_file"],
        "skills": ["markdown-reporting"],
        "model": "claude-sonnet"
    }
}

这里的配置体现了 Subagents 的核心思想:每个子 Agent 只做自己该做的事,只拿自己需要的工具。


MCP + PTC、Skills、Subagents 的分层定位

这几个机制可以放进同一张表里比较。

机制所在层次解决的问题典型使用场景不适合的情况
MCP连接层标准化连接外部系统访问数据库、文件系统、业务 API、第三方服务不负责定义复杂任务流程
PTC连接层 / 执行层用程序批量编排工具调用批量查询、数据聚合、格式转换、多工具流水线需要模型持续语义判断的任务
Skills认知层给模型按需加载任务知识PDF 处理、报告模板、代码规范、领域流程一次性临时任务,或不可复用的零散知识
Subagents组织层拆分复杂任务并隔离上下文代码审查、测试、文档、数据分析、多角色协作很小的单步任务,拆分反而增加成本

决策时可以按这样的顺序思考:

flowchart TD
    A[要设计一个 Agent 能力] --> B{是否需要访问外部系统}
    B -- 是 --> C[用 MCP 封装外部能力]
    B -- 否 --> D{是否有可复用任务流程}

    C --> E{是否存在多次确定性工具调用}
    E -- 是 --> F[用 PTC 编排批量调用]
    E -- 否 --> D

    F --> D
    D -- 是 --> G[封装为 Skill]
    D -- 否 --> H{任务是否复杂到需要角色分工}

    G --> H
    H -- 是 --> I[拆成 Subagents]
    H -- 否 --> J[单 Agent 即可]

一个完整协同场景:项目审查与报告生成

假设用户给出任务:

分析这个代码仓库,完成安全审查、运行测试、整理提交历史,并生成一份项目质量报告。

这个任务不适合交给单一 Agent 从头做到尾。更合理的设计是让主 Agent 负责拆解和汇总,子 Agent 分别处理专业任务。

flowchart TB
    U[用户:生成项目质量报告] --> M[主 Agent]

    M --> S1[Security Subagent<br/>安全审查]
    M --> S2[Test Subagent<br/>测试执行]
    M --> S3[Git Subagent<br/>提交历史分析]
    M --> S4[Report Subagent<br/>报告生成]

    S1 --> K1[Skill:安全审查规范]
    S2 --> K2[Skill:测试日志分析]
    S4 --> K4[Skill:Markdown 报告模板]

    S1 --> T1[MCP:读取代码文件]
    S2 --> T2[MCP:执行测试命令]
    S3 --> T3[MCP:访问 Git 历史]

    S3 --> PTC[PTC:批量统计提交、作者、文件变更]
    PTC --> S3

    S1 --> R1[安全问题摘要]
    S2 --> R2[测试结果摘要]
    S3 --> R3[提交历史摘要]

    R1 --> M
    R2 --> M
    R3 --> M

    M --> S4
    S4 --> Final[项目质量报告]

在这个设计里:

  • MCP 负责让 Agent 访问代码仓库、执行测试命令、读取 Git 历史;
  • PTC 负责把提交记录统计、文件变更聚合这类确定性数据处理一次性跑完;
  • Skills 负责告诉安全审查、日志分析、报告生成各自应该遵循什么流程;
  • Subagents 负责把安全、测试、数据分析、报告写作隔离在不同上下文里。

主 Agent 不需要读取所有测试日志,也不需要保存完整提交历史。它只接收每个 Subagent 返回的结构化摘要,再完成最终整合。


落地时需要注意的几个坑

1. MCP 工具不要暴露得过宽

MCP Server 能连接外部系统,也意味着它可能带来操作风险。尤其是写文件、执行命令、访问生产数据库这类能力,应该做权限边界。

常见做法包括:

  • 只给只读 Agent 暴露只读工具;
  • 对危险操作增加确认流程;
  • 限制工具可访问的目录、表、接口范围;
  • 记录工具调用日志,便于审计;
  • 对返回结果做大小限制,避免上下文被大结果撑爆。

2. PTC 必须运行在受控沙箱里

PTC 的本质是让模型生成并执行代码,所以运行环境不能完全信任模型输出。沙箱至少要限制:

  • 文件系统访问范围;
  • 网络访问范围;
  • 命令执行权限;
  • CPU、内存、运行时间;
  • 可用依赖包;
  • 工具调用权限。

PTC 适合提升确定性流程的执行效率,但不能因为它方便,就让模型生成的代码直接运行在高权限环境里。

3. Skill 描述要具体,否则模型难以匹配

Skill 的 description 是模型发现技能的入口。如果描述太模糊,模型可能不用它;如果描述太宽泛,模型又可能误用它。

不好的描述:

description: Help with documents.

更好的描述:

description: Extract text, tables, metadata, and page-level content from PDF files. Use when the user asks to convert, parse, summarize, or analyze uploaded PDF documents.

描述应该包含三类信息:

  • 这个 Skill 能处理什么任务;
  • 用户可能会怎样表达需求;
  • 哪些场景应该使用它。

4. Subagents 需要明确返回格式

Subagent 如果只返回一大段自由文本,主 Agent 仍然要花很多成本理解和整理。更稳定的方式是规定返回结构。

例如安全审查 Subagent 可以返回:

{
  "summary": "Found 3 medium-risk issues and 1 high-risk issue.",
  "findings": [
    {
      "file": "src/auth/login.ts",
      "line": 42,
      "risk": "high",
      "type": "authentication bypass",
      "evidence": "The token expiration check is skipped when rememberMe is true.",
      "suggested_fix": "Always validate token expiration before granting access."
    }
  ],
  "requires_action": true
}

结构化结果能减少主 Agent 的整理成本,也便于系统后续做自动化处理。

5. 不要把所有任务都拆成 Subagents

Subagents 会带来额外调度成本。任务很小、上下文很短、角色单一时,单 Agent 更简单。

适合拆分的信号包括:

  • 一个任务里出现多个明显角色;
  • 工具权限差异很大;
  • 中间结果很长,容易污染主上下文;
  • 子任务可以并行处理;
  • 子任务需要不同模型或不同 Skills。

如果只是“把这段文字改成 Markdown 表格”,没有必要创建一个专门的 Subagent。


核心理解

MCP、PTC、Skills、Subagents 可以用一句话区分:

  • MCP 让 Agent 能连接外部系统;
  • PTC 让 Agent 用程序高效编排多次工具调用;
  • Skills 让 Agent 按需获得专业任务知识;
  • Subagents 让 Agent 系统具备分工协作能力。

它们组合起来后,Agent 不再只是一个带工具的大语言模型,而更像一个分层的软件系统:底层有标准化连接,中间有可复用技能,上层有任务组织和角色分工。设计 Agent 应用时,把这三层边界划清楚,系统会更容易维护,也更容易扩展到复杂业务场景。


评论