01 概念全景图
从调用一个简单的API,到一个能够自主思考、使用工具完成复杂任务的智能体,其核心概念演进过程可以概括为以下全景图:
LLM(大语言模型)
│
│ 厂商通过 HTTP 提供调用能力
▼
LLM API
│
│ 客户端维护对话历史数组
▼
Context(上下文)
│
│ 告诉 LLM “你有哪些工具可用”
▼
Tool Calling(工具调用)
│
│ 加入循环:思考 → 行动 → 观察
▼
Agent Loop(智能体循环)
│
├──────────────┬──────────────┐
▼ ▼ ▼
MCP 协议 Sub-Agent Agent Skill
(标准化工具对接) (分工协作) (流程复用)
02 基础概念
在动手构建之前,我们需要清晰地理解构成一个现代AI Agent的几个核心基石。
2.1 LLM(大语言模型)
ChatGPT、Claude、Gemini、DeepSeek 等都是 LLM。其本质是超大号的“文字接龙”机器——给定一段文字,它会根据概率预测并生成下一个词。当模型的参数量达到千亿级别时,它就涌现出了写代码、写文章、做数学题等令人惊讶的能力。
2.2 LLM API(大模型接口)
LLM 运行在云端庞大的GPU集群上,厂商通过标准的 HTTP API 向我们提供调用能力,其过程可以简化为:
你的代码 → HTTP POST(带上问题) → LLM 服务 → HTTP 响应(返回回答)
2.3 Context(上下文)
LLM 本身是无状态的——每次API调用都是一次全新的、独立的请求,它不会记得上一句你说了什么。所谓的“上下文”,就是你随请求一起发过去的所有信息,主要包括:
- 对话历史:之前的每一轮问答
- 系统提示词:告诉 AI “你是谁、该怎么做”的指令
- 工具结果:上一步工具调用返回的数据
这个过程如下所示:
第 1 次请求:[消息1] → AI 回复1
第 2 次请求:[消息1, 回复1, 消息2] → AI 回复2
第 3 次请求:[消息1, 回复1, 消息2, 回复2, 消息3] → AI 回复3
每次都把完整历史发过去,AI 才能“记住”之前聊了什么。“记忆”不在 AI 脑子里,而在你发送的数组里。
每个模型都有上下文窗口限制,比如 128K tokens。超出这个长度,最早的内容就会被截掉。
这是从“聊天机器人”进化到“Agent”的关键一步。普通 LLM 只能生成文字,但如果你告诉它有一个 get_weather 工具,它就能返回结构化的调用请求:
{ "functionCall": { "name": "get_weather", "args": { "city": "深圳" } } }
需要明确的是,LLM 并没有真的去查天气,它只是说“我想调这个工具”。真正执行查询并返回天气数据的是你的后端代码。LLM 负责“动脑”决策,你的代码负责“动手”执行。
2.5 AI Agent(智能体)
Agent 是一种架构模式,它把上面三者有机地串联在一起:
Agent = LLM(大脑) + Tools(手脚) + Loop(驱动循环)
- LLM 负责理解任务、做出决策
- Tools 负责执行具体操作
- Loop 让 AI 反复执行“思考→行动→观察”的循环,直到任务完成
2.6 MCP(模型上下文协议)
有了 Tool Calling,Agent 可以调用工具。但每接入一个新工具,你都需要写一套定义、解析、执行的胶水代码。工具一多,维护成本呈指数级增长。
MCP(Model Context Protocol)就是为了解决这个问题而生的标准化协议,它让 Agent 能够以即插即用的方式对接外部工具和数据源——相当于 AI 世界的 USB 接口标准。
2.7 Sub-Agent(子智能体)
如果一个 Agent 什么任务都做,不仅容易出错,其上下文也会很快被各种无关的中间信息塞满。Sub-Agent 模式的核心思想是让一个主 Agent(调度者)把复杂的子任务委派给专门的小 Agent 去执行。每个子 Agent 拥有自己独立的上下文和专属的工具集,任务完成后只把精炼的结果交还给主 Agent。
2.8 Agent Skill(技能)
Tool 是单个原子动作(比如“读文件”),但很多实际任务是一套固定流程(比如“生成 Git commit”需要:查状态 → 看 diff → 写 commit message → 执行提交)。
Agent Skill 就是预定义好的 prompt + 工具组合——它将多个工具和特定的指令提示打包成一个可以一键触发的标准化流程。
2.9 Context Management(上下文管理)
LLM 的上下文窗口是有限的黄金资源。对话越长,历史消息越多,总会塞满。而且 token 数量直接决定了 API费用和响应速度。
上下文管理就是在“记住足够多的信息”和“别超出限额”之间找到最佳平衡。常见的策略包括滑动窗口、摘要压缩以及 RAG(检索增强生成) 等。
03 从零构建 Agent — 四个阶段
整个构建过程可以分为四个清晰且递进的阶段,每完成一个阶段,你的 Agent 就解锁一项核心能力。
3.1 阶段一:单次对话(API 调用)
这是最简单的起点——直接调用 LLM API,实现与 AI 的一问一答。
const body = {
messages: [
{ role: "system", content: "你是一个有帮助的助手。" },
{ role: "user", content: "你好" },
],
};
const res = await fetch(apiEndpoint, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${apiKey}`,
},
body: JSON.stringify(body),
});
const data = await res.json();
console.log(data.choices[0].message.content);
关键参数解析:
- 系统提示词(system prompt):告诉 AI “你是谁、该怎么做”的隐藏指令,用户看不到,但 AI 会始终遵守。
- 对话内容(messages):用户实际发送的消息,每条消息需要包含
role(说话者身份)和 content(说话内容)。
此阶段能力:单轮问答。程序关闭,对话即忘。
3.2 阶段二:多轮对话(上下文维护)
LLM 本身不记得历史,因此需要在客户端主动维护一个 history 数组,并在每次请求时带上完整的历史记录:
class Chat {
private history: Message[] = [];
async send(text: string): Promise<string> {
this.history.push({ role: "user", content: text });
const reply = await this.client.sendMessage(this.history, this.systemPrompt);
this.history.push({ role: "assistant", content: reply });
return reply;
}
}
核心理解:LLM 本身是无状态的,“记忆”完全靠客户端的数组来模拟和维持。
此阶段能力:支持多轮连贯对话,但 Agent 仍然只会“说”,不会“做”。
3.3 阶段三:工具调用(Function Calling)
现在 AI 能记住对话了,我们给它装上“手”——即 Tool Calling 能力。
首先,需要一个工具注册表,用标准格式描述每个工具:
{
name: "run_shell_command",
description: "Run a shell command on the user‘s machine...",
parameters: {
command: { type: "string", description: "The shell command to execute" },
},
required: ["command"],
}
然后,实现工具的执行逻辑:
execute(params: Record<string, unknown>): Promise<unknown> {
const command = params.command as string;
return new Promise((resolve) => {
exec(command, { timeout: timeoutMs }, (error, stdout, stderr) => {
resolve({ exitCode: error?.code ?? 0, stdout, stderr });
});
});
}
当你把工具列表随请求发给 API 后,AI 的回复就可能从纯文本转变为函数调用请求:
// 纯文本回复
{ "text": "你好!有什么可以帮你的?" }
// 工具调用请求
{ "functionCall": { "name": "run_shell_command", "args": { "command": "ls -la" } } }
记住,AI 只是下达了指令,真正在后台执行 ls -la 命令的是你的代码。
3.4 阶段四:Agent Loop(ReAct 循环)
有了工具调用,AI 能完成“单步动作”。但现实任务通常需要多步协作。这时需要引入 Agent Loop,即一个自动化的驱动循环——AI调用工具后,代码将执行结果反馈给它,AI基于结果思考下一步,如此循环直至任务完成。
这个过程就是著名的 ReAct (Reason + Act) 范式:
- Reasoning(推理):AI 思考当前状况,决定下一步该做什么。
- Acting(行动):AI 发出工具调用请求,代码执行该工具。
- Observation(观察):代码将工具执行的结果反馈给 AI。
其核心循环代码如下:
async send(text: string): Promise<string> {
this.history.push({ role: "user", content: text });
for (let i = 0; i < MAX_ROUNDS; i++) {
const result = await this.client.sendMessage(this.history, options);
this.history.push({ role: "assistant", content: result });
if (!result.functionCall) {
return result.text ?? "";
}
const { name, args } = result.functionCall;
const toolResult = await this.toolRegistry.execute(name, args);
this.history.push({
role: "tool",
content: JSON.stringify({ name, result: toolResult }),
});
}
throw new Error("Max tool call rounds exceeded");
}
实际运行示例:
用户:“帮我看看当前目录有什么文件,然后统计代码行数”
第 1 轮:AI → 执行 `ls -la` → 代码返回结果
第 2 轮:AI → 执行 `wc -l src/*.ts` → 代码返回结果
第 3 轮:AI → 返回文本总结 → 循环结束 ✅
安全机制:MAX_ROUNDS 是一个必要的安全阀,防止 AI 陷入死循环。
3.5 工程化原则
拥有了 Agent Loop,一个能自主运行的 Agent 骨架就完成了。但要使其真正健壮、可用,还需遵循以下工程化原则:
-
工具设计:从“万能胶”到“手术刀”
不要只提供一个 run_shell_command 这样的万能工具。应该设计专一、原子化的工具:
read_file:支持分页读取,避免大文件直接撑爆上下文。
edit_file:通过提供 old_string → new_string 的方式修改代码,比让 AI 直接生成 Shell 编辑命令更安全可靠。
list_directory:返回结构化的 JSON 列表,包含文件大小和类型。
工具越“原子化”、返回结果越“结构化”,Agent 运行的成功率和效率就越高。
-
上下文注入:给 Agent 戴上“扩增实境眼镜”
在每轮对话开始前,自动采集并注入环境信息到 Prompt 中,例如当前工作目录、文件列表、时间戳等。这样 Agent 一开始就知道自己“在哪里”、“手头有什么”,无需额外花费轮次去探索环境。
-
显示优化:让“黑盒”变透明
Agent 执行工具时,应给予用户清晰、友好的反馈,而不是直接输出原始 JSON。
interface ToolExecuteResult {
data: unknown; // LLM 需要的结构化原始数据
displayText?: string; // 用户在终端看到的友好提示
}
例如,执行命令时显示 $ ls -la,读文件时显示 Read src/index.ts (lines 1-20)。
-
指令优化:从“聊天”到“工作”
系统提示词极大地影响 Agent 行为。针对开发工具场景,提示词应:
- 强制要求:禁止客套废话,直接输出结果。
- 角色定位:明确自己是一个专注于效率的交互式 CLI Agent。
- 鼓励思考链:在调用工具前进行简短的推理,提升决策准确性。
04 进阶架构
当基础 Agent 跑通后,要应对更复杂的生产场景,就需要引入更高级的架构模式。
4.1 上下文管理
上下文窗口是 Agent 的“工作记忆”,但容量有限且昂贵。管理不善会导致信息丢失、成本飙升和响应变慢。
为什么需要上下文管理
| 问题 |
说明 |
| Token 限制 |
每个模型有上下文窗口上限(如 128K),超出部分会被截断。 |
| 成本 |
Token 数量直接决定 API 调用费用,历史越长越贵。 |
| 速度 |
输入 token 越多,模型推理的延迟通常越高。 |
常见策略
策略1:滑动窗口
只保留最近 N 轮对话,丢弃更早的消息。
function slidingWindow(history: Message[], maxTurns: number): Message[] {
if (history.length <= maxTurns * 2) {
return history;
}
const systemPrompt = history[0];
const recentMessages = history.slice(-(maxTurns * 2));
return [systemPrompt, ...recentMessages];
}
优点:实现简单,效果直接。
缺点:早期重要信息会完全丢失。
策略2:摘要压缩
让 LLM 将旧的、冗长的对话历史压缩成一段简短的摘要。
原始历史(5000 tokens):
用户问了天气 → AI 查了天气 → 用户问了新闻 → AI 查了新闻 → ...
压缩后(200 tokens):
“用户先查了深圳天气(25°C 晴),然后查了今日科技新闻(共 3 条),接着要求将新闻翻译成英文。”
优点:能保留关键信息,压缩率高。
缺点:压缩过程本身消耗 token,且可能丢失细节。
策略3:RAG(检索增强生成)
不把所有信息都塞进上下文,而是存入外部向量数据库。当需要“回忆”时,按需检索相关的历史片段并注入当前上下文。
用户提问:“上次讨论的数据库方案是什么?”
1. 把问题转成向量 → 去向量数据库检索
2. 找到相关的历史片段 → 注入当前上下文
3. LLM 基于检索结果回答
优点:上下文保持精简,理论上可“记住”无限量的历史。
缺点:需要搭建和维护额外的向量数据库基础设施。
策略组合
实际项目中通常组合使用多种策略,形成分层记忆体系:
┌─────────────────────────────────────────────┐
│ 1. 系统提示词 (始终保留) │
│ 2. 压缩摘要(旧历史) (摘要压缩) │
│ 3. 检索到的相关知识片段 (RAG) │
│ 4. 最近 N 轮对话 (滑动窗口) │
│ 5. 当前用户输入 (始终保留) │
└─────────────────────────────────────────────┘
上下文管理没有银弹,需要根据具体场景灵活组合策略。
4.2 MCP 协议
当工具数量增多,为每个 Agent 重复编写“定义→解析→执行”的胶水代码会让维护成本爆炸。MCP(Model Context Protocol) 正是为解决此问题而生的标准化协议。
MCP 解决的问题
没有 MCP 时:
Agent A 对接 GitHub → 写一套 GitHub 工具定义 + 执行逻辑
Agent A 对接 Slack → 写一套 Slack 工具定义 + 执行逻辑
Agent B 对接 GitHub → 再写一套(跟 A 的还不一样)
...
M 个 Agent × N 个工具 = M × N 套集成代码。
有了 MCP:
Agent A ─┐ ┌─ GitHub MCP Server
Agent B ─┤── MCP 协议 ──────┤─ Slack MCP Server
Agent C ─┘ (标准接口) └─ 数据库 MCP Server
只需 M + N 套代码(每个Agent一个客户端,每个工具服务一个服务端)。
MCP 的核心能力
MCP 定义了三种核心资源,通过标准协议暴露给 Agent:
- Tools (工具):Agent 可以调用的可执行函数,让模型执行操作。
- Resources (资源):Server 暴露的只读数据源,让模型读取上下文信息。
- Prompts (提示词):Server 提供的预定义 Prompt 模板,用于复用高质量的指令。
MCP 通信架构
┌─────────────────────────────────────────────────┐
│ Host │
│ (Agent 应用) │
│ │
│ ┌────────────┐ ┌────────────┐ │
│ │ MCP Client │ │ MCP Client │ ... │
│ └─────┬──────┘ └─────┬──────┘ │
└─────────┼───────────────┼───────────────────────┘
│ MCP 协议 │ MCP 协议
▼ ▼
┌────────────┐ ┌────────────┐
│ MCP Server │ │ MCP Server │
│ (GitHub) │ │ (Database) │
└────────────┘ └────────────┘
4.3 Sub-Agent 模式
单一 Agent 在处理复杂任务时面临上下文污染(中间结果占满空间)和任务过杂(思维在不同工作间频繁切换)的瓶颈。Sub-Agent 模式通过分工协作来解决这些问题。
Sub-Agent 架构
用户:“帮我调研 React 和 Vue 的优缺点,然后写一个技术选型报告”
┌──────────────┐
│ 主 Agent │ ← 理解任务、拆分、汇总
│(Orchestrator)│
└───────┬──────┘
┌─────────┼─────────┐
▼ ▼ ▼
┌───────────┐ ┌──────────┐ ┌──────────┐
│调研 Agent │ │调研 Agent│ │写作 Agent│
│ (React) │ │ (Vue) │ │ (报告) │
└───────────┘ └──────────┘ └──────────┘
每个子 Agent:
- 拥有独立的上下文——任务间互不干扰。
- 配备专属的工具集——各司其职。
- 完成后只返回精炼结果——避免中间过程污染主对话。
Sub-Agent 定义示例
name: code-reviewer # 唯一标识
description: "Reviews code..." # 描述,用于主Agent决策时选择
tools: [read_file, list_dir] # 工具白名单
model: "model-name" # 可覆盖默认模型
maxTurns: 15 # 限制最大工具调用轮数
prompt: | # 专属系统提示词
You are a code reviewer specialized in identifying:
- Security vulnerabilities
- Performance issues
...
关键设计:通过工具白名单限制权限、可配置独立模型、设置轮数限制防止子任务失控。
4.4 Agent Skill
Tool 是原子动作,但很多实际任务是一套固定流程。Skill 就是将这类流程(特定 Prompt + 多个 Tool 的组合)打包成一个可复用的快捷操作。
Skill 的本质
一个 Skill = Prompt 模板 + 元数据。它本身不执行代码,而是通过注入精心设计的 Prompt 来指导主 Agent 按既定流程调用已有的 Tools。
Skill 定义示例
name: commit
description: "Generate a conventional commit message for staged changes"
trigger: /commit
prompt: |
Analyze the staged changes and generate a commit message
following the Conventional Commits specification.
The commit message should:
1. Start with a type: feat, fix, docs, style, refactor, test, or chore
2. Include a scope in parentheses if applicable
3. Have a concise subject line (max 50 chars)
4. Include a body if the change is complex
Skill 的触发方式
- 用户命令触发:用户输入
/commit,系统匹配并注入对应 Skill 的 Prompt。
- LLM 自主调用:将 Skill 包装成一个特殊的 Tool,LLM 在 Agent Loop 中可以像调用普通 Tool 一样决定启用某个 Skill。
Skill 的核心价值
- 提升效率:将重复性流程固化为一键操作。
- 封装专家经验:无需用户知晓具体步骤和参数。
- 保证一致性:在团队中统一复杂操作的标准。
理解三者的区别是设计高效 Agent架构 的关键。以下决策流和场景对照可供参考:
决策流程图:
新需求
│
├─ 是单个原子操作?(读文件、发请求)
│ └─ → 用 Tool
│
├─ 是固定流程?(步骤固定,仅输入不同)
│ └─ → 用 Skill
│
├─ 需要独立上下文?(中间过程会污染主对话)
│ └─ → 用 Sub-Agent
│
└─ 需要不同专业模型?
└─ → 用 Sub-Agent
| 具体场景对照表: |
场景 |
推荐方案 |
理由 |
| 读取一个文件 |
Tool |
单个原子操作。 |
| 生成 Git commit message |
Skill |
固定流程(查 diff → 写 message)。 |
| 调研某个技术方案 |
Sub-Agent |
需要大量搜索,中间结果会污染主上下文。 |
| 执行代码审查 |
Sub-Agent |
需要独立、专注的上下文,可能需专用模型。 |
| 格式化代码 |
Tool |
单个操作,调用格式化工具即可。 |
| 生成单元测试 |
Skill |
固定流程(读源码 → 分析 → 生成测试)。 |
| 同时调研3个竞品 |
Sub-Agent × 3 |
并行执行,各自需要独立上下文。 |
组合使用
在实际复杂的项目中,三者经常被组合使用,以发挥最大效能:
用户输入 /review(触发 Skill)
│
▼
Skill prompt 指导主 Agent 拆分任务
│
├─ Sub-Agent 1:代码审查(使用 read_file Tool)
├─ Sub-Agent 2:安全检查(使用 grep Tool)
└─ Sub-Agent 3:性能分析(使用 run_command Tool)
│
▼
主 Agent 汇总结果,生成报告
05 总结
本文系统地梳理了从 LLM 到功能完备的 AI Agent 的完整知识体系与构建路径:
基础概念:
- LLM 是无状态的预测模型,通过 API 调用。
- Context 是你发送的全部信息(历史+提示词+工具结果),“记忆”由客户端数组维护。
- Tool Calling 让 LLM 从“聊天”进化到“操作”,LLM决策,代码执行。
构建四阶段:
- 单次对话 → 调用API,一问一答。
- 多轮对话 → 客户端维护历史数组。
- 工具调用 → 注册工具,LLM决策调用。
- Agent Loop → 实现ReAct循环,自动化多步执行。
进阶架构:
- 上下文管理:滑动窗口、摘要压缩、RAG检索增强,需按场景组合。
- MCP 协议:标准化工具对接,将 M×N 的集成复杂度降为 M+N。
- Sub-Agent:通过独立上下文实现分工协作,解决污染和专注度问题。
- Agent Skill:将固定流程打包成可复用的Prompt模板。
- 选择原则:原子操作用 Tool,固定流程用 Skill,需独立上下文或专用模型时用 Sub-Agent。
掌握这些核心概念与模式,你便具备了从零开始设计并实现一个适应复杂场景的、健壮的 AI Agent 系统的能力。在实践中,通常需要根据具体任务需求,灵活选用和组合这些架构模式。如果你想深入探讨某个具体实现或遇到问题,欢迎在 云栈社区 的技术论坛与更多开发者交流。