跳转到主内容
Logo

从零搭一个最小 Agent:看清一个 Agent 的全部骨架

Published on
...
Authors

从零搭一个最小 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 来跑模型。

正文插图 2B

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"]
正文插图 3B

关键就是 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学习用命令行 agenttool-use loop、天气工具、身份、用户画像简单、单进程、无长期运行
OpenClaw / Hermes个人 AI 运行时/多 agent 系统多入口、多 agent、cron、记忆、工具生态会话、权限、插件、运行时稳定性
Claude Codecoding agent读写代码、执行命令、修 bug、跑测试代码理解、仓库上下文、工程安全
Codexcoding agent代码修改、调试、审查、测试闭环工具权限、上下文管理、协作协议

13. 我现在理解 Agent 的方式

经过这个练习,我觉得 agent 可以这样理解:

Agent = LLM + 上下文 + 工具 + 循环 + 状态

其中:

身份 -> prompt
对用户的认知 -> user_profile / memory
外部能力 -> tools
专项任务说明 -> skills
外部工具生态 -> MCP
长期运行能力 -> runtime
多个角色协作 -> multi-agent

所以学习 agent 不一定要一上来就用复杂框架。更好的路线是:

先写一个最小 loop
再加一个真实工具
再加身份
再加用户画像
再加记忆
再加 skills
最后再接 MCP 和多 agent

这样每一层复杂度都能看见,不会被框架一下子淹没。

参考资料