Agent 是什么:定义、组成与最小项目骨架
从定义出发理解 Agent 与 ChatBot 的本质区别,拆解 Agent 的六大组成模块,并搭好 Python + uv 的最小项目骨架。
这篇笔记解决什么问题
"Agent" 这个词现在到处都是,但很多人对它的理解停留在"更聪明的聊天机器人"。这篇笔记要把三件事讲清楚:第一,Agent 的严格定义是什么,它和你每天用的 ChatBot 到底差在哪;第二,一个 Agent 拆开来由哪几块组成,每一块承担什么职责;第三,如果你想自己动手写一个 Agent,第一步的项目骨架应该怎么搭——包括 Python 环境、包管理器、API key 和目录结构。
读完这篇你不会立刻拥有一个能干活的 Agent,但你会知道接下来要造的东西长什么样、由哪些零件构成,并且本地环境已经准备就绪,随时可以开始写第一行代码。
核心概念:Agent 的四个要素
先给出一个可操作的定义:
Agent 是一个以目标为导向的任务执行系统——它能感知外部环境,自主做出决策,并通过调用工具来实际改变世界,直到目标达成。
这个定义里有四个关键词,缺一个都不算真正的 Agent:
自主(Autonomy)。你只需要交代"要什么",不需要交代"每一步怎么做"。Agent 拿到目标后,自己决定先干什么、后干什么、遇到岔路走哪条。如果每一步都要人类点头,那只是一个带确认框的脚本。
感知(Perception)。Agent 必须能观察环境的当前状态:读文件、查数据库、看命令的返回值、接收 API 响应。没有感知能力的系统只能按预设剧本执行,无法应对"世界和预期不一样"的情况——而真实任务里,世界几乎总是和预期不一样。
工具(Tools)。语言模型本身只会输出文字,是工具让它的决策落地为动作。工具集合直接决定了 Agent 的能力边界:给它文件读写工具,它就能整理文档;给它 shell 执行权限,它就能部署服务。可以说,Agent 的能力清单就是它的工具清单。
目标(Goal)。Agent 的一切行为都要收敛到一个明确的任务目标上。它不是陪聊的,每一轮思考、每一次工具调用都应该在回答同一个问题:"我离完成任务还差什么?"
Agent 与 ChatBot:数字员工 vs 百科全书
用一个具体场景来对比。假设你的需求是:
把这个月服务器日志里的报错按类型归类,统计每类出现的次数,写一份故障分析文档存到项目目录里。
把这句话丢给一个普通的 ChatBot(不管背后的模型多强),你会得到一段很有条理的文字:教你用什么命令提取报错、建议按什么维度归类、给你一份文档模板。它什么都懂,但什么都没做——日志还在服务器上原封不动,文档一个字都没生成。ChatBot 的本质是一本会对话的百科全书:知识渊博,有问必答,但它的输出永远停留在"说"。
同样的需求交给 Agent,过程完全不同:它会先调用工具列出日志文件,读取内容,自己写脚本提取和统计报错,把结果整理成 Markdown,最后把文件写进你指定的目录。中间如果发现歧义——比如日志目录里有三个月的文件,它可能会停下来问你一句"只处理 6 月的对吗"——确认后继续干。任务结束时,你得到的不是一段建议,而是一份真实存在的文档。
这就是两者的本质区别:ChatBot 是被动应答的知识库,一问一答就结束;Agent 是主动执行的数字员工,接下任务就要负责交付结果。 中间的鸿沟不是模型能力,而是"能不能作用于环境"——也就是上面说的感知与工具。
关键机制:Agent 的六大组成模块
把一个能干活的 Agent 拆解开,会看到六个协作的模块:
| 模块 | 职责 | 类比 |
|---|---|---|
| 大模型 | 理解输入、推理决策、生成输出,是整个系统的"发动机" | 大脑 |
| 角色设定 | 通过系统提示词约束 Agent 的身份、风格和行为边界 | 岗位职责说明书 |
| 记忆 | 短期记忆跟踪当前任务的上下文,长期记忆沉淀跨会话的经验和偏好 | 工作笔记 + 个人经验 |
| 工具 | 一组可被模型调用的函数或外部接口,是行动能力的来源 | 双手和设备 |
| 规划 | 把复杂目标拆成有序的子步骤,处理多步推理和依赖关系 | 项目排期 |
| 循环 | 驱动"思考 → 行动 → 观察结果 → 再思考"不断迭代,直到任务完成或达到上限 | 工作节奏 |
这六个模块里,最容易被低估的是循环。很多人以为 Agent 的核心是模型或工具,但真正让 Agent "活起来"的是那个不断运转的执行环:模型每轮决定"接下来做什么",系统执行动作后把结果喂回给模型,模型再基于新信息做下一轮决策。没有这个环,工具调用只是一次性的函数执行;有了这个环,系统才具备"根据反馈调整行为"的能力——这正是"自主"的技术实现。
另一个容易混淆的点是记忆和上下文的关系。短期记忆基本等于当前对话的消息列表(上下文窗口内的内容),长期记忆则需要额外的存储机制(文件、向量库等)在会话之间传递信息。本系列后续会专门拆解记忆、规划、多 Agent 协作这些模块,这一篇先建立整体地图。
代码模式:从一次模型调用到一个执行环
虽然正式写代码是下一步的事,但先看两段骨架代码,能帮你把上面的概念落到实处。
第一段:最基础的 LLM 调用。国内外主流模型服务(DeepSeek、Kimi、GLM、Qwen 等)几乎都提供 OpenAI 兼容接口,所以只用 openai 这一个 SDK,换 base_url 和模型名就能切换厂商:
import os
from openai import OpenAI
# base_url 指向任意 OpenAI 兼容服务,不绑定单一厂商
client = OpenAI(
api_key=os.environ["LLM_API_KEY"],
base_url=os.environ["LLM_BASE_URL"], # 例如 https://api.deepseek.com/v1
)
resp = client.chat.completions.create(
model=os.environ["LLM_MODEL"],
messages=[
{"role": "system", "content": "你是一个严谨的运维助手。"},
{"role": "user", "content": "解释一下什么是幂等操作"},
],
)
print(resp.choices[0].message.content)这段代码只是一个 ChatBot:一问一答,没有行动能力。
第二段:给它套上执行环,就有了 Agent 的雏形。下面是伪代码级别的骨架,重点看结构而不是细节:
MAX_STEPS = 20 # 防止死循环的保险丝
def run_agent(goal: str) -> str:
history = [
{"role": "system", "content": AGENT_PERSONA}, # 角色设定
{"role": "user", "content": goal}, # 目标
]
for _ in range(MAX_STEPS): # 循环
reply = call_llm(history, tools=TOOL_SCHEMAS) # 大模型 + 工具声明
if not reply.tool_calls:
return reply.content # 没有动作请求 = 任务收尾
history.append(reply) # 短期记忆
for tc in reply.tool_calls:
outcome = execute_tool(tc.name, tc.arguments) # 行动
history.append({ # 感知:结果回灌
"role": "tool",
"tool_call_id": tc.id,
"content": outcome,
})
return "已达最大步数,任务中止"注意每一行注释和六大模块的对应关系:AGENT_PERSONA 是角色,history 是短期记忆,TOOL_SCHEMAS 声明工具,for 循环就是执行环,而"把工具结果追加回消息列表"这一步实现了感知。规划能力在这个最小版本里由模型隐式完成(它自己决定调用顺序),更复杂的显式规划后面再加。
实践:搭建最小项目骨架
概念清楚了,把开发环境立起来。
1. Python 与 uv
需要 Python 3.12 及以上。包管理推荐 uv——它同时管依赖和虚拟环境,速度比 pip 快一个量级。安装(macOS / Linux):
curl -LsSf https://astral.sh/uv/install.sh | sh
uv --version # 输出版本号即安装成功Windows 用户在 PowerShell 里执行官网给出的安装命令即可,验证方式相同。
2. 准备一个 API key
到任意一家提供 OpenAI 兼容接口的模型服务商注册并创建 API key。DeepSeek、Kimi(月之暗面)、GLM(智谱)都是低成本的选择,新账号通常有免费额度,学习阶段的调用开销可以忽略不计。key 创建后立即复制保存——多数平台只展示一次。
3. 目录骨架
建一个项目目录,里面只需要两个子目录:
mkdir agent-lab && cd agent-lab
mkdir backend # 所有 Python 源码
mkdir workspace # Agent 运行时的工作区:配置、会话记录、产出文件把"代码"和"运行产物"从第一天就分开,是个值得坚持的习惯:backend 进版本控制,workspace 是 Agent 读写的沙盒,两者互不污染。
4. 环境变量与 .env
在项目根目录创建 .env,写入三个变量:
LLM_API_KEY=你的key
LLM_BASE_URL=https://api.deepseek.com/v1
LLM_MODEL=deepseek-chat换厂商时只改后两行,代码一个字不用动——这就是坚持用 OpenAI 兼容接口的好处。
5. .gitignore
如果用 Git 管理项目(建议用),根目录加一个 .gitignore:
.env
.venv/
__pycache__/
workspace/最终结构:
agent-lab/
├── .env # 密钥与模型配置(不入库)
├── .gitignore
├── backend/ # 源码
└── workspace/ # 运行时工作区(不入库)常见坑
- 把 API key 写进代码或提交到 Git。 这是最高频也最危险的错误。key 只放
.env,.gitignore第一行就是它。一旦不小心推到公开仓库,立刻去平台吊销重建,删除提交记录是来不及的。 - 循环不设上限。 Agent 可能因为工具持续报错而反复重试,没有
MAX_STEPS这类保险丝,就是无限烧 token。上限、超时、预算控制从最小版本就要有。 - 把 Agent 理解成"更强的提示词工程"。 提示词只影响六大模块中的"角色",Agent 的核心竞争力在工具、循环和记忆这些工程结构上,光调提示词造不出数字员工。
- 一开始就绑死某个厂商的私有 SDK。 用 OpenAI 兼容接口写代码,模型层随时可换,做实验对比不同模型的表现也只是改两行配置的事。
- 忽视 workspace 的边界。 Agent 有文件写入能力后,一定要限定它只能在工作区内操作,否则一次跑偏的
rm或误写就可能伤到项目源码甚至系统文件。
动手清单
- 安装 Python 3.12+ 和 uv,用
python --version、uv --version确认两者可用。 - 在一家 OpenAI 兼容的模型平台注册并创建 API key,写入项目根目录的
.env。 - 按上文搭好
agent-lab/(含backend/、workspace/、.env、.gitignore),并git init后确认git status里看不到.env。 - 在
backend/里用uv init初始化环境,uv add openai python-dotenv,把本文第一段调用代码跑通,看到模型的回复。 - 口头练习:不看笔记,向别人(或自己)讲清楚 Agent 的四个要素和六大模块,以及"执行环"为什么是 Agent 区别于 ChatBot 的关键。
*本文为学习笔记,知识框架参考自叶小钗「生产级 Agent」系列课程;文字与代码示例为本站原创整理。*