跳转至

第 6 章:从 Mini Agent 到真实项目

目标:理解教学版 Agent 距离可维护、可扩展、可上线项目还差什么,以及应该按什么顺序补齐这些能力。

先说结论:前五章已经解决了什么

前五章已经把一个 AI Agent 的核心骨架搭出来了:

  • Provider:负责和模型通信
  • Tool + Registry:负责声明与执行工具
  • ReAct Loop:负责“思考 -> 行动 -> 观察 -> 再思考”
  • Session / Memory / Context:负责状态与上下文
  • MessageBus / Channel:用简化教学模型说明如何把 Agent 从终端扩展到多平台
  • Skills:负责按需注入领域知识

这意味着你已经不是在看概念图,而是真的有了一个能对话、能做事、能扩展、能接平台的教学版 Agent。

但从“能跑”到“能长期维护”,还差一层工程化能力。

6.1 先承认边界

教学版的目标是帮助你理解系统为什么这么设计,不是直接充当生产脚手架。

它最常见的边界有 6 类:

  1. 配置写死在代码里,不适合多人协作
  2. 工具边界过松,安全性不足
  3. 对失败场景缺少重试和恢复
  4. 多用户并发时没有完整的隔离与锁
  5. 日志和观测薄弱,出问题难排查
  6. 测试策略基本靠手动验证

如果你先看清这些边界,就不容易把“教学代码能跑”误解成“项目已经能上线”。

6.2 第一步:把单文件脚本拆成项目结构

前几章的 mini_agent.py 很适合教学,但不适合继续增长。一个更稳的最小结构通常像这样:

mybot/
├── app.py
├── config.py
├── providers/
├── agent/
├── tools/
├── session/
├── memory/
├── channels/
├── workspace/
└── tests/

拆分原则只有一条:按职责拆,不按“看起来专业”拆。

例如:

  • providers/ 只管模型接口
  • tools/ 只管工具定义和实现
  • agent/ 只管推理循环和上下文组装
  • channels/ 只管平台接入

这样以后你改 Telegram 适配层时,不会顺手把 ReAct 循环也改坏。

6.3 配置管理

最早期教学草稿常把 API Key 和模型写进代码,但这会诱导复制凭据。当前配套示例已经改为从环境变量读取凭据和模型,并默认使用临时教学工作区;真实项目还要做到三件事:

  1. 密钥不写死在代码里
  2. 模型、工作区、开关项可配置
  3. 支持多实例隔离

一个实用的分工方式是:

  • 环境变量:放敏感信息,如 API Key
  • 配置文件:放模型名、workspace 路径、启用的 channels
  • 代码默认值:只放安全且通用的兜底值

这样你就能很自然地从“一个脚本”过渡到“一个可复制的 bot 实例”。

6.4 安全边界

Agent 项目最容易被低估的不是 Prompt,而是工具风险

比如教学版里的 exec 很方便,但真实项目至少要继续补三层限制:

  • 命令黑名单或白名单
  • 路径限制,只允许访问工作区
  • 用户访问控制,例如 allowFrom

你可以把它理解成三道闸:

  1. 谁能用这个 Bot
  2. 这个 Bot 能碰哪些文件
  3. 这个 Bot 能执行哪些动作

缺少任意一道,Bot 都可能从“聪明工具”变成“高权限脚本入口”。

6.5 错误恢复与重试

教学版默认的是“调用失败就报错返回”。真实项目至少会遇到这些情况:

  • Provider 超时
  • 模型返回格式异常
  • 外部 API 返回 429
  • Tool 调用偶发失败
  • Channel 断连后需要恢复

这时候你要补的不是“更多 if”,而是明确的错误策略:

  • 哪些错误直接返回用户
  • 哪些错误自动重试
  • 重试几次
  • 失败后是否降级

工程化的本质不是永不失败,而是失败时行为可预期

6.6 并发与会话隔离

单人 CLI 脚本几乎不会暴露并发问题,但一旦接入 Telegram、Discord 这类平台,很快就会遇到:

  • 两个用户同时发消息
  • 同一个用户短时间内连续触发多轮工具调用
  • 一个 session 正在处理时又来了新消息

你至少要把下面两件事想清楚:

  1. session_key 如何唯一标识会话
  2. 同一个 session 是否需要串行处理

很多“AI 回答串台”问题,根本不是 Prompt 问题,而是会话隔离没设计好。

6.7 观测与调试

教学版适合靠 print() 看过程,但真实项目至少要能回答下面几个问题:

  • 这条回复来自哪个 session
  • 这轮用了哪个模型
  • 调了哪些工具
  • 哪一步失败了
  • 失败发生在 provider、agent、tool 还是 channel

最低限度建议记录:

  • 请求时间
  • session_key
  • 输入长度
  • 调用的 tool 名称
  • 错误类型

一旦这些基础日志在,排查效率会差很多个量级。

6.8 测试策略

教学版主要靠“最小验证步骤”保证你理解机制。项目化以后,建议至少补 3 层测试:

Tool 单测

验证:

  • 参数是否合法
  • 错误是否可预期
  • 输出格式是否稳定

Agent / Session 测试

验证:

  • Session 是否正确保存与读取
  • 历史截断是否符合预期
  • Context Builder 是否包含关键部分

集成测试

验证:

  • 一条消息能否从 channel 进来,再正确走完整个处理链路
  • Tool 失败时,最终行为是否符合你的设计

不要一开始就追求大而全的测试矩阵。先把最容易坏的边界测起来。

6.9 如何开始你自己的项目

如果你准备从现在开始做自己的 bot,推荐按这个顺序推进:

  1. 选一个足够窄的场景
  2. 只接一个 channel
  3. 先做 1 到 2 个高价值工具
  4. 再补 1 个真正有用的 Skill
  5. 跑通后再补安全、日志、重试

一个好的起点通常不是“做个平台”,而是:

  • 一个财务顾问 Bot
  • 一个代码助手 Bot
  • 一个团队 FAQ Bot
  • 一个个人助理 Bot

场景越具体,你越容易判断 Tool、Skill 和 Prompt 到底该放在哪一层。

6.10 什么时候该回头读 nanobot 源码

你不需要一开始就通读整个仓库。更高效的方式是“带着问题回去看”:

main 差异:插件化 Channel 的阅读入口

v0.2.2 用户仍按稳定版命令和配置操作。仅当你要审阅固定对照 main@b189a376 的新结构时,才从各插件包的 manifest.py 进入实现,例如 telegram/runtime.pywebsocket/runtime.py。浏览器服务的其余边界继续沿 webui/ 追踪。

这样源码会从“很大一片目录”变成“带答案的参考实现”。

6.11 这章真正想告诉你的事

前五章已经告诉你Agent 是怎么长出来的。这一章想补的是另一半:项目是怎么长稳的

从这里开始,你应该把教学版 Agent 当成骨架,而不是终点:

  • 结构先清楚
  • 场景先收窄
  • 路径先跑通
  • 然后再补安全、并发、重试和测试

这样你做出来的第一个 bot,才更可能继续长成第二个、第三个,而不是在第一次扩展时就塌掉。

从教程走向项目,推荐按这个顺序补

如果你现在准备把教学版继续长成自己的项目,最稳的路线通常不是“哪里都补一点”,而是按下面顺序推进:

  1. 先把配置外置:不要再把 key、model、workspace 写死在代码里
  2. 再补安全边界:先收紧工具能力和访问范围
  3. 再补日志与观测:没有日志,后面很多问题根本没法定位
  4. 再补重试和错误策略:让失败时行为可预期
  5. 最后再补并发优化和更多平台:这是放大器,不是起步器

很多第一次做 Agent 项目的人,最容易犯的错不是“补少了”,而是补的顺序反了

如果你现在就想开始自己的 Bot

先不要急着做这些:

  • 不要一开始就接很多个平台
  • 不要一开始就做很宽的通用能力
  • 不要一开始就为并发和扩展性设计一个很重的框架

先做一个场景窄、路径短、能稳定完成任务的 Bot,比“看起来架构很完整”的空骨架有价值得多。

相关材料