从零搭一个最小 Agent:看清一个 Agent 的全部骨架
- Published on
- ...
- Authors

- Name
- Huashan
- @herohuashan
从零搭一个最小 Agent:看清一个 Agent 的全部骨架
这篇笔记记录我从一个空文件夹开始,手写一个最小 agent 的过程。目标不是一上来使用复杂框架,而是先看清楚 agent 最核心的结构:模型如何看到工具,如何决定调用工具,程序如何执行工具,再把结果交回模型生成最终回答。
最后我也会把这个小 agent 和更复杂的 OpenClaw、Hermes、Claude Code、Codex 做一个对比,帮助理解它们到底复杂在哪里。
1. 从空文件夹开始
练习目录是:
/Users/huashan/Agent-development
一开始我只需要几个文件:
Agent-development/
├── agent.py
├── requirements.txt
├── README.md
├── prompts/
│ └── identity.md
├── memory/
│ └── user_profile.md
└── docs/
└── agent-learning-note.md
requirements.txt 里只放一个依赖:
anthropic
因为这次我选择走 Anthropic-style 的 tool-use 写法,同时用 MiniMax 的 Anthropic-compatible API 来跑模型。

8. .env:把 API Key 放到本地
一开始每次运行都要写:
export MINIMAX_API_KEY="..."
后来我加了一个很小的 .env 读取器。现在可以在项目根目录放:
MINIMAX_API_KEY=your_key_here
.env 已经加入 .gitignore,不会被提交到 Git。agent.py 启动时会读取它,但如果 shell 里已经 export 了同名变量,会优先使用 shell 的值。最简实现:
from pathlib import Path
import os
def load_dotenv(path: str = ".env") -> None:
if not Path(path).exists():
return
for line in Path(path).read_text().splitlines():
line = line.strip()
if not line or line.startswith("#") or "=" not in line:
continue
k, v = line.split("=", 1)
os.environ.setdefault(k.strip(), v.strip()) # setdefault: shell 优先
load_dotenv()
api_key = os.environ["MINIMAX_API_KEY"]

关键就是 setdefault——已存在的环境变量不会被 .env 覆盖,所以 shell 里临时 export 的值永远赢,本地文件只兜底。
9. 小 Agent 和复杂 Agent 的关系
现在这个 agent 可以概括为:
identity + user_profile + tools + loop
这已经是 agent 的最小骨架。OpenClaw、Hermes、Claude Code、Codex 看起来复杂很多,但它们底层依然离不开这个结构。
差别主要是复杂系统在这个骨架上叠了更多层:
更多入口
更多记忆
更多工具
更多身份
更多权限控制
更强运行时工程
更复杂的任务调度
10. OpenClaw 和 Hermes 复杂在哪里
OpenClaw / Hermes 更像长期运行的个人 AI 系统,而不是一次性命令行 agent。
它们复杂在:
- 入口更多:Discord、Telegram、语音、cron、webhook、定时任务。
- 记忆更多:长期记忆、当天记忆、会话历史、向量检索、跨 agent 共享记忆。
- 工具更多:通知、日历、邮件、文件、搜索、MCP、数据库、交易、语音。
- agent 更多:主 agent、生活 agent、英语 agent、交易 agent、研究 agent。
- 运行时更重:常驻服务、日志、监控、重启、权限、密钥、失败告警。
如果说我这个小项目是:
一次性命令行 agent
那 OpenClaw / Hermes 更像:
长期运行的个人 AI 操作系统
但它们仍然离不开同一个循环:
模型看上下文和工具 schema
-> 决定调用工具
-> 程序执行工具
-> 工具结果回给模型
-> 模型继续决策或最终回答
11. Claude Code 和 Codex 算不算 Agent
Claude Code 和 Codex 当然也算 agent,而且是 coding agent。
它们不是生活助理,而是专门住在代码仓库里的软件工程 agent。
普通生活 agent 的 loop 是:
用户问题 -> 判断工具 -> 调工具 -> 回答
coding agent 的 loop 是:
读代码 -> 搜索文件 -> 理解需求 -> 修改代码 -> 跑测试 -> 看报错 -> 再修改 -> 总结结果
本质仍然是:
模型负责决策
工具负责执行
loop 负责闭环
只是工具换成了软件工程工具:
read_file / search_code / apply_patch / run_command / run_tests / git_diff / inspect_logs
Claude Code 和 Codex 复杂在它们要理解真实代码仓库、遵守工程约束、处理 Git 状态、运行测试、避免破坏用户未提交的改动,还要在失败时继续调试。
12. 一张对比表
| 系统 | 类型 | 核心能力 | 复杂点 |
|---|---|---|---|
| 本文的小 agent | 学习用命令行 agent | tool-use loop、天气工具、身份、用户画像 | 简单、单进程、无长期运行 |
| OpenClaw / Hermes | 个人 AI 运行时/多 agent 系统 | 多入口、多 agent、cron、记忆、工具生态 | 会话、权限、插件、运行时稳定性 |
| Claude Code | coding agent | 读写代码、执行命令、修 bug、跑测试 | 代码理解、仓库上下文、工程安全 |
| Codex | coding agent | 代码修改、调试、审查、测试闭环 | 工具权限、上下文管理、协作协议 |
13. 我现在理解 Agent 的方式
经过这个练习,我觉得 agent 可以这样理解:
Agent = LLM + 上下文 + 工具 + 循环 + 状态
其中:
身份 -> prompt
对用户的认知 -> user_profile / memory
外部能力 -> tools
专项任务说明 -> skills
外部工具生态 -> MCP
长期运行能力 -> runtime
多个角色协作 -> multi-agent
所以学习 agent 不一定要一上来就用复杂框架。更好的路线是:
先写一个最小 loop
再加一个真实工具
再加身份
再加用户画像
再加记忆
再加 skills
最后再接 MCP 和多 agent
这样每一层复杂度都能看见,不会被框架一下子淹没。