跳至主要內容

从零理解 Agent,再到 miniagent 与 Claude Code 的实现对比

离心原创大约 12 分钟notesAIAgentGo

我用Agent写了一个Mini Agent...

从零理解 Agent,再到 miniagent 与 Claude Code 的实现对比

最近用 Agent(Claude Code)写了一个 mini agent,这篇文章回顾一下这个过程,顺便聊聊 Agent 的核心概念,以及 miniagent 和 Claude Code 在实现思路上的异同。


一、什么是 Agent?

"Agent" 这个词被用烂了。它可以指一段带 for 循环的 LLM 调用,也可以指复杂的多智能体协作系统。这里我们只讨论最核心的定义:

Agent = 感知 + 推理 + 行动 + 记忆的循环体

更具体地说,一个 Agent 的基本要素包括:

1. ReAct 循环(Reasoning + Acting)

Agent 最经典的执行模式是 ReAct:

用户输入
  → LLM 推理(Thought)
  → 工具调用(Action)
  → 工具返回(Observation)
  → LLM 继续推理
  → ... 循环
  → 最终回答(Final Answer)

这个循环让 LLM 从"一次性问答"变成了"持续迭代解决问题"的系统。

2. Tool Calling(工具调用)

工具是 Agent 与外部世界交互的桥梁。没有工具,LLM 只是一个文字游戏机;有了工具,它可以:

  • 读写文件系统
  • 执行 Shell 命令
  • 发起 HTTP 请求
  • 操作数据库
  • 调用其他 API

现代 LLM(GPT-4、Claude、DeepSeek 等)都原生支持 Function Calling,Agent 框架的核心工作之一就是管理这套工具注册与调度机制。

3. Memory(记忆)

Agent 需要记忆才能在多轮对话和跨任务场景下保持连贯性。记忆通常分为几层:

层级描述存储形式
上下文窗口当前对话的即时记忆LLM context
短期记忆本次 session 的摘要文件 / 数据库
长期记忆跨 session 的持久知识结构化文件 / 向量数据库

4. Planning(规划)

复杂任务需要先规划再执行。规划能力让 Agent 把"写一个完整功能"这种大任务分解成可执行的步骤序列,而不是盲目地一步步试错。

5. Guardrails(安全护栏)

Agent 能执行真实操作,因此安全是绕不开的话题:

  • 哪些工具需要用户确认?
  • 哪些 HTTP 地址可以访问?
  • 输出内容如何脱敏?
  • 同一个工具调用多少次才算异常?

护栏系统是生产级 Agent 的必备组件。


二、miniagent:用 Go 写一个最小可用的 Agent Runtime

项目背景

miniagent 是我用 Claude Code 辅助写的一个 Go 项目,目标是实现一个小而完整的本地优先 Agent 运行时:

A small Go-based AI agent runtime with planning, tools, memory, skills, and guardrails.

项目地址:github.com/LixvYang/miniagentopen in new window

核心设计原则

miniagent 刻意保持克制:

  • Small Go core:代码量小,易读、易改、易嵌入
  • Provider-flexible:兼容 OpenAI-compatible API,可接 OpenAI、DeepSeek 等
  • Local-first safety:工作区边界、HTTP 守卫、审批钩子内置
  • Structured runtime:planner、tools、memory、sessions、skills、guardrails 各自独立分包

项目结构

cmd/miniagent/          CLI 入口
internal/agent/         主执行循环
internal/config/        YAML + 环境变量配置
internal/guard/         集中式守卫策略与审批存储
internal/llm/           模型抽象层
internal/llm/openai/    OpenAI-compatible 客户端
internal/memory/        日志、投影、草稿、Prompt 注入
internal/planner/       运行时计划状态与渲染
internal/session/       多轮对话历史
internal/skills/        SKILL 发现、frontmatter、选择、安装
internal/tools/         内置工具与注册表
skills/                 默认内置 skill 集合

执行流程:Plan-First Loop

miniagent 采用了一个 plan-first 的执行模型,这是它区别于简单 ReAct 实现的关键设计:

用户输入任务
  → LLM 必须先调用 plan_create(不能跳过)
  → 生成简洁可执行的计划
  → 按步骤执行工具
  → 每个成功的工具调用自动推进计划步骤
  → 完成后输出最终答案
  → (可选)-show-plan 展示计划执行状态

这个设计强制让模型先思考后行动,避免了"直接乱调工具"的问题。

内置工具集

plan_create   创建执行计划(必须首先调用)
get_time      获取当前时间
remember      写入记忆
recall        读取记忆
list_skills   列出可用 skills
read_file     读取文件
write_file    写入文件
run_shell     执行 Shell 命令
http_get      发起 HTTP GET 请求

记忆系统

记忆存储在本地文件系统,结构清晰:

memory/
  log/events.jsonl          追加写入的事件日志(Event Sourcing)
  log/checkpoint.json       投影检查点
  long_term.json            持久化长期记忆
  index.md                  长期记忆的可读索引
  YYYY-MM-DD/<session>.md   短期 session 摘要
  sessions/<session>.json   原始对话历史

流程是:任务完成 → 追加 MemoryEvent → 后台 projection worker → LLM 生成摘要草稿 → 更新短期/长期读模型 → 注入到下次运行的 Prompt。

Skills 系统

Skills 是通过 SKILL.md 文件定义的可复用指令集,格式和 Claude Code 的 skills 体系完全一致(frontmatter + Markdown body):

# 使用指定 skill
go run ./cmd/miniagent run --skill planning "Plan a refactor"

# 安装远程 skill
go run ./cmd/miniagent skills install https://github.com/example/SKILL.md

# 在 prompt 中引用 skill
go run ./cmd/miniagent run "Use $memory before answering"

护栏系统

守卫层统一管理所有安全策略:

  • 指定工具执行前需要用户审批
  • 单次运行内禁止重复工具调用
  • 每个工具的调用次数上限(防止循环)
  • HTTP 白名单、私有 IP 拦截、重定向策略
  • 工具观察结果和最终回复的脱敏
# 列出所有守卫规则
go run ./cmd/miniagent guard list

# 审批某次工具调用
go run ./cmd/miniagent guard approve <approval-id>

快速上手

export MINIAGENT_MODEL_NAME=deepseek-chat
export MINIAGENT_MODEL_BASE_URL=https://api.deepseek.com/v1
export MINIAGENT_MODEL_API_KEY=your_api_key

# 一次性任务
go run ./cmd/miniagent run -show-plan "检查当前项目并生成摘要"

# 多轮对话
go run ./cmd/miniagent chat -session demo

三、对比:miniagent vs Claude Code 的实现思路

claude-code-docsopen in new window 是一份对 Claude Code 客户端源码的深度技术分析文档,原始代码通过 npm 包的 sourcemap 意外泄露。515,498 行 TypeScript,2766 个文件,记录了一个生产级 Agent 的完整实现。

下面从几个维度对比两者的思路差异:

1. 执行循环的技术实现

miniagentClaude Code
循环模式Plan-First ReAct,Go for 循环6 阶段 ReAct,TypeScript AsyncGenerator
规划约束强制 plan_create 作为第一个工具调用无强制,依赖模型能力自主规划
状态管理函数参数传递7 个核心变量 + 不可变更新(每轮 {...state}
流式输出暂不支持(返回完整结果)AsyncGenerator yield 逐 token 输出
子 Agentfork 机制(Skill Agent、Compact Agent、Session Memory Agent)

Claude Code 用 AsyncGenerator 构建主循环是一个关键选型——它天然支持"执行到一半暂停、把中间结果交出去、等外面处理完再继续",让流式输出、实时审批、工具并发可以统一在同一套机制下实现。miniagent 用简单的 Go for 循环,清晰够用,但没有流式能力。

Claude Code 还实现了 Agent fork 机制:执行 Skill、生成压缩摘要、沉淀 session memory 时,都会 fork 出独立子 Agent,拥有独立 token 预算和消息历史,避免污染主 Agent 上下文。fork 的子 Agent 还会与父 Agent 共享 Prompt Cache(CacheSafeParams 机制),复用缓存降低 API 成本。

2. 记忆架构

miniagentClaude Code
指令记忆无(靠 System Prompt 硬编码)CLAUDE.mdopen in new window 五层体系(全局管理 → 用户 → 项目 → 本地 → 自动)
记忆组织单层文件@include 指令支持模块化拆分,支持 200+ 文件类型,防循环引用
长期记忆写入手动调用 remember 工具Agent 自主写入 MEMORY.mdopen in new window(最多 200 行/25KB,系统级约束)
短期记忆session 摘要文件Session Memory,与压缩系统深度集成
上下文压缩3 层递进:微压缩 → Session Memory 沉淀 → Full Compact 摘要

Claude Code 的记忆系统最有意思的设计有两个:

CLAUDE.mdopen in new window 五层覆盖的逻辑和 CSS 层叠、Git 配置层级一脉相承——越具体的配置优先级越高,本地覆盖全局。团队可以把公司规范放全局级、项目约定放项目级、个人偏好放本地级,互不干扰。

MEMORY.mdopen in new window 是 Agent 自己写给自己看的,和人写给 Agent 看的 CLAUDE.mdopen in new window 严格区分。所有记忆最终拼接注入 system prompt,还附带显式的 OVERRIDE 声明,防止模型的预训练默认行为盖过用户配置。

miniagent 目前没有等价的多层指令记忆机制,这是两者最大的功能差距之一。

3. 工具系统

miniagentClaude Code
工具数量9 个40+(部分通过 feature flag 控制)
工具协议OpenAI Function Calling自定义协议 + MCP(6 种传输类型)
工具粒度通用(run_shell 涵盖大部分操作)精细化拆分(GlobTool/GrepTool/FileEditTool/FileWriteTool 各司其职)
执行方式串行并行(Promise.all,多工具同时运行)
错误隔离单一 error 返回每个工具独立 try/catch,单个失败不影响其他并行工具
扩展方式代码层注册MCP server(任意语言实现)

值得关注的是 Claude Code 把文件编辑和文件写入分成两个工具FileEditTool 做精确字符串替换,FileWriteTool 做整文件写入。修改一个 1000 行文件中的 3 行时,Agent 只需发那 3 行的 diff,而不是整个文件——同时节省 token 和降低出错率。

工具数量越多,模型选错的概率也越高。Claude Code 用精心设计的工具描述和 system prompt 使用指南来缓解这个问题,这本身也是一个持续调优的工程方向。miniagent 工具少,但好处是模型选择简单,出错率低。

4. 安全模型

miniagentClaude Code
权限模式单一审批流三种模式:default(全人工)/ auto(ML 分类器)/ plan(规划置信度)
危险命令拦截重复调用限制 + 循环次数上限42 条硬编码 bash 危险模式(python、node、eval、curl 等)
智能分类YOLO 分类器:side-query Claude 模型评估命令安全性 + 置信度评分
模式切换安全不适用Dangerous Rule Stripping:切换到 auto 模式时自动剥离可能被绕过的 allow 规则
文件系统沙箱工作区边界限制路径校验 + 路径穿越防护 + .git/.claude 目录保护
行为学习Denial Tracking:记录用户拒绝模式,自适应调整后续权限策略
审批时机CLI 审批,先批准再重跑任务实时阻塞,审批后继续当前执行

Claude Code 权限系统是整个代码库规模最大的单一模块,超过 6300 行代码分布在 25 个文件里。几个值得单独说的设计:

YOLO 分类器:名字来自"You Only Live Once",实现在 yoloClassifier.ts,把即将执行的 bash 命令发给 Claude 模型判断安全性,需要 Opus 4.6 以上版本支持。这意味着 Claude Code 的安全判断本身也在消耗 LLM 调用。

Dangerous Rule Stripping:从 default 切换到 auto 模式时,系统会主动清除之前配置的涉及危险模式的 allow 规则。防止用户在 default 模式下为方便加了 Bash(python *) 的 allow,切到 auto 后被分类器自动放行绕过 42 条拦截规则。这是防御性编程的典型案例:不信任上游配置在所有场景都是安全的。

miniagent 的安全模型轻量很多,规则透明,适合明确边界的本地任务。Claude Code 的安全是多层纵深防御,防御面广但规则不透明。

5. Skills 执行机制

两者的 Skills 格式完全一致(SKILL.md + YAML frontmatter),但执行机制有本质区别:

miniagentClaude Code
执行方式SKILL.mdopen in new window 内容注入主 Agent 上下文fork 出独立子 Agent 执行
上下文隔离无,共享主 Agent 消息历史子 Agent 有独立 token 预算和消息历史
工具限制继承主 Agent 所有工具子 Agent 只能用安全工具子集(不能访问权限管理、MCP 配置等敏感工具)
加载策略启动时注入 metadata,按需读全文两阶段:先只注入 description,确定选用后再读完整 SKILL.mdopen in new window
容量限制system prompt 最多列 150 个 Skill,总字符预算 30,000

Claude Code 的两阶段加载很关键:Agent 选 Skill 时只看 description,不加载全文,避免把所有 Skill 的完整内容塞进 system prompt 爆掉上下文。子 Agent fork 执行则保证一个 Skill 的问题不会影响主 Agent。miniagent 目前是直接注入,在 Skill 数量多时会有上下文压力。

6. 定位差异

miniagentClaude Code
目标场景本地自动化、嵌入业务系统、学习 Agent 实现软件工程任务、大规模代码操作
语言GoTypeScript
代码规模小(易读易改)超大(515K 行)
provider 支持OpenAI-compatible(OpenAI、DeepSeek 等)主要绑定 Claude API
上下文压缩三层自动压缩
记忆层级单层五层 CLAUDE.mdopen in new window + MEMORY.mdopen in new window
开放程度开源(计划中)源码泄露分析

四、用 Agent 写 Agent 的感受

这次用 Claude Code 写 miniagent 的体验很有意思:用一个 Agent 来构建另一个 Agent,在实现记忆系统时能直接"感受"到当前 Agent 的记忆是怎么工作的,在设计 skills 时能对照 Claude Code 的 skills 机制来借鉴。

几个值得记录的点:

  1. Plan-First 约束的价值:强制规划让 Agent 的执行过程更可预测,也更容易调试。Claude Code 没有这个硬约束,但 Claude 模型足够强大,通常会自己规划。对于较弱的模型(如 deepseek-chat),强制规划显著提升了任务完成质量。

  2. Event Sourcing 适合记忆系统:记忆天然是追加写入的,用事件日志 + 投影的模式比直接 CRUD 更稳健,也更容易做 time-travel 调试。

  3. 工具越少越好:miniagent 只有 9 个工具,但足够覆盖大多数本地任务。工具太多会让模型选择困难,增加 token 消耗。

  4. 安全要内置,不要靠约定:HTTP 私有 IP 拦截、重复调用限制这些守卫,必须在框架层实现,不能依赖"模型不会调用危险工具"的假设。


五、总结

Agent 的核心是一个感知-推理-行动的循环,但从 demo 到生产,中间有大量工程细节要填:记忆管理、规划约束、工具安全、上下文压缩……

miniagent 是对这些细节的一次最小化实现,Go 写的,代码量小,适合学习和嵌入。Claude Code 是生产级的参考实现,规模更大,功能更完整。

两者最有趣的交集在 skills 系统——一套通过 Markdown 文件扩展 Agent 行为的轻量机制,简单但有效。