零依赖极简 Agentic 框架架构解析
在 AI Agent 框架百花齐放的当下,动辄数万行代码、依赖数百个 npm 包的 "重型" 框架已成为常态。然而,NanoAgent 和 JS-son 等项目却走了一条截然不同的路 —— 以不足千行代码实现完整的 Agent 运行时,且零运行时依赖。这种极简架构不仅降低了认知负担,更揭示了 Agent 系统的本质:状态机、工具编排与事件流的精妙组合。
极简架构的设计哲学
NanoAgent 的核心理念是 "单一职责":框架只负责控制循环(Control Loop),将 RAG、向量检索、数据存储等能力通过 MCP(Model Context Protocol)标准委托给外部工具。这种设计使得核心代码量压缩至约 1000 行 TypeScript,却足以支撑复杂的 Agent 工作流。
JS-son 则提出了三条设计原则:可用性优于理论优雅、灵活性优于严格规范、可扩展性优于开箱即用。这些原则强调框架不应强加特定的编程范式,而应作为 "即插即用" 的依赖融入现有技术栈。
两种框架的共同点是零依赖哲学—— 核心模块不引入任何第三方库,仅依赖语言原生能力。这不仅减少了供应链攻击面,更使得代码可审计性大幅提升:开发者可以在一个下午内通读并理解整个框架的实现逻辑。
状态机设计:纯函数与不可变快照
NanoAgent 的状态管理采用不可变状态机模式。每个执行步骤返回全新的 AgentState 对象,而非修改现有状态。这种设计带来了三个工程优势:
首先,可重复运行。由于状态变更通过纯函数实现,相同的输入必然产生相同的输出,便于调试和测试。其次,时间旅行调试。完整的状态快照序列可以被持久化,支持任意时刻的状态回溯。第三,并发安全。不可变数据消除了竞态条件,使得 Agent 可以在边缘计算等受限环境中安全运行。
AgentState 的核心结构包含:模型驱动器、消息历史、内存数据和终止状态。与之配合的 AgentContext 则提供纯函数钩子:目标检测、工具注册表、控制器逻辑等。这种分离确保了状态数据与业务逻辑的解耦。
JS-son 在此基础上引入了 BDI(Belief-Desire-Intention)架构。Belief 表示 Agent 对世界的认知,Desire 表达目标倾向,Intention 则是当前激活的计划集合。每个 Agent 的 next() 方法执行标准的推理循环:更新信念、应用偏好函数、执行激活计划、向环境发送动作请求。
工具调用编排:从注册表到 MCP
工具编排是 Agent 框架的核心能力。NanoAgent 的 ToolRegistry 采用JSON Schema 边界校验策略:工具定义时必须提供输入参数的 JSON Schema,框架在调用前自动验证参数合法性,失败时提前拦截。
工具函数可以返回 memPatch 对象,通过纯 Lambda 函数更新 Agent 内存。这种设计使得工具不仅是副作用的执行者,更是状态转换的参与者。例如,一个数据库查询工具可以在返回结果的同时,将查询结果缓存到 Agent 的短期记忆中。
更值得关注的是 MCP(Model Context Protocol)集成。NanoAgent 同时提供 MCP 服务端和客户端实现:
- 服务端模式:通过
serveMCP将本地工具暴露为 HTTP 端点,支持跨进程、跨语言的工具调用 - 客户端模式:通过
MCPClient消费远程工具,自动处理工具发现(listTools)、缓存(5 分钟 TTL)和调用转换
这种架构使得工具可以脱离 Agent 进程独立部署 ——RAG 检索可以运行在 GPU 集群,向量数据库可以托管在托管服务,Agent 核心仅需维持轻量级的 HTTP 客户端。水平扩展时,工具作为无状态 HTTP 处理器,可以使用标准的负载均衡和自动扩缩容策略。
事件流处理:确定性步进与异常恢复
Agent 的执行流程被抽象为确定性步进(Deterministic Stepping)。stepAgent 函数驱动单次状态转换:调用模型 → 解析工具调用 → 执行工具 → 更新状态。每个步骤原子化,失败时触发恢复钩子。
NanoAgent 内置了卡死检测机制:空响应、重复的助手消息、缺失的工具输出都会触发异常处理。框架定义了四种终止原因:await_user(等待用户输入)、tool_error(工具执行错误)、done(任务完成)、stopped(外部停止)。
对于复杂工作流,框架提供 Sequence 包装器支持多阶段编排。每个阶段可以配置独立的上下文、初始状态和最大步数限制(maxSteps)。工作流执行后返回最终结果和历史记录,便于审计和重放。
可落地的工程参数
基于上述架构分析,以下是实现极简 Agentic 框架的关键参数清单:
状态管理参数
- 状态快照深度:建议保留最近 50-100 个状态快照用于调试
- 内存补丁大小:单个
memPatch建议不超过 10KB,避免状态膨胀 - 消息历史截断:当消息数超过 20 条时,考虑摘要压缩策略
工具编排参数
- MCP 缓存 TTL:工具发现结果缓存 5 分钟,平衡实时性与性能
- Schema 校验:所有工具输入必须定义 JSON Schema,必填字段显式声明
- 超时配置:工具调用默认超时 30 秒,可配置重试策略(最多 3 次)
工作流控制参数
- 最大步数:单阶段工作流默认限制 8 步,防止无限循环
- 卡死检测:连续 3 次相同助手消息触发异常恢复
- 调试模式:开发环境启用
debug: true,输出每步的状态变更详情
部署参数
- Bun 运行时:NanoAgent 针对 Bun 优化,冷启动时间 < 100ms
- 边缘就绪:核心包体积 < 50KB(gzip),适合 Serverless 部署
- 内存占用:典型 Agent 实例内存占用 < 128MB
风险与局限
极简架构并非银弹。首先,功能边界清晰意味着复杂场景需要自行扩展。例如,JS-son 当前仅支持同步执行,异步计划支持仍是未来工作。其次,零依赖要求开发者自行处理日志、监控、配置管理等横切关注点。第三,MCP 生态尚处早期,工具标准化程度不足,跨框架兼容性有待验证。
此外,纯函数状态机虽然调试友好,但状态序列化开销在大规模 Agent 集群中可能成为瓶颈。建议在生产环境中启用状态压缩(如 MessagePack)或差异同步策略。
结语
NanoAgent 和 JS-son 证明了 Agent 框架可以既极简又完整。通过聚焦状态机、工具编排和事件流三大核心,它们将框架代码量压缩了两个数量级,同时保持了生产可用性。这种设计哲学对于资源受限场景(边缘计算、IoT、Serverless)尤为适用,也为 Agent 框架的 "去臃肿化" 提供了可行路径。
当大多数框架在追逐功能完备性时,极简主义提醒我们:Agent 的本质是循环 —— 观察、思考、行动 —— 仅此而已。
参考资料
- NanoAgent GitHub 仓库:https://github.com/hbbio/nanoagent
- JS-son 论文与文档:https://github.com/TimKam/JS-son
- Agentic Motherfucking Website:https://agenticmotherfucking.website/
- Model Context Protocol 规范:https://modelcontextprotocol.io/introduction
内容声明:本文无广告投放、无付费植入。
如有事实性问题,欢迎发送勘误至 i@hotdrydog.com。