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。它通常包含两类信息:
- 元数据:名称、描述,用来让模型判断什么时候应该使用这个 Skill。
- 完整指南:任务步骤、注意事项、可用脚本、输入输出格式、示例。
一个简化版 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 分成了三层:
| 层级 | 加载内容 | 目的 |
|---|---|---|
| 技能发现 | name、description | 让模型知道有哪些技能可用 |
| 技能理解 | 完整 SKILL.md | 让模型理解任务流程和约束 |
| 资源加载 | 脚本、模板、示例、文档 | 任务执行时按需读取具体材料 |
这样做的好处很直接:系统可以拥有很多 Skills,但每次任务只加载少量相关内容。上下文里保留的是当前任务需要的信息,而不是所有可能用到的知识。
Skills 与工具的区别
Skills 很容易和工具混在一起,但两者定位不同。
| 对比项 | Tool / MCP Tool | Skill |
|---|---|---|
| 核心作用 | 执行一个外部动作 | 告诉模型某类任务怎么做 |
| 典型形式 | 函数、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 应用时,把这三层边界划清楚,系统会更容易维护,也更容易扩展到复杂业务场景。