从0开始手写AI Agent框架:nano-agentscope(一)项目介绍

过去的一年里,AI Agent 已经从"概念验证"迅速走向"工程实践"。

相比传统的「Prompt + LLM」模式,Agent 具备以下关键特征:

  • 🧠 自主推理(Reasoning)
  • 🔧 工具调用(Tool Use)
  • 🗂️ 状态 / 记忆管理(Memory)
  • 🔁 多轮决策循环(ReAct Loop)
  • 🤝 多 Agent 协作(Multi-Agent,进阶)

市面上已经出现了不少成熟框架,例如 AgentScope、AutoGen、LangGraph 等。但它们往往工程复杂、抽象层级高,对于想真正理解 Agent 内部机制的开发者并不友好。

于是我写了这个项目:

nano-agentscope:一个"能跑、够用、看得懂"的 AI Agent 框架

它的目标不是功能齐全,而是帮助你从底层理解:Agent 到底是如何工作的

项目地址:

👉 https://github.com/brianxiadong/nano-agentscope

我写 nano-agentscope 的动机很朴素:把 Agent 这套东西拆到"我能完全掌控每一环"的程度

真实工程里,Agent 失败通常不是"代码报错"那么简单,而是下面这些更隐蔽的问题:

  • 上下文断了:你以为模型看到了工具结果,但其实没喂进去。
  • 协议不一致:内部消息结构和 SDK 消息结构混着用,一扩展就炸。
  • 工具调用闭环没打通 :模型确实发起了 tool_call,但你回写 tool_result 的格式不对,下一轮推理完全忽略。
  • 排障没有抓手:看不到 LLM 请求、看不到工具入参、看不到工具结果,最后只能"改 prompt 祈祷"。

所以一期我只做一个目标:

  • 把单智能体的 ReAct(Reasoning + Acting)闭环跑通,并做到可 debug。

读完这一篇,你应该能做到两件事:

  1. 从源码层面说清楚:一个最小 Agent 框架需要哪些抽象、各自边界在哪里。
  2. 真出问题时,你知道从哪一环开始定位,而不是盲目调 prompt。

项目介绍

nano-agentscope 是一个极简版的 AI Agent 框架,设计目标非常明确:

  • ✅ 代码量小,可完整通读
  • ✅ 模块职责清晰,结构直观
  • ✅ 保留主流 Agent 框架的核心思想
  • ❌ 不追求"开箱即用"的复杂能力

你可以把它理解为:

AgentScope 的"教学版 / 最小实现"

当前 nano-agentscope 的核心结构如下:

text 复制代码
nano_agentscope/
├── agent.py        # Agent 核心执行引擎
├── message.py      # 消息与内容结构定义
├── model.py        # LLM 抽象与实现
├── formatter.py    # Prompt / 消息格式化
├── memory.py       # 对话与上下文记忆
├── tool.py         # 工具注册与执行
└── tests/          # 基础测试

nano-agentscope 的 Agent 本质上是一个 ReAct(Reason + Act)循环执行器。

整体流程可以简化为:

text 复制代码
用户输入
   ↓
消息(Message)
   ↓
Prompt 格式化(Formatter)
   ↓
大模型(LLM)
   ↓
解析模型输出
   ├─ 普通回答 → 返回给用户
   └─ 工具调用 → 执行 Tool
                      ↓
                  工具结果
                      ↓
                  更新 Memory
                      ↓
                  继续下一轮推理

一句话总结:

Agent = LLM + 状态 + 工具 + 循环控制

而 nano-agentscope 做的事情,就是把这几个要素拆开、写清楚。

1)我的拆分原则:让"变化"停留在最小范围内

写框架最容易犯的错是:把所有东西都塞进 Agent.reply(),然后靠 if/else 维护世界和平。nano-agentscope 的拆分原则是:把变化隔离在边界上

  • 模型厂商会变(OpenAI / DashScope / 自建网关)
  • 工具来源会变(本地函数 / 远程 MCP / 业务 RPC)
  • 消息协议会变 (不同 SDK 的 messages 结构、tool calling 结构差异)

因此我把核心链路拆成 5 个可替换的模块:

  • Msg:内部统一消息协议(我只在内部认这一套)
  • Memory:保存上下文(一期先最简单)
  • Formatter:内部协议 → 某个 SDK 的请求协议
  • Model:某个 SDK 的响应 → 内部统一响应
  • Toolkit:工具注册 / schema 生成 / 执行 / 结果回写

ReActAgent 只做"编排",不做"适配"。


2)先定"内部协议":不要让 SDK 协议污染你的业务逻辑

我见过太多项目一开始直接用 OpenAI 的 messages 结构写业务逻辑,后面想接第二家模型就重构到吐血。

nano-agentscope 的策略是:内部统一用 Msg + ContentBlock

  • Msg 代表一条消息(role/name/content/metadata/...
  • content 不仅是字符串,而是多个内容块:
    • text
    • tool_use
    • tool_result
    • image(简化)

一个关键的小设计是:即使 content 是字符串,也要能"自动视作文本块",这样上层逻辑永远按"块"处理。

落点代码:message.pyMsg.get_content_blocks()


3)ReAct 主循环:最小闭环长什么样?

ReAct 的本质非常简单:

  1. Reasoning:把上下文喂给模型,让它决定要不要用工具
  2. Acting:如果模型要用工具,就执行工具,把结果回写上下文
  3. 重复直到模型不再请求工具

nano-agentscope 里,这个闭环几乎一眼就能看懂:

  • 落点代码:agent.pyReActAgent.reply()
  • 判断是否继续循环:看输出里有没有 tool_use

最重要的一句工程经验是:

  • 工具结果不回写记忆,就等于没调用过工具。

这是绝大多数工具调用失败的根因(而不是 prompt 写得不好)。


4)Formatter:工具调用最容易"卡死"的就是这层

如果你只看模型输出,很容易误判:

  • 模型已经发起 tool_calls
  • 但你回写 tool_result 的消息格式不对
  • 下一轮模型拿不到工具结果,于是继续瞎编/继续调用

因此 nano-agentscope 里把 Formatter 当成"协议转换器",并且默认实现 OpenAIFormatter

  • 内部 tool_use → OpenAI 风格 tool_calls
  • 内部 tool_result → OpenAI 风格 role="tool" + tool_call_id

落点代码:formatter.pyOpenAIFormatter.format()

工程上你可以把它理解为:

  • 内部协议稳定ContentBlock
  • 外部协议可替换(换模型 SDK 时换 Formatter 即可)

5)Model 适配:把"千奇百怪"的响应统一成 ChatResponse

上层 Agent 真正关心的只有两件事:

  • 这次输出有没有 tool_use
  • 如果没有,最终文本是什么?

因此 Model 层的核心职责就是:

  • 把不同 SDK 的响应解析成统一的 ChatResponse(content=[...blocks])
  • 把 token/metadata 统一收敛,便于日志和统计

落点代码:model.py

这层看起来"很 boring",但它把上层 Agent 从 SDK 细节里解放出来,是框架能扩展的关键。


6)MCP:把远程工具当成本地工具用(先把心智模型立住)

一期我不展开 MCP 的协议细节,只建立一个工程上好用的心智模型:

  • MCP server 提供工具列表
  • 客户端把每个远程工具包装成一个"可 await 的函数对象"
  • Toolkit 把它当成本地函数一样注册/执行

落点代码:mcp.pyMCPToolFunction

为什么这套方式工程上好用?因为它让"工具来源"对 Agent 来说是透明的:

  • 本地工具/远程工具都走同一套 tool calling 闭环
  • 远程网络抖动可以在 MCP 这一层做超时/重试兜底(不污染 Agent 主逻辑)

相关推荐
奔袭的算法工程师2 小时前
论文解读--FocalFormer3D : Focusing on Hard Instance for 3D Object Detection
人工智能·目标检测·计算机视觉
Sui_Network2 小时前
Sui 2025→2026 直播回顾中文版
大数据·前端·人工智能·深度学习·区块链
小宋加油啊2 小时前
lora大模型微调小例子
人工智能
电商API&Tina2 小时前
【电商API接口】多电商平台数据API接入方案(附带实例)
运维·开发语言·数据库·chrome·爬虫·python·jenkins
天云数据2 小时前
【报名开启】“智防于心·安产于行”——AI赋能能源安全新质生产力研讨会(北京)
人工智能·安全·能源
富唯智能2 小时前
解锁“试管自动抓取搬运”新纪元:富唯智能复合机器人重塑精准物流
人工智能·机器人
ZPC82102 小时前
FANUC 机器人 PR 寄存器
人工智能·python·算法·机器人
秃了也弱了。2 小时前
python实现语音识别:SpeechRecognition库
python
yaoxin5211232 小时前
278. Java Stream API - 限制与跳过操作全解析
java·开发语言·python