AgentGPT 进阶:把自主 AI 代理稳稳部署到生产环境
本教程面向已有基础、想将 AgentGPT 用于实际项目的开发者。你将学会从源码部署、配置自定义工具、优化性能到监控运维的全流程,最终能独立搭建并维护一个生产级的自主 AI 代理服务。
1. 1. 从零搭建本地开发环境:克隆、配置与首次启动
第 1 章:从零搭建本地开发环境:克隆、配置与首次启动
这一章的目标很简单:让你能在自己电脑上跑起来 AgentGPT,看到那个聊天界面,并且能跟它说上话。别被“自主 AI 代理”这种词吓到,本质上就是一套前后端代码,我们把它拉下来、装好依赖、启动服务,然后打开浏览器就能用。
开始之前,先确认你电脑上有什么
AgentGPT 依赖几个基础工具,缺一个后面就会报错。花两分钟检查一下:
- 编辑器:推荐 VS Code,不是必须,但后面调试方便。
- Node.js:版本至少 16+,最好 18 或 20。终端里跑
node -v看看。 - Git:用来克隆代码。
git --version确认。 - Docker Desktop:这个最重要。AgentGPT 用 Docker 跑数据库和后台服务。装好后打开 Docker 应用,登录账号(免费),确保它在后台运行。
docker --version和docker compose version都能正常输出才行。 - OpenAI API Key:去 platform.openai.com 注册,拿到一串以
sk-开头的密钥。先记下来,后面配置要用。 - Serper API Key(可选但推荐):去 serper.dev 注册免费账号,拿到 API key。没有它 Agent 也能跑,但搜索功能会失效。
第一步:把代码拉到本地
打开终端,找个你习惯放项目的目录(比如 ~/projects 或 D:\code),然后跑:
git clone https://github.com/reworkd/AgentGPT.git
cd AgentGPT跑完后你会看到 AgentGPT 文件夹,里面就是完整的项目代码。ls(Mac/Linux)或 dir(Windows)看一眼,能看到 next、platform、db 这些子目录——分别对应前端、后端和数据库配置。
第二步:用自动脚本一键配置
项目自带了一个 setup 脚本,它会帮你做三件事:复制环境变量模板、安装依赖、启动 Docker 容器。省掉你手动一个个敲命令的麻烦。
Mac/Linux 用户:
./setup.shWindows 用户(在 Git Bash 或 PowerShell 里):
./setup.bat脚本跑起来后,它会先问你要 OpenAI API Key。把刚才记下的 sk-... 粘贴进去,回车。接着问 Serper API Key,如果你有就填,没有直接回车跳过。还会问 Replicate API Token,同样可选,跳过就行。
脚本接下来会自动做这些事情:
- 把
.env.example复制成.env,并把你的 API Key 填进去 - 用
npm install安装前端依赖 - 用
pip install安装后端依赖(它会在 Docker 里处理) - 启动 Docker Compose,拉起 MySQL 数据库和后端服务
这个过程大概需要 3-5 分钟,取决于你的网络速度。你会看到终端里一堆日志在滚动,别慌,那是正常现象。
预期结果:脚本结束后,终端最后几行应该显示类似这样的信息:
Frontend: http://localhost:3000
Backend: http://localhost:8000
Database: localhost:3306如果看到报错,最常见的原因是:
- Docker 没启动:去打开 Docker Desktop 应用,等它状态变成绿色再重试。
- 端口被占用:3000 或 8000 端口被其他程序占了。关掉冲突的程序,或者改
.env里的端口配置。 - Node.js 版本太低:升级到 18 以上。
第三步:手动检查环境变量
脚本已经帮你填好了 API Key,但最好看一眼确认。打开项目根目录下的 .env 文件(用编辑器打开),内容大概长这样:
# 必须填
OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# 可选
SERPER_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
REPLICATE_API_TOKEN=
# 数据库配置(脚本自动生成,不用改)
DATABASE_URL=mysql://user:password@localhost:3306/agentgpt确保 OPENAI_API_KEY 那一行不是空的,而且值以 sk- 开头。如果为空,手动填进去。
第四步:启动所有服务
如果脚本已经帮你启动了服务,这一步可以跳过。但如果你中途关掉了终端,或者想重新启动,用这个命令:
docker compose up -d-d 参数让容器在后台运行,这样终端就不会被日志刷屏。想看日志可以用 docker compose logs -f。
启动后,确认所有容器都正常运行:
docker compose ps你应该看到三个容器状态都是 Up:
agentgpt-db-1(MySQL 数据库)agentgpt-platform-1(后端 FastAPI 服务)agentgpt-next-1(前端 Next.js 应用)
第五步:打开浏览器,见证奇迹
打开 Chrome 或 Edge,地址栏输入:
http://localhost:3000你应该能看到 AgentGPT 的界面——一个深色主题的聊天页面,中间有个输入框,写着“Name your AI agent”之类的提示。
如果页面空白或报错:
- 检查终端里有没有报错日志。前端报错看
docker compose logs next,后端报错看docker compose logs platform。 - 最常见的原因是 API Key 无效或没填。去
.env里确认。 - 如果页面加载但一直转圈,可能是后端没连上数据库。等几秒再刷新。
小试牛刀:创建一个 Agent
在输入框里给你的 Agent 起个名字,比如“调研小助手”,然后在目标框里写一个简单的任务,比如:
搜索“2024 年 AI 代理框架排名”,总结前三个框架的特点。
点击“Deploy Agent”按钮。如果一切正常,你会看到 Agent 开始思考、列出任务、执行任务,最后给出结果。这个过程会调用 OpenAI 的 API,所以会消耗你的 API 额度,但一个简单任务也就几分钱。
常见问题速查
| 问题 | 原因 | 解决 |
|---|---|---|
docker: command not found |
Docker 没装或没加到 PATH | 重装 Docker Desktop,重启终端 |
port 3000 already in use |
其他程序占了端口 | 关掉冲突程序,或改 .env 里的 NEXT_PUBLIC_PORT |
OpenAI API key is invalid |
API Key 填错了或过期了 | 去 OpenAI 后台重新生成一个 |
Database connection refused |
MySQL 还没启动完 | 等 10 秒再刷新,或 docker compose restart db |
| 页面能打开但 Agent 不响应 | 后端没连上 OpenAI | 检查 .env 里的 API Key,重启 docker compose restart platform |
下一步
现在你已经能在本地跑起来 AgentGPT 了。下一章我们会配置 OpenAI 和 Serper API 密钥,让 Agent 真正能联网搜索和调用大模型——你现在用的只是最基本的聊天功能,配置好密钥后,Agent 才能发挥真正的自主能力。
2. 2. 配置 OpenAI 与 Serper API 密钥:让 Agent 真正联网
你跟着第一章把 AgentGPT 跑起来了,打开浏览器看到那个漂亮的界面,但一输入目标,Agent 就卡住不动——大概率是因为它还没拿到联网的“通行证”。这一章我们就来解决这个问题:配置 OpenAI 和 Serper 的 API 密钥,让 Agent 真正能思考、能搜索。
为什么需要这两个密钥?
想象一下,AgentGPT 就像一个超级聪明的实习生,但它有两个致命缺陷:第一,它没有自己的大脑(需要 OpenAI 的 GPT 模型来思考);第二,它没有眼睛和耳朵(需要 Serper 来搜索互联网)。没有 API 密钥,这个实习生就是个空壳子,什么都干不了。
前置条件
- 你已经按照第一章完成了
./setup.sh或./setup.bat的安装 - 项目目录下有一个
.env文件(如果没有,复制.env.example重命名即可) - 你有一个浏览器,能打开网页注册账号
第一步:获取 OpenAI API 密钥
OpenAI 的 API 密钥是 Agent 的“大脑皮层”,所有推理、决策、任务分解都靠它。
- 打开 platform.openai.com/signup 注册账号(如果已有账号直接登录)
- 登录后,点击右上角头像 → "View API Keys"
- 点击 "Create new secret key",给你的密钥起个名字比如 "agentgpt-dev"
- 立即复制这个密钥——它只显示一次,关掉页面就再也看不到了
⚠️ 常见坑:很多人复制的时候会不小心多复制一个空格,或者漏掉最后几个字符。建议粘贴到记事本里检查一遍,确保没有多余的空格或换行。
第二步:获取 Serper API 密钥
Serper 是 Google 搜索的 API 封装,Agent 通过它来搜索互联网。没有它,Agent 就只能靠自己的“知识”回答问题,无法获取实时信息。
- 打开 serper.dev/signup 注册
- 注册后会自动获得 2500 次免费查询(够你玩很久了)
- 登录后,在 Dashboard 页面找到 "API Key",复制它
💡 小提示:Serper 的免费额度用完后再注册一个新账号就行,或者升级到付费计划(很便宜,$50/月 5 万次查询)。
第三步:配置环境变量
现在我们把这两个密钥放进项目里。打开项目根目录下的 .env 文件(如果没有,复制 .env.example 并重命名):
# 在项目根目录下
cp .env.example .env然后用文本编辑器打开 .env,找到这两行:
OPENAI_API_KEY=
SERPER_API_KEY=把刚才复制的密钥填进去,注意不要加引号,不要有空格:
OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
SERPER_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx⚠️ 重要:OpenAI 的密钥以
sk-开头,Serper 的密钥是一串随机字符。如果填错了格式,Agent 会报错。
第四步:重启服务让配置生效
环境变量修改后,需要重启后端服务才能生效。如果你是用 Docker 运行的:
# 停止并重新启动所有容器
docker-compose down
docker-compose up -d如果你是用 ./setup.sh 直接运行的,直接关掉终端重新运行一次即可。
验证配置是否成功
打开浏览器访问 http://localhost:3000,创建一个新的 Agent,输入一个需要联网搜索的目标,比如:
"搜索今天比特币的价格,并告诉我最近一周的价格趋势"
如果配置正确,你会看到 Agent 开始思考,然后调用搜索工具,最后给出带实时数据的回答。如果看到类似这样的错误:
Error: 401 Unauthorized - Invalid API key说明 OpenAI 密钥有问题,回去检查一下格式和是否有空格。
如果 Agent 一直在思考但没有任何输出,可能是 Serper 密钥没配置好——试试在浏览器里直接访问 http://localhost:3000/api/agents 看看后端日志。
一个小技巧:用环境变量文件管理多个配置
如果你经常切换不同的 API 密钥(比如开发环境和测试环境),可以创建多个 .env 文件:
# 开发环境
cp .env .env.dev
# 测试环境
cp .env .env.test然后在启动时指定使用哪个文件:
# 使用开发环境配置
docker-compose --env-file .env.dev up -d这样切换环境只需要改文件名,不用每次都编辑 .env 文件。
配置完成后的效果
现在你的 AgentGPT 已经“活”过来了。它不仅能理解你的指令,还能实时搜索互联网获取最新信息。下一章我们会用它做一个真正的竞品调研 Agent,到时候你就会发现,没有这两个密钥,Agent 就是个哑巴;有了它们,它就是个能干的助手。
如果配置过程中遇到任何问题,检查一下:
- API 密钥是否复制完整
.env文件里有没有多余的空格或引号- 重启服务后是否真的加载了新配置(可以看后端日志确认)
搞定了?那我们就进入下一章,让 Agent 真正开始干活吧。
3. 3. 自定义 Agent 名称与目标:写一个能自动调研竞品的 Agent
好,这一章我们来干点实际的。前两章你已经把 AgentGPT 跑起来了,也接上了 OpenAI 和 Serper 的 API。现在,我们要让这个 Agent 真正为你干活——不是让它随便逛,而是给它一个明确的名字、一个具体的任务,让它像你的员工一样去调研竞品。
为什么名字和目标这么重要?
想象一下,你招了个实习生,你只说“去了解一下市场”,他大概率会一脸懵。但如果你说“小王,你去调研一下我们主要竞品 A 公司最近三个月的产品更新和定价策略”,他立马就知道该搜什么、看什么、整理什么。
AgentGPT 里的 Agent 也一样。你给它起的名字(Name)和设定的目标(Goal),就是它的“岗位职责说明书”。名字影响它在对话和日志里的身份标识,目标则直接决定了它要执行的任务链。目标写得越清晰、越可执行,Agent 的产出就越靠谱。
前置条件
在开始之前,确保你已经:
- 完成了第 1 章的本地环境搭建,AgentGPT 在
http://localhost:3000能正常打开。 - 完成了第 2 章的 API 密钥配置,
OPENAI_API_KEY和SERP_API_KEY都已经填好。 - 浏览器里能看到 AgentGPT 的主界面,有一个输入框让你填 Name 和 Goal。
第一步:起个好名字
打开 http://localhost:3000,你会看到一个简洁的界面,顶部有个输入框写着“Name your custom AI...”。这里别随便填个“test”或者“agent”,给它一个有意义的名字。
比如我们要做一个竞品调研 Agent,可以叫:
竞品侦察兵或者更正式一点:
MarketIntel-Agent名字会出现在 Agent 的对话历史、日志输出里,方便你以后区分多个 Agent。如果你同时跑好几个 Agent,一个好名字能让你一眼认出谁是谁。
第二步:写一个能干活的目标
这是最关键的一步。目标框里写的是 Agent 的“终极任务”,它会基于这个目标自己拆解出子任务,然后一步步执行。
我们拿一个真实场景举例:假设你是一家 SaaS 公司的产品经理,想了解主要竞品“Notion”最近三个月的动态。
一个糟糕的目标是:
调研 Notion太模糊了。Agent 不知道要调研什么维度,可能搜出 Notion 的历史、创始人故事、用户评价,乱七八糟一堆。
一个好的目标应该是:
调研 Notion 在 2024 年 1 月至 3 月期间的产品更新、定价策略变化、用户评价趋势和主要功能发布。整理成一份包含时间线、关键变化和影响分析的报告。看到了吗?好目标有这几个要素:
- 明确的范围:时间范围(2024 年 1 月至 3 月)
- 具体的维度:产品更新、定价、用户评价、功能发布
- 期望的输出形式:一份包含时间线、关键变化和影响分析的报告
Agent 拿到这个目标后,会自己规划:先搜索“Notion 2024 年 1 月产品更新”,再搜索“Notion 2024 年定价变化”,然后搜索“Notion 用户评价 2024”,最后把结果汇总成报告。
第三步:点击“Deploy Agent”并观察
填好名字和目标后,点击那个大大的“Deploy Agent”按钮。你会看到 Agent 开始工作:
- 它先显示“思考中...”,然后列出它自己拆解的子任务。
- 接着它开始执行第一个子任务,比如搜索“Notion 2024 年 1 月产品更新”。
- 它会调用 Serper API 去搜索,拿到结果后,用 OpenAI 的模型分析这些结果。
- 然后它继续下一个子任务,直到所有子任务完成。
在界面上,你会看到一个类似聊天记录的窗口,Agent 每完成一步都会输出结果。你可以实时看到它搜到了什么、分析了什么。
常见问题与排查
问题 1:Agent 一直卡在“思考中”不动
这通常是因为 OpenAI API 调用超时或者 Serper API 没配置好。检查一下:
- 你的
.env文件里OPENAI_API_KEY和SERP_API_KEY是否正确? - 打开浏览器开发者工具(F12),看 Network 标签页,有没有请求返回 401 或 429 错误?
- 如果用的是免费 OpenAI 账号,可能有速率限制,等几分钟再试。
问题 2:Agent 搜出来的结果不相关
大概率是你的目标写得太宽泛。比如你写“调研 Notion”,它可能搜出 Notion 的维基百科页面,而不是产品更新。试试把目标写得更具体,加上“产品更新”“定价变化”这些关键词。
问题 3:Agent 执行到一半就停了
AgentGPT 默认有最大迭代次数限制(通常是 25 次)。如果你的目标需要很多子任务,可能没做完就停了。这时候可以:
- 把目标拆得更细,一次只调研一个维度。
- 或者等后面第 6 章我们讲参数调整时,再教你调大迭代次数。
一个小技巧:先手动规划再让 Agent 执行
如果你不确定目标写得好不好,可以先在脑子里或者纸上列一下:如果我是这个 Agent,我会怎么完成这个任务?需要搜索哪些关键词?需要分析哪些信息?
比如调研竞品,典型的步骤是:
- 搜索“竞品名称 + 产品更新 + 时间范围”
- 搜索“竞品名称 + 定价 + 时间范围”
- 搜索“竞品名称 + 用户评价 + 时间范围”
- 把搜索结果汇总,提取关键变化
- 生成对比分析报告
把这些步骤写进目标里,Agent 执行起来会更精准。
试试看:跑一个真实的竞品调研
现在,打开你的 AgentGPT,输入:
- Name:
竞品侦察兵 - Goal:
调研 Notion 在 2024 年 1 月至 3 月期间的产品更新、定价策略变化和用户评价趋势。整理成一份包含时间线、关键变化和影响分析的报告。
点击 Deploy Agent,然后去泡杯咖啡。几分钟后,你会看到一份初步的竞品调研报告。虽然可能不如专业分析师写的那么深入,但作为第一轮信息收集,已经能帮你省下大量手动搜索的时间。
如果结果不错,你可以把这份报告作为起点,再让 Agent 针对某个具体发现做深入调研。比如它提到 Notion 在 2 月发布了 AI 功能,你可以再创建一个新 Agent,目标设为“深入调研 Notion AI 功能的具体能力、定价和用户反馈”。
总结
这一章的核心就一句话:给 Agent 一个清晰、具体、可执行的目标,它就能成为你的得力助手。 名字是它的身份,目标是它的任务书。写目标时,想象你在给一个聪明但需要明确指令的实习生布置工作——越具体,结果越好。
下一章,我们会给 Agent 装上更多“工具”,比如让它能自己算数、读写文件,能力直接翻倍。
4. 4. 给 Agent 接入自定义工具:添加搜索、计算与文件操作能力
给 Agent 装上“手脚”:自定义工具
默认情况下,AgentGPT 的 Agent 其实挺“残废”的——它只能调用内置的搜索和思考能力。如果你想让它帮你算个复杂的表达式、读取本地文件、或者调用一个公司内部的 API,它就只能干瞪眼。
这一章我们就来解决这个问题:给 Agent 添加自定义工具。学完之后,你的 Agent 就能像有了“手脚”一样,执行你指定的任何操作。
前置条件
- 已经完成了第 2 章的 API 密钥配置(OpenAI 和 Serper 都配好了)
- 项目能正常启动,在
http://localhost:3000能看到界面 - 对 Python 和 FastAPI 有最基础的了解(知道路由和函数怎么写就行)
第一步:找到工具注册的地方
AgentGPT 的后端(platform 目录)里,工具的定义都放在 platform/tools/ 下面。我们先看看现有的工具长什么样:
ls platform/tools/你会看到类似这样的结构:
tools/
├── __init__.py
├── search.py # 搜索工具
├── reasoning.py # 推理工具
└── tool_base.py # 工具基类打开 tool_base.py,你会发现每个工具都是一个类,继承自 BaseTool,只需要实现一个 run 方法。这个 run 方法接收一个字符串参数(用户的输入),返回一个字符串(工具的执行结果)。
第二步:写第一个自定义工具——计算器
我们先写一个最简单的计算器工具。在 platform/tools/ 下新建一个文件 calculator.py:
import ast
import operator
# 安全的运算符映射,只允许数学运算
ALLOWED_OPERATORS = {
ast.Add: operator.add,
ast.Sub: operator.sub,
ast.Mult: operator.mul,
ast.Div: operator.truediv,
ast.Pow: operator.pow,
ast.USub: operator.neg,
}
class CalculatorTool:
name = "calculator"
description = "计算数学表达式,例如 '2 + 3 * 4' 或 '10 / 2'"
def run(self, query: str) -> str:
try:
# 只解析表达式,不执行任意代码
tree = ast.parse(query.strip(), mode='eval')
result = self._eval_node(tree.body)
return f"计算结果: {result}"
except Exception as e:
return f"计算失败: {str(e)}"
def _eval_node(self, node):
if isinstance(node, ast.Constant):
return node.value
elif isinstance(node, ast.BinOp):
left = self._eval_node(node.left)
right = self._eval_node(node.right)
op_type = type(node.op)
if op_type in ALLOWED_OPERATORS:
return ALLOWED_OPERATORS[op_type](left, right)
raise ValueError(f"不支持的运算符: {op_type}")
elif isinstance(node, ast.UnaryOp):
operand = self._eval_node(node.operand)
op_type = type(node.op)
if op_type in ALLOWED_OPERATORS:
return ALLOWED_OPERATORS[op_type](operand)
raise ValueError(f"不支持的一元运算符: {op_type}")
else:
raise ValueError(f"不支持的表达式类型: {type(node)}")这里用了 ast 模块来解析表达式,而不是直接用 eval()——因为 eval() 能执行任意 Python 代码,太危险了。用 ast 解析后,我们只允许数学运算,别的都拒绝。
第三步:把工具注册到 Agent 的工具箱
现在工具写好了,但 Agent 还不知道它的存在。我们需要修改工具加载的地方。
打开 platform/tools/__init__.py,把我们的计算器加进去:
from .search import SearchTool
from .reasoning import ReasoningTool
from .calculator import CalculatorTool # 新增
# 所有可用的工具列表
AVAILABLE_TOOLS = [
SearchTool(),
ReasoningTool(),
CalculatorTool(), # 新增
]
def get_tool_by_name(name: str):
for tool in AVAILABLE_TOOLS:
if tool.name == name:
return tool
return None第四步:让 Agent 能调用新工具
工具注册好了,但 Agent 在决策时怎么知道该用哪个工具?这取决于 Agent 的“思考”过程。在 platform/agent/agent.py 里,Agent 会收到一个任务列表,然后逐个执行。我们需要修改任务执行逻辑,让它能识别并调用我们的计算器。
找到 agent.py 中处理工具调用的部分(大概在 80-120 行之间),修改成类似这样:
from tools import AVAILABLE_TOOLS
def execute_task(task: str, context: dict) -> str:
# 检查任务是否匹配某个工具
for tool in AVAILABLE_TOOLS:
# 简单的关键词匹配,实际项目中可以用更智能的方式
if tool.name in task.lower():
# 提取用户输入(去掉工具名称部分)
query = task.replace(tool.name, "").strip()
return tool.run(query)
# 没有匹配的工具,走默认的 LLM 推理
return llm_reasoning(task, context)注意:这只是一个简化的示例。实际项目中,Agent 会用 LLM 来决定调用哪个工具,而不是简单的关键词匹配。但为了演示,我们先这样写。
第五步:测试你的计算器
重启后端服务:
# 在 platform 目录下
uvicorn main:app --reload现在打开前端,创建一个新的 Agent,在目标里输入类似这样的内容:
计算 1234 * 5678 的结果如果一切正常,Agent 应该会调用计算器工具,返回 计算结果: 7006652。
第六步:添加文件操作工具
计算器太简单了?我们来写一个更有用的——文件读取工具。在 platform/tools/ 下新建 file_reader.py:
import os
from pathlib import Path
class FileReaderTool:
name = "file_reader"
description = "读取指定路径的文件内容,支持 .txt, .md, .csv 格式"
# 只允许读取这些目录下的文件
ALLOWED_PATHS = [
Path("/app/data"),
Path("/app/uploads"),
]
def run(self, query: str) -> str:
filepath = Path(query.strip())
# 安全检查:防止路径遍历攻击
try:
filepath = filepath.resolve()
except Exception:
return "错误:无法解析文件路径"
# 检查文件是否在允许的目录下
allowed = False
for allowed_path in self.ALLOWED_PATHS:
try:
filepath.relative_to(allowed_path)
allowed = True
break
except ValueError:
continue
if not allowed:
return f"错误:只能访问 {', '.join(str(p) for p in self.ALLOWED_PATHS)} 目录下的文件"
# 检查文件是否存在
if not filepath.exists():
return f"错误:文件 {filepath} 不存在"
if not filepath.is_file():
return f"错误:{filepath} 不是一个文件"
# 检查文件大小(限制 1MB)
if filepath.stat().st_size > 1_000_000:
return "错误:文件太大(超过 1MB)"
# 读取文件
try:
content = filepath.read_text(encoding='utf-8')
# 限制返回内容长度
if len(content) > 5000:
content = content[:5000] + "\n\n...(文件过长,仅显示前 5000 字符)"
return f"文件内容:\n{content}"
except Exception as e:
return f"读取文件失败: {str(e)}"这个工具做了几层安全防护:
- 路径遍历防护:用
resolve()解析真实路径,防止../../etc/passwd这种攻击 - 目录白名单:只允许读取特定目录下的文件
- 文件大小限制:防止 Agent 读取超大文件导致内存溢出
别忘了把它加到 __init__.py 的 AVAILABLE_TOOLS 里。
常见报错与排查
报错:ModuleNotFoundError: No module named 'tools.calculator'
检查 __init__.py 里的导入语句是否正确,以及文件路径是否在 Python 的搜索路径中。如果 platform 目录不在 PYTHONPATH 里,可以这样启动:
PYTHONPATH=/path/to/agentgpt/platform uvicorn main:app --reload报错:Agent 一直调用搜索工具,不用计算器
这是因为我们用的关键词匹配太粗糙了。实际项目中,Agent 会用 LLM 分析任务内容,然后决定调用哪个工具。你可以临时把搜索工具从 AVAILABLE_TOOLS 里注释掉,先测试计算器是否正常工作。
报错:计算器返回 计算失败: ...
检查你的表达式格式。计算器只支持基本的四则运算和幂运算,不支持函数调用(比如 sin(30) 就不行)。
小例子串一串
假设你有一个数据分析的需求:每天从某个目录读取当天的销售数据文件,然后计算总销售额。
- 用
file_reader工具读取/app/data/sales_2024-01-15.csv - Agent 分析文件内容,提取出金额列
- 用
calculator工具计算总和
Agent 的任务列表可能长这样:
1. 使用 file_reader 读取 /app/data/sales_2024-01-15.csv
2. 分析文件内容,提取所有金额数值
3. 使用 calculator 计算 1200 + 3400 + 5600 + 7800
4. 返回总销售额当然,实际项目中你可能会写一个专门的 CSV分析工具,一步到位。但通过组合多个基础工具,Agent 已经能完成很多工作了。
注意事项
- 工具的描述很重要:Agent 的 LLM 会根据
description字段来判断什么时候该用这个工具。描述写得越清晰,Agent 调用得越准确。 - 错误处理要友好:工具返回的错误信息应该让 Agent 能理解,而不是抛出一堆技术栈。Agent 看到错误后,可能会尝试其他方式完成任务。
- 性能考虑:如果工具执行时间较长(比如调用外部 API),记得设置超时。Agent 默认的等待时间有限,工具卡住了会影响整个任务流程。
- 安全第一:任何涉及文件系统、网络请求、命令执行的工具,都要做严格的输入验证和权限控制。Agent 的输入来自用户,你永远不知道用户会输入什么。
5. 5. 让 Agent 记住上下文:配置长期记忆与对话历史
每次跟 Agent 聊天,它都像得了失忆症——上一秒刚查完的资料,下一秒就忘得干干净净。这不是你 Agent 笨,而是它默认就没有"记性"这个功能。每次执行任务,它都是从头开始思考,之前聊了什么、查到了什么,一概不记得。
这一章我们就来解决这个问题:给 Agent 装上记忆模块,让它能记住对话历史,在多次交互中保持上下文连贯。配置好之后,你的 Agent 就能像人类一样"记得之前聊到哪了",做调研、写报告这类需要多轮对话的任务会顺畅很多。
前置条件
开始之前,确保你已经:
- 完成了第 1 章的本地环境搭建,AgentGPT 能在
localhost:3000正常运行 - 配置好了 OpenAI API 密钥(第 2 章的内容)
- 数据库已经启动并连接成功(第 1 章 Docker 部署时会自动处理)
如果你还没搞定这些,先回去补课,不然这章的操作跑不起来。
记忆是怎么工作的
AgentGPT 的记忆机制其实不复杂。每次 Agent 执行一步操作,它会把当前的结果和思考过程存到数据库里。下一次 Agent 需要做决策时,它会先去数据库里翻一翻之前干了什么,把这些历史信息拼到 prompt 里一起发给 OpenAI。
说白了就是:每次对话都带上小抄。
这个小抄存在哪?存在 MySQL 数据库里。AgentGPT 用 Prisma ORM 来管理数据库,记忆相关的表叫 Agent 和 AgentMessage。Agent 表存 Agent 的基本信息(名字、目标、状态),AgentMessage 表存每一条对话记录。
第一步:检查数据库表结构
先看看数据库里有没有存记忆的地方。打开你的数据库管理工具(比如 DBeaver 或者直接用命令行),连上 MySQL:
# 如果你用 Docker 启动的,先进容器
docker exec -it agentgpt-db mysql -u root -p
# 输入密码后,切换到 agentgpt 数据库
USE agentgpt;
# 看看有哪些表
SHOW TABLES;你应该能看到 Agent 和 AgentMessage 这两张表。如果看不到,说明你的数据库初始化有问题,回去重新跑一遍 ./setup.sh。
AgentMessage 表的结构大概长这样:
| 字段 | 类型 | 说明 |
|---|---|---|
| id | VARCHAR(36) | 主键 |
| agentId | VARCHAR(36) | 关联到哪个 Agent |
| role | VARCHAR(20) | 'user' 或 'assistant' |
| content | TEXT | 消息内容 |
| createdAt | DATETIME | 创建时间 |
每次 Agent 跟你对话或者自己执行任务,都会往这张表里插一条记录。
第二步:配置记忆长度
默认情况下,AgentGPT 会记住最近 10 条对话。这个数字够用吗?看场景。如果你只是让 Agent 查个天气,10 条绰绰有余;但如果你让它写一份 5000 字的竞品分析报告,10 条可能连一半都聊不完。
修改这个配置很简单,找到项目根目录下的 .env 文件(如果没有就复制 .env.example 创建一个),加上这一行:
AGENT_MEMORY_LENGTH=20这个值设多大合适?我的建议是:
- 简单问答:10-15 条就够了
- 多步骤任务(比如调研、写报告):20-30 条
- 超长对话(比如让 Agent 写一本书):50 条封顶
别设太大,原因有两个:一是 OpenAI API 按 token 收费,历史消息越多,每次请求越贵;二是 prompt 太长会影响模型的理解质量,它会被大量历史信息淹没,反而抓不住重点。
改完 .env 文件后,重启后端服务:
# 如果你用 Docker
docker-compose restart backend
# 如果直接跑
# 先 Ctrl+C 停掉,再重新启动
cd platform
uvicorn main:app --reload第三步:验证记忆是否生效
重启之后,我们来做个测试。打开浏览器访问 http://localhost:3000,创建一个新的 Agent,给它一个需要多轮对话才能完成的目标,比如:
目标:调研三家国内主流 AI 大模型公司(百度、阿里、科大讯飞),对比它们的产品特点
然后开始跟 Agent 对话。先问第一个问题:
"帮我查一下百度的文心一言有哪些核心功能"
Agent 会去搜索并返回结果。这时候别急着问下一个,先看看数据库里有没有存下这条记录:
SELECT * FROM AgentMessage WHERE agentId = '你刚创建的 Agent ID' ORDER BY createdAt;你应该能看到一条 role 为 'user' 的记录(你问的问题)和一条 role 为 'assistant' 的记录(Agent 的回答)。
接着问第二个问题:
"再查一下阿里的通义千问"
Agent 回答之后,再查数据库,应该又多出两条记录。现在问第三个问题:
"对比一下这两家的产品,列出 3 个主要差异"
关键来了:如果记忆生效,Agent 应该能记得刚才查到的百度和阿里的信息,直接给出对比结果。如果它说"我没查到百度的信息"或者重新去搜索,说明记忆没配置好。
第四步:排查常见问题
问题 1:Agent 还是记不住
检查 .env 文件里的 AGENT_MEMORY_LENGTH 有没有被正确读取。可以在后端代码里加个临时日志来验证:
打开 platform/agent/agent.py,找到初始化 Agent 的地方,大概在 30 行左右,加一行打印:
import os
print(f"Memory length: {os.getenv('AGENT_MEMORY_LENGTH', '10')}")重启后端,看控制台输出。如果显示的是默认值 10,说明你的 .env 文件没被加载。检查一下文件路径对不对,是不是在 platform/ 目录下。
问题 2:数据库连接失败
如果 Agent 能正常对话但数据库里没有记录,检查数据库连接配置。打开 platform/.env,确认这几项:
DATABASE_URL=mysql://root:yourpassword@localhost:3306/agentgpt注意端口号,Docker 启动的 MySQL 默认端口是 3306,但如果你本地也装了 MySQL,可能会有冲突。用 docker ps 查看实际映射的端口。
问题 3:记忆太多导致请求超时
如果你设了 50 条记忆,每次请求都会带上这 50 条历史。OpenAI API 有超时限制,如果历史太长可能会超时。这时候要么减少记忆长度,要么在代码里加个 token 数限制:
打开 platform/agent/prompts.py,找到构建 prompt 的地方,大概长这样:
def build_memory_prompt(messages: list) -> str:
total_tokens = 0
memory_parts = []
for msg in reversed(messages):
# 估算每条消息的 token 数(粗略按 4 字符 = 1 token)
msg_tokens = len(msg.content) // 4
if total_tokens + msg_tokens > 2000: # 限制 2000 token
break
memory_parts.append(f"{msg.role}: {msg.content}")
total_tokens += msg_tokens
return "\n".join(reversed(memory_parts))这样即使设了 50 条记忆,实际用到的也不会超过 2000 token,既省钱又不会超时。
第五步:进阶用法——自定义记忆策略
默认的记忆策略是"保留最近 N 条",简单粗暴。但有些场景下你可能想要更智能的记忆方式,比如:
- 摘要记忆:把之前的对话压缩成一段摘要,而不是原样保留
- 关键信息提取:只记住对话中提到的关键数据(比如价格、日期、数字)
- 分层记忆:短期记忆保留最近 10 条,长期记忆只存摘要
这些需要改代码来实现。以摘要记忆为例,在 platform/agent/memory.py 里加一个类:
from langchain.memory import ConversationSummaryMemory
from langchain.llms import OpenAI
class SummaryMemory:
def __init__(self):
self.llm = OpenAI(temperature=0)
self.memory = ConversationSummaryMemory(llm=self.llm, max_token_limit=500)
def add_message(self, role: str, content: str):
self.memory.chat_memory.add_message(
HumanMessage(content=content) if role == "user"
else AIMessage(content=content)
)
def get_summary(self) -> str:
return self.memory.buffer然后在 agent.py 里把原来的记忆逻辑替换成这个。每次 Agent 需要历史信息时,拿到的不是原始对话,而是一段精炼的摘要。这样既保留了上下文,又大幅减少了 token 消耗。
一个小例子串起来
假设你要让 Agent 帮你写一份"新能源汽车市场分析报告"。没有记忆的情况下,你问完"特斯拉 2024 年销量",Agent 回答完就忘了。你再问"对比比亚迪",它得重新去查特斯拉的数据。
配置好记忆后,流程变成:
- 你问:"特斯拉 2024 年全球销量是多少?"
- Agent 搜索并回答:"特斯拉 2024 年全球销量约 180 万辆"
- 这条记录存进数据库
- 你接着问:"对比一下比亚迪同期销量"
- Agent 去数据库翻出上一条记录,知道你已经查过特斯拉了
- Agent 搜索比亚迪数据,然后给出对比:"特斯拉 180 万辆,比亚迪 300 万辆,比亚迪领先约 67%"
整个过程流畅自然,Agent 就像个有记忆的助手,而不是每次都要重新认识你。
注意事项
- 记忆不是永久存储:AgentGPT 默认不会无限期保存所有对话。如果你需要长期存档,得自己写个定时任务把数据库里的历史记录导出
- 隐私问题:所有对话都明文存在数据库里。如果涉及敏感信息,建议加密存储或者定期清理
- 性能影响:记忆越多,每次请求越慢。20 条以内基本无感,超过 50 条会有明显延迟
配置好记忆之后,你的 Agent 就从"金鱼脑"变成了"大象脑"。下一章我们会聊怎么调整 Agent 的行为参数,让它在"太保守"和"太放飞"之间找到平衡点。
6. 6. 调整 Agent 行为参数:温度、最大迭代与停止条件
让 Agent 不再“疯跑”:温度、最大迭代与停止条件
你有没有遇到过这种情况:给 Agent 设定了一个目标,它就开始疯狂执行任务,一个接一个,完全停不下来?或者它输出的内容天马行空,跟你的需求差了十万八千里?这通常不是 Agent 笨,而是你没给它设好“行为边界”。
这一章我们就来调教 Agent 的“脾气”——通过调整温度、最大迭代次数和停止条件,让它在“创造力”和“可控性”之间找到平衡点。这些参数直接决定了 Agent 是像脱缰野马还是训练有素的助手。
前置准备
在开始之前,确保你已经:
- 成功启动了 AgentGPT 的本地环境(第 1 章的内容)
- 配置好了 OpenAI API 密钥(第 2 章)
- 能正常创建和运行一个 Agent
第一步:找到参数配置的“总开关”
AgentGPT 的行为参数主要藏在两个地方:前端创建 Agent 时的表单,和后端的配置文件。我们先从前端入手,因为这是最直观的调整方式。
打开浏览器,访问 http://localhost:3000,点击“创建 Agent”按钮。你会看到一个表单,里面除了 Agent 名称和目标,还有几个滑块和输入框——这些就是我们要调整的参数。
第二步:理解“温度”——Agent 的“脑洞”大小
温度(Temperature)是控制 Agent 输出随机性的参数,取值范围 0 到 2。简单来说:
- 温度越低(接近 0):Agent 越“保守”,倾向于选择最可能的答案,输出稳定但可能缺乏创意
- 温度越高(接近 2):Agent 越“放飞自我”,会尝试更多可能性,输出多样但可能跑偏
在 AgentGPT 的创建表单里,温度默认是 0.5。这个值对大多数任务来说是个不错的折中——既不会太死板,也不会太离谱。
实际测试一下:创建一个 Agent,目标设为“列出 5 个提高工作效率的方法”,温度分别设为 0.1、0.5 和 1.5,看看输出有什么不同。你会发现:
- 温度 0.1:每次运行结果几乎一样,都是“番茄工作法、GTD、时间块”这类经典方法
- 温度 0.5:每次会有一些变化,但核心方法保持稳定
- 温度 1.5:可能冒出“用冥想代替工作”“养一只猫来减压”这种奇怪建议
什么时候调高温度? 当你需要 Agent 做头脑风暴、创意写作,或者探索多种解决方案时。比如让 Agent 设计营销文案,温度设到 0.8-1.0 效果更好。
什么时候调低温度? 当你需要 Agent 执行精确任务,比如提取数据、生成代码、回答事实性问题。这种情况下,温度设到 0.1-0.3 更靠谱。
第三步:设置“最大迭代”——给 Agent 戴上缰绳
最大迭代(Max Iterations)是 AgentGPT 里最容易被忽略但最重要的参数。它控制 Agent 最多能执行多少轮“思考→执行→反馈”的循环。
默认值是 5,这意味着 Agent 最多会执行 5 个任务。如果目标简单,5 次可能够了;但如果目标复杂,比如“调研竞品并生成报告”,5 次可能只够查几个网页,根本写不完报告。
怎么设置合适的值?
- 简单任务(查一个数据、翻译一句话):1-3 次
- 中等任务(写一篇短文、做简单分析):5-10 次
- 复杂任务(深度调研、多步骤流程):10-25 次
- 非常复杂(需要反复验证和迭代):25-50 次
注意:每次迭代都会调用 OpenAI API,这意味着迭代次数越多,花费越高。设置 50 次迭代可能让你的账单瞬间飙升。
实际测试:创建一个 Agent,目标设为“调研当前最流行的 3 个前端框架,并比较它们的优缺点”,最大迭代设为 3。你会发现 Agent 可能只查了 1-2 个框架就停了,因为 3 次迭代不够它完成所有步骤。改成 10 次再试,效果会好很多。
第四步:配置“停止条件”——让 Agent 知道什么时候收手
停止条件(Stop Conditions)是 AgentGPT 里比较高级的功能,它告诉 Agent:“当你遇到这些情况时,就停下来,别继续了。”
在 AgentGPT 的配置中,停止条件通常通过两种方式实现:
- 关键词停止:当 Agent 的输出包含特定关键词时停止。比如设置“完成”“结束”“报告已生成”作为停止词。
- 目标达成判断:Agent 会自我评估是否已经达成了初始目标,如果判断为“是”,就主动停止。
实际操作:在创建 Agent 的表单里,找到“停止条件”或“Stop Conditions”输入框(如果前端版本没有这个选项,可以在后端配置文件中添加)。输入几个关键词,用逗号分隔:
完成, 结束, 报告已生成, 目标已达成这样当 Agent 的输出中出现这些词时,它就会自动停止,不会继续无意义地执行下去。
小技巧:把停止条件和最大迭代结合起来用。比如设置最大迭代 20 次,同时设置停止条件为“完成”。这样 Agent 要么在 20 次内完成任务并主动停止,要么在 20 次后强制停止——双重保险。
第五步:在后端配置中微调参数
前端表单只能调整部分参数,如果你想更精细地控制,需要直接修改后端代码。
找到 platform/ 目录下的 Agent 配置文件,通常是 agent.py 或 agent_controller.py。打开它,你会看到类似这样的代码:
# 这是 Agent 的核心配置,不要直接复制,根据你的版本调整
class AgentConfig:
temperature: float = 0.5
max_iterations: int = 5
stop_conditions: List[str] = []你可以在这里修改默认值,这样所有新创建的 Agent 都会使用你设定的默认参数:
class AgentConfig:
temperature: float = 0.3 # 更保守一点
max_iterations: int = 10 # 默认给更多迭代次数
stop_conditions: List[str] = ["完成", "结束", "目标已达成"]修改后重启后端服务(通常是 docker-compose restart 或直接重启容器),新参数就会生效。
常见问题与排查
问题 1:Agent 一直循环执行同一个任务
- 原因:温度太高导致 Agent 无法做出稳定决策,或者停止条件没设置好
- 解决:降低温度到 0.3 以下,同时设置明确的停止条件
问题 2:Agent 执行一两次就停了,任务没完成
- 原因:最大迭代次数设得太低
- 解决:增加最大迭代次数,从 10 开始试
问题 3:Agent 输出内容完全跑题
- 原因:温度太高,或者目标描述不够清晰
- 解决:降低温度到 0.2-0.3,同时优化目标描述,让它更具体
问题 4:API 调用费用飙升
- 原因:最大迭代次数设得过高,或者 Agent 陷入了死循环
- 解决:设置合理的最大迭代次数(一般不超过 25),同时配置停止条件作为保险
一个完整的例子:自动调研竞品
让我们把这些参数用在一个真实场景里。假设你要创建一个 Agent,让它自动调研某个竞品并生成报告:
- Agent 名称:竞品调研助手
- 目标:调研 Notion 这个产品的功能、定价、用户评价,并生成一份 500 字左右的对比报告
- 温度:0.4(需要一定的创意来组织报告,但不能太放飞)
- 最大迭代:15(调研需要查多个网页、整理信息、写报告,5 次不够)
- 停止条件:报告已生成, 调研完成
运行这个 Agent,你会看到它先搜索 Notion 的功能介绍,然后查定价信息,接着找用户评价,最后整理成报告。当它输出“报告已生成”时,自动停止——完美收工。
参数调优的黄金法则
最后分享几个经验法则,帮你快速找到合适的参数组合:
- 简单任务:温度 0.2 + 迭代 3 + 关键词停止
- 创意任务:温度 0.8 + 迭代 10 + 目标达成停止
- 复杂分析:温度 0.3 + 迭代 20 + 双重停止条件
- 探索性任务:温度 1.0 + 迭代 15 + 无停止条件(但要监控)
记住,没有“万能参数”,每个任务都需要微调。多试几次,观察 Agent 的行为,慢慢你就能凭直觉判断该用什么参数了。
7. 7. 多 Agent 协作:同时运行多个 Agent 并共享结果
你手头已经跑起来了一个 AgentGPT 实例,能帮你想一些调研任务了。但现实世界里的活儿,往往不是单打独斗能搞定的。比如你要分析一个市场,得同时查竞品、搜行业报告、扒用户评价——一个 Agent 挨个做,慢不说,还容易搞混上下文。要是能派三个 Agent 同时开工,各干各的,最后把结果汇总给你,那效率就完全不一样了。
这一章我们就来干这件事:让多个 Agent 同时跑起来,并且让它们能把结果写到同一个地方,方便你最后收网。
前置条件
- 你已经完成了第 1 章到第 3 章的配置,AgentGPT 能在
http://localhost:3000正常启动和运行。 - 你有一个可用的 OpenAI API Key 和 Serper API Key(用于搜索工具)。
- 你大概知道 AgentGPT 的界面长什么样:输入目标,点“Deploy Agent”,然后看它一步步执行。
第一步:理解 AgentGPT 的“单线程”限制
默认情况下,AgentGPT 一次只能运行一个 Agent。你点“Deploy Agent”之后,界面会锁定,直到这个 Agent 完成或你手动停止。这不是 bug,是设计——因为一个 Agent 的思考链是连续的,它需要记住自己上一步干了什么,才能决定下一步。
但我们要的是“同时跑多个”,所以得换个思路:不依赖界面上的“单 Agent”模式,而是通过后端 API 直接创建多个 Agent 实例,让它们各自独立运行。
第二步:找到后端 API 入口
AgentGPT 的后端(FastAPI)暴露了一个创建 Agent 的接口。在项目目录 platform 下,找到 agent.py 或类似的文件(具体路径可能是 platform/routers/agent.py)。里面有一个 POST 端点,通常是 /agent/create 或 /agent/run。
我们不需要改代码,直接用 curl 或 Postman 调用它。先确认你的后端在运行(默认端口 8000)。
打开终端,试一下这个命令(替换 YOUR_OPENAI_KEY 和 YOUR_SERPER_KEY):
curl -X POST http://localhost:8000/agent/create \
-H "Content-Type: application/json" \
-d '{
"name": "竞品分析Agent",
"goal": "搜索并列出特斯拉Cybertruck的主要竞品,每个竞品给出3个关键特点",
"api_key": "YOUR_OPENAI_KEY",
"serper_api_key": "YOUR_SERPER_KEY",
"max_iterations": 5
}'预期结果:你会收到一个 JSON 响应,里面包含一个 id 字段,比如 "id": "abc123"。这个 ID 就是你这个 Agent 实例的唯一标识。如果报错 422,检查 JSON 格式和字段名是否正确(字段名可能叫 name、goal、openai_api_key 等,以实际代码为准,这里用的是常见命名)。
第三步:同时启动多个 Agent
现在,我们开三个终端窗口(或者用 & 后台运行),同时发三个请求,每个 Agent 干不同的活。
终端 1:竞品分析 Agent
curl -X POST http://localhost:8000/agent/create \
-H "Content-Type: application/json" \
-d '{
"name": "竞品分析Agent",
"goal": "搜索并列出特斯拉Cybertruck的主要竞品,每个竞品给出3个关键特点",
"api_key": "YOUR_OPENAI_KEY",
"serper_api_key": "YOUR_SERPER_KEY",
"max_iterations": 5
}'终端 2:行业报告 Agent
curl -X POST http://localhost:8000/agent/create \
-H "Content-Type: application/json" \
-d '{
"name": "行业报告Agent",
"goal": "搜索2024年电动皮卡市场规模和增长趋势,总结成3个要点",
"api_key": "YOUR_OPENAI_KEY",
"serper_api_key": "YOUR_SERPER_KEY",
"max_iterations": 5
}'终端 3:用户评价 Agent
curl -X POST http://localhost:8000/agent/create \
-H "Content-Type: application/json" \
-d '{
"name": "用户评价Agent",
"goal": "搜索Cybertruck早期用户的正面和负面评价,各列出2条",
"api_key": "YOUR_OPENAI_KEY",
"serper_api_key": "YOUR_SERPER_KEY",
"max_iterations": 5
}'预期结果:三个请求几乎同时返回,每个都给你一个不同的 Agent ID。现在,这三个 Agent 正在后端并行执行。你可以打开浏览器,访问 http://localhost:3000,但界面上可能只显示一个 Agent 的状态(因为前端默认只跟踪最近创建的那个)。别慌,它们确实在跑。
第四步:查看每个 Agent 的执行结果
AgentGPT 的后端会把每个 Agent 的执行步骤和最终结果存到数据库里。我们可以通过另一个 API 来查询。
假设你有一个 Agent ID 是 abc123,执行这个命令:
curl http://localhost:8000/agent/abc123预期结果:你会看到这个 Agent 的完整执行记录,包括它想了什么、调用了什么工具、得到了什么结果。如果 Agent 还在跑,你会看到 status: "running";如果完成了,就是 status: "completed",并且 result 字段里会有最终输出。
你可以对三个 ID 分别执行这个查询,等它们都变成 completed 后,把结果手动汇总。但这样太累了,我们得让它们自动把结果写到同一个地方。
第五步:让 Agent 共享结果——用文件作为“黑板”
最简单的方式:让每个 Agent 在完成时,把结果追加到一个共享的文本文件里。AgentGPT 的 Agent 可以执行 Python 代码(如果配置了代码执行工具)。我们给每个 Agent 的目标里加上一句:“最后,把结果写入 /tmp/shared_results.txt”。
修改一下请求体,比如竞品分析 Agent:
{
"name": "竞品分析Agent",
"goal": "搜索并列出特斯拉Cybertruck的主要竞品,每个竞品给出3个关键特点。最后,把结果写入 /tmp/shared_results.txt,格式为:'竞品分析: [你的结果]'",
"api_key": "YOUR_OPENAI_KEY",
"serper_api_key": "YOUR_SERPER_KEY",
"max_iterations": 5
}其他两个 Agent 也类似,但写入时用不同的前缀(比如“行业报告:”和“用户评价:”)。
注意:这要求 Agent 有文件写入权限。在 Docker 环境下,/tmp 通常是可写的。如果你用的是 Docker Compose 部署,确保 platform 容器能访问宿主机的 /tmp 目录(可以在 docker-compose.yml 里加 volume 映射)。
预期结果:等三个 Agent 都跑完后,登录到你的服务器或本地机器,执行:
cat /tmp/shared_results.txt你会看到类似这样的输出:
竞品分析: 1. Rivian R1T - 特点:... 2. Ford F-150 Lightning - 特点:... 3. GMC Hummer EV - 特点:...
行业报告: 1. 2024年电动皮卡市场规模预计达... 2. 年增长率约... 3. 主要驱动力是...
用户评价: 正面:... 负面:...完美!三个 Agent 的结果已经合并到一个文件里了。
常见报错与排查
报错:curl: (7) Failed to connect to localhost port 8000: Connection refused
后端没启动。确保你运行了 docker-compose up 或者手动启动了 FastAPI 服务(cd platform && uvicorn main:app --reload)。
报错:{"detail":"Not authenticated"}
AgentGPT 默认有认证。你需要在请求头里加上一个有效的 token。最简单的方法:在浏览器里登录 AgentGPT,打开开发者工具(F12),在 Application -> Local Storage 里找到类似 next-auth.session-token 的值,把它作为 Authorization: Bearer <token> 加到 curl 命令里。
curl -X POST http://localhost:8000/agent/create \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_SESSION_TOKEN" \
-d '{...}'报错:Agent 一直卡在“思考”阶段,不执行工具
检查 API Key 是否有效,以及 Serper API 的配额是否用完。可以在后端日志里看到具体的错误信息(docker logs <container_name>)。
实用技巧
- 控制并发数量:不要一次启动几十个 Agent,OpenAI API 有速率限制。建议同时不超过 5 个,除非你用了多个 API Key。
- 给 Agent 起有意义的名字:这样在数据库里查记录时,一眼就能看出哪个是干什么的。
- 用脚本自动化:把上面的 curl 命令写成一个 shell 脚本,循环启动多个 Agent,然后轮询检查状态,最后自动汇总结果。这样你点一下就能跑完整个流程。
小例子串起来
假设你要做一个“智能周报系统”,需要同时收集三个维度的信息:团队进度、行业新闻、竞品动态。你可以写一个简单的 Python 脚本,调用 AgentGPT 的 API 启动三个 Agent,等它们都完成后,读取共享文件,然后用一个模板生成周报。整个过程不到 10 行代码,但背后是三个 AI 在并行工作。
多 Agent 协作的核心思路就是:各自独立执行,共享结果存储。你不需要改 AgentGPT 的代码,只需要用好它的 API,再加一点“文件黑板”的创意。下一章我们会聊怎么在前端定制一个页面,让你能直观地看到所有 Agent 的运行状态,而不是靠 curl 去查。
8. 8. 前端定制:修改 UI 主题与添加自定义页面
改颜色、换字体、加页面:让 AgentGPT 长成你想要的样子
AgentGPT 默认的深色主题挺酷的,但如果你想让界面更符合自己的品牌色、或者想加一个“关于我们”页面、甚至把整个 UI 改成浅色模式,完全不用动底层逻辑——前端用的是 Next.js + TailwindCSS,改起来比想象中简单得多。
这一章我们就干两件事:先改主题(颜色、字体、间距这些全局样式),再添加一个自定义页面(比如一个“使用说明”页)。做完之后,你的 AgentGPT 看起来就不像“别人的项目”了。
前置条件
- 已经跑通了本地开发环境(第 1 章的内容)
- 对 React 组件和 TailwindCSS 有最基础的了解(知道 className 怎么写就行)
- 项目根目录下的
next文件夹就是前端代码所在
第一步:找到主题配置文件
TailwindCSS 的主题配置集中在 next/tailwind.config.js 里。打开它,你会看到类似这样的结构:
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./src/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}theme.extend 就是我们的游乐场。所有自定义颜色、字体、间距都写在这里,不会覆盖 Tailwind 默认值,只是叠加。
第二步:改颜色——把主色调换成你的品牌色
假设你想把主色调从默认的蓝色(blue-600)换成一种更温暖的橙色。先找到项目里用了 blue-600 的地方——别慌,不用一个个文件翻,Tailwind 的配置可以一次性搞定。
在 tailwind.config.js 的 theme.extend 里加上 colors:
theme: {
extend: {
colors: {
primary: {
50: '#fff7ed',
100: '#ffedd5',
200: '#fed7aa',
300: '#fdba74',
400: '#fb923c',
500: '#f97316',
600: '#ea580c',
700: '#c2410c',
800: '#9a3412',
900: '#7c2d12',
},
},
},
},保存之后,你就可以在任意组件里用 bg-primary-600、text-primary-500 这样的类名了。但问题是,项目里原来写死的 blue-600 不会自动变成 primary-600——你需要全局替换。别手动改,用编辑器的“在文件中查找替换”功能,把 blue-600 换成 primary-600,blue-500 换成 primary-500,以此类推。
预期结果:刷新页面后,按钮、链接、高亮文字都变成了橙色系。
第三步:改字体——换一个更现代的字体
默认字体是系统无衬线字体(sans)。如果你想换成 Inter 或者 Noto Sans SC(对中文更友好),需要两步。
先安装字体包。在 next 目录下运行:
npm install @fontsource/inter然后在 next/src/pages/_app.tsx 里引入:
import '@fontsource/inter/400.css';
import '@fontsource/inter/600.css';
import '@fontsource/inter/700.css';最后回到 tailwind.config.js,在 theme.extend 里加上 fontFamily:
fontFamily: {
sans: ['Inter', 'system-ui', 'sans-serif'],
},预期结果:所有文本的字体都变成了 Inter,标题更清晰,阅读体验提升明显。
第四步:添加一个自定义页面——比如“使用说明”
现在我们要加一个 /guide 页面,里面放一些 AgentGPT 的使用技巧。Next.js 的页面路由在 next/src/pages 下,每个 .tsx 文件对应一个路由。
新建 next/src/pages/guide.tsx:
import type { NextPage } from 'next';
import Head from 'next/head';
import Link from 'next/link';
const Guide: NextPage = () => {
return (
<>
<Head>
<title>使用说明 - AgentGPT</title>
</Head>
<div className="min-h-screen bg-gray-900 text-white p-8">
<div className="max-w-3xl mx-auto">
<Link href="/" className="text-primary-500 hover:underline mb-4 block">
← 返回首页
</Link>
<h1 className="text-3xl font-bold mb-6">AgentGPT 使用说明</h1>
<section className="space-y-4">
<div className="bg-gray-800 rounded-lg p-6">
<h2 className="text-xl font-semibold mb-2">1. 创建你的第一个 Agent</h2>
<p className="text-gray-300">
在首页输入 Agent 名称和目标,点击部署即可。Agent 会自动拆解任务并执行。
</p>
</div>
<div className="bg-gray-800 rounded-lg p-6">
<h2 className="text-xl font-semibold mb-2">2. 配置 API 密钥</h2>
<p className="text-gray-300">
前往设置页面填入 OpenAI 和 Serper 的 API 密钥,Agent 才能联网和调用 LLM。
</p>
</div>
<div className="bg-gray-800 rounded-lg p-6">
<h2 className="text-xl font-semibold mb-2">3. 查看执行日志</h2>
<p className="text-gray-300">
每个 Agent 的运行过程都会实时展示在右侧面板,你可以随时停止或重新运行。
</p>
</div>
</section>
</div>
</div>
</>
);
};
export default Guide;保存后,访问 http://localhost:3000/guide,就能看到这个新页面了。
预期结果:浏览器打开 /guide 路径,显示一个带返回链接的说明页面,样式和主站保持一致(因为用了同样的 Tailwind 类)。
第五步:在导航栏里加一个入口
光有页面没人知道也不行。找到导航栏组件,通常在 next/src/components/Navbar.tsx 或类似位置。在里面加一个链接:
<Link href="/guide" className="text-gray-300 hover:text-white transition-colors">
使用说明
</Link>位置可以放在“设置”按钮旁边。保存后刷新,导航栏就多了一个入口。
常见问题与排查
改了颜色但页面没变化?
检查 tailwind.config.js 的路径是否正确——content 数组里要包含所有用到了 Tailwind 类名的文件路径。如果只配了 ./src/**/*.{js,ts,jsx,tsx},但你的组件在别的地方,就不会生效。
自定义页面样式和主站不一致?
确保新页面也引入了全局样式文件。在 next/src/pages/_app.tsx 里通常已经 import 了 ../styles/globals.css,新页面只要用了 Tailwind 类名就会自动继承。
字体加载慢?
@fontsource 的字体是自托管的,不会依赖 Google Fonts 的 CDN,速度很快。如果还是慢,检查是否只引入了需要的字重(比如只引入 400、600、700,不要全量引入)。
一个真实场景串起来
假设你给公司内部部署了一个 AgentGPT,用来自动生成周报。你可以把主色调改成公司品牌色(比如深蓝色 #1e3a5f),字体改成更商务的 Inter,然后加一个 /guide 页面,里面写清楚“如何配置周报模板”“如何设置定时运行”等内部文档。这样团队成员打开系统就能直接看到指引,不用再翻文档了。
9. 9. 后端扩展:添加自定义 API 端点与数据库模型
给 AgentGPT 加个"记分牌":自定义 API 端点与数据库模型
假设你跑了一段时间的 AgentGPT,发现每次 Agent 完成任务后,你想知道它花了多少步、调用了多少次工具、最终结果是什么——但这些信息散落在日志里,没有一个专门的接口能查。更麻烦的是,你想给每个 Agent 打标签分类,比如"市场调研组""代码生成组",现有的数据库表里根本没这个字段。
这时候你就得自己动手了:加一个新的数据库模型来存 Agent 的执行记录,再写一个 API 端点让前端能查这些数据。这一章我们就干这件事。
前置准备
- 你已经成功启动了 AgentGPT 的本地开发环境(第 1 章的内容)
- 你熟悉项目的基本目录结构,特别是
platform/和prisma/这两个文件夹 - 你装了 Prisma CLI(通常跟着项目一起装好了,没装的话
npm install -g prisma)
第一步:设计你要存什么
先想清楚需求。我们要存的是 Agent 每次执行任务的"快照":
- agent_id:哪个 Agent 干的
- goal:它当时的目标是什么
- steps_taken:它执行了多少步
- tools_used:用了哪些工具(比如搜索、计算)
- result_summary:最终结果的摘要
- created_at:什么时候完成的
这些信息跟 AgentGPT 现有的 Agent 模型是分开的,所以我们新建一个表,叫 AgentRun。
第二步:在 Prisma 里加模型
AgentGPT 的数据库模型定义在 prisma/schema.prisma 里。打开这个文件,在现有的模型后面加上:
model AgentRun {
id String @id @default(cuid())
agentId String
goal String
stepsTaken Int @default(0)
toolsUsed String @default("")
resultSummary String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
agent Agent @relation(fields: [agentId], references: [id])
}注意这里 agentId 关联到了已有的 Agent 模型——这样你就能通过 Agent 查到它所有的执行记录,反过来也能从执行记录找到对应的 Agent。
加完之后,运行迁移命令:
npx prisma migrate dev --name add_agent_run如果一切顺利,你会看到类似这样的输出:
Your database is now in sync with your schema.
✔ Generated Prisma Client (4.x.x) to ./node_modules/@prisma/client这时候去数据库里看一眼,应该多了一张 AgentRun 表。
第三步:写 API 端点
AgentGPT 的后端用的是 FastAPI,路由文件在 platform/routers/ 下面。我们新建一个文件 platform/routers/agent_runs.py:
from fastapi import APIRouter, Depends, HTTPException
from sqlmodel import Session, select
from typing import List
from ..database import get_session
from ..models import AgentRun, AgentRunCreate, AgentRunPublic
router = APIRouter(prefix="/api/agent-runs", tags=["agent-runs"])
@router.get("/", response_model=List[AgentRunPublic])
def list_agent_runs(
agent_id: str = None,
limit: int = 10,
session: Session = Depends(get_session)
):
query = select(AgentRun)
if agent_id:
query = query.where(AgentRun.agentId == agent_id)
query = query.order_by(AgentRun.createdAt.desc()).limit(limit)
results = session.exec(query).all()
return results
@router.post("/", response_model=AgentRunPublic)
def create_agent_run(
run_data: AgentRunCreate,
session: Session = Depends(get_session)
):
run = AgentRun.from_orm(run_data)
session.add(run)
session.commit()
session.refresh(run)
return run等等,这里用了 AgentRunCreate 和 AgentRunPublic,我们还没定义它们。在 platform/models.py 里加上:
from sqlmodel import SQLModel, Field
from datetime import datetime
from typing import Optional
class AgentRunBase(SQLModel):
agentId: str
goal: str
stepsTaken: int = 0
toolsUsed: str = ""
resultSummary: Optional[str] = None
class AgentRunCreate(AgentRunBase):
pass
class AgentRunPublic(AgentRunBase):
id: str
createdAt: datetime
updatedAt: datetime最后,别忘了在 platform/main.py 里注册这个路由:
from .routers import agent_runs
app.include_router(agent_runs.router)重启后端服务(docker-compose restart backend 或者直接 Ctrl+C 再 docker-compose up),然后试试看:
curl http://localhost:8000/api/agent-runs/应该返回一个空数组 []。再用 POST 创建一条记录:
curl -X POST http://localhost:8000/api/agent-runs/ \
-H "Content-Type: application/json" \
-d '{"agentId": "你的agent_id", "goal": "调研竞品", "stepsTaken": 5, "toolsUsed": "search,web"}'返回的 JSON 里应该包含你刚提交的数据,外加 id、createdAt 这些自动生成的字段。
第四步:让 Agent 执行完后自动记录
光有 API 端点还不够,得让 Agent 在完成任务后自动调用这个接口。找到 Agent 执行完成后的回调位置——通常在 platform/services/agent.py 或类似文件里,有个 execute_agent 函数,执行完所有步骤后会返回结果。在那个位置加上:
from ..routers.agent_runs import create_agent_run
from ..database import get_session
# 在 agent 执行完所有步骤后
async def record_agent_run(agent, result):
session = next(get_session())
run_data = AgentRunCreate(
agentId=agent.id,
goal=agent.goal,
stepsTaken=len(agent.executed_tasks),
toolsUsed=",".join(agent.used_tools),
resultSummary=result[:500] # 只存前500字符,防止太长
)
create_agent_run(run_data, session)这里有个小坑:get_session 是个生成器,你得用 next() 来拿 session 实例。如果你直接传进去,FastAPI 的依赖注入系统会报错。
常见报错与排查
"Table 'AgentRun' doesn't exist"
迁移没跑成功。检查一下 prisma/schema.prisma 的语法,然后重新跑 npx prisma migrate dev。
"Column 'toolsUsed' cannot be null"
你在 POST 请求里没传 toolsUsed 字段,但模型里没设默认值。要么在请求里加上,要么在模型定义里给个默认空字符串。
"AttributeError: 'AgentRun' object has no attribute 'from_orm'"
你用的 SQLModel 版本可能比较老。换成手动赋值:run = AgentRun(**run_data.dict())。
小技巧:给前端加个页面
后端搞定了,前端也得跟上。在 next/pages/ 下新建一个 agent-runs.tsx,用 fetch 调用 /api/agent-runs/,把数据渲染成一个表格。这样你就能在浏览器里直接看到所有 Agent 的执行记录了。
一个完整的例子
假设你有个 Agent 叫"市场小助手",目标是"分析三家竞品的定价策略"。它执行了 8 步,用了搜索和网页抓取工具,最终结果是一段总结。执行完后,数据库里会多一条记录:
{
"id": "clx...",
"agentId": "cm5...",
"goal": "分析三家竞品的定价策略",
"stepsTaken": 8,
"toolsUsed": "search,web",
"resultSummary": "竞品A定价$19/月,竞品B$29/月,竞品C$9/月...",
"createdAt": "2024-03-15T10:30:00Z",
"updatedAt": "2024-03-15T10:30:00Z"
}下次你想复盘这个 Agent 的表现,直接 GET 这个接口就能拿到所有历史数据,不用再去翻日志了。
10. 10. 性能调优:缓存、并发控制与数据库优化
你的 Agent 跑得慢?先别急着怪 OpenAI
你有没有遇到过这种情况:Agent 明明设定好了目标,结果等了好几分钟才返回第一个结果,中间还时不时卡住不动。更让人抓狂的是,同样的任务,第二次跑反而快了不少——但第三次又慢了。
这不是玄学。AgentGPT 的性能瓶颈通常不在 OpenAI 的 API 响应速度上(虽然那也确实不慢),而是出在三个地方:重复的数据库查询、串行执行的任务队列、以及没必要的全表扫描。这一章我们就来逐个击破。
前置条件
- 你已经成功运行过 AgentGPT(本地或服务器都行)
- 数据库里有至少几十条 Agent 运行记录(没数据的话,跑几个测试任务就行)
- 能访问后端代码(
platform/目录)
第一步:给数据库查询加缓存——别反复读同一份数据
先看一个典型场景:每次 Agent 执行任务时,都要从数据库里查当前 Agent 的配置信息。如果一次任务循环 10 步,那同样的查询就跑了 10 次。这就像你每次去厨房拿杯子都重新走一遍从卧室到厨房的路——明明可以一次拿完。
AgentGPT 后端用的是 FastAPI + SQLModel,缓存最直接的办法是用 functools.lru_cache 配合 Redis。但为了快速见效,我们先从最简单的内存缓存开始。
打开 platform/core/agent.py,找到加载 Agent 配置的地方(大概是 load_agent_config 函数),加上缓存:
from functools import lru_cache
@lru_cache(maxsize=128)
def get_cached_agent_config(agent_id: str) -> dict:
# 原来的数据库查询逻辑
agent = session.query(Agent).filter(Agent.id == agent_id).first()
return agent.to_dict() if agent else None预期结果:同一个 agent_id 在缓存有效期内只查一次数据库。后续调用直接从内存返回。
注意:lru_cache 默认不清除,如果 Agent 配置在运行中被修改,缓存会返回旧数据。生产环境建议用 Redis + TTL(过期时间),后面会讲。
第二步:用 Redis 做分布式缓存——多实例共享
如果你的 AgentGPT 部署了多个后端实例(比如用 Docker Compose 起了两个 platform 容器),内存缓存就失效了——每个实例有自己的缓存,数据不一致。
这时候需要 Redis。AgentGPT 的 docker-compose.yml 里其实已经预留了 Redis 服务,只是默认没启用。我们把它加上:
# docker-compose.yml 的 services 部分
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redis_data:/data然后在后端代码里连接 Redis。打开 platform/core/dependencies.py,添加:
import redis.asyncio as redis
redis_client = redis.from_url("redis://redis:6379/0")
async def get_cached(key: str):
return await redis_client.get(key)
async def set_cached(key: str, value: str, ttl: int = 300):
await redis_client.setex(key, ttl, value)预期结果:多个后端实例共享同一个缓存,配置数据在 5 分钟内只查一次数据库。
常见报错:如果 Redis 连不上,检查 docker-compose.yml 里 platform 服务的 depends_on 有没有加 redis,以及网络配置是否正确。
第三步:并发控制——别让 Agent 同时干太多事
AgentGPT 默认是串行执行任务的:Agent 想一个任务 -> 执行 -> 看结果 -> 再想下一个。这很安全,但也很慢。
一个常见的优化是让 Agent 在等待 OpenAI 返回结果时,先处理其他不依赖这个结果的任务。比如:Agent 要搜索三个关键词,完全可以同时搜,不用等第一个搜完再搜第二个。
修改 platform/core/agent.py 里的任务执行逻辑,用 asyncio.gather 并发执行独立任务:
import asyncio
async def execute_tasks_concurrently(tasks: list):
# 只并发执行互不依赖的任务
independent_tasks = [task for task in tasks if not task.depends_on]
results = await asyncio.gather(
*[execute_single_task(task) for task in independent_tasks],
return_exceptions=True
)
return results预期结果:原本需要 30 秒的 3 个独立搜索任务,现在可能 10 秒就完成了。
注意:并发数不是越大越好。OpenAI API 有速率限制(Rate Limit),并发太多会被 429 拒绝。建议加个信号量控制最大并发数:
semaphore = asyncio.Semaphore(3) # 最多同时 3 个请求
async def execute_single_task(task):
async with semaphore:
# 原来的执行逻辑
pass第四步:数据库优化——索引和查询瘦身
AgentGPT 用 Prisma(前端)和 SQLModel(后端)操作 MySQL/PlanetScale。最常出问题的查询是:按 Agent ID 查所有执行记录。
打开 platform/models/agent_execution.py,看看 get_executions_by_agent 函数。如果它没有索引,每次都要全表扫描。
加索引:
# 在 AgentExecution 模型定义里
class AgentExecution(SQLModel, table=True):
__tablename__ = "agent_executions"
id: int = Field(primary_key=True)
agent_id: str = Field(index=True) # 加索引!
created_at: datetime = Field(default_factory=datetime.utcnow)
status: str = Field(default="pending")然后运行数据库迁移:
# 如果你用 Alembic
alembic revision --autogenerate -m "add index on agent_id"
alembic upgrade head预期结果:按 Agent ID 查询执行记录的速度提升 10-100 倍(取决于数据量)。
实用技巧:如果查询经常按 created_at 排序,可以建复合索引:
agent_id: str = Field(index=True)
# 在迁移脚本里手动加复合索引
# CREATE INDEX idx_agent_created ON agent_executions (agent_id, created_at DESC);第五步:用一个小例子验证效果
假设你有一个 Agent,任务是“调研三家竞品公司的最新动态”。它需要:
- 搜索公司 A(3 个关键词)
- 搜索公司 B(3 个关键词)
- 搜索公司 C(3 个关键词)
优化前:9 个搜索串行执行,每个等 2-3 秒,加上数据库查询,总共 30 秒以上。
优化后:
- 缓存:Agent 配置只查一次,后续 5 分钟内复用
- 并发:9 个搜索同时发起(受信号量限制,实际同时 3 个)
- 索引:查询执行记录毫秒级返回
总时间降到 10-12 秒,而且随着任务数增加,优化效果更明显。
常见问题排查
Q:加了缓存后,Agent 配置改了但没生效?
A:lru_cache 默认不清除。临时方案是重启后端,或者改成 Redis + TTL。生产环境建议用 Redis,设置 60 秒过期。
Q:并发执行后,OpenAI 返回 429 Too Many Requests? A:降低信号量的最大值,从 3 降到 2 或 1。也可以加指数退避重试:
import backoff
@backoff.on_exception(backoff.expo, openai.error.RateLimitError, max_tries=5)
async def call_openai(prompt):
# 原来的 API 调用
passQ:加了索引后查询反而变慢了?
A:检查是不是建了太多索引。每个索引都会拖慢写入速度。只给最常用的查询字段加索引,比如 agent_id 和 created_at。
Q:Redis 内存会不会爆?
A:设置合理的 TTL(过期时间),比如 300 秒。如果数据量大,还可以用 maxmemory-policy allkeys-lru 让 Redis 自动淘汰不常用的缓存。
11. 11. 部署到生产:使用 Docker Compose 与反向代理
从本地跑通到线上可用:Docker Compose 部署 + Nginx 反向代理
如果你已经跟着前面几章把 AgentGPT 在本地跑起来了,现在应该能在 localhost:3000 上看到那个漂亮的聊天界面,并且能正常调用 Agent。但问题来了——你总不能把笔记本搬到客户现场,或者让同事都连你电脑的 localhost 吧?
这一章要解决的就是:怎么让 AgentGPT 变成一个真正可访问的线上服务。我们会用 Docker Compose 把整个项目打包成标准化的容器,再用 Nginx 做反向代理,配上 HTTPS 和域名。这样你部署到任何 VPS 或者云服务器上,别人就能通过 https://你的域名.com 来用你的 Agent 了。
前置条件
开始之前,确认你已经:
- 在本机成功运行过 AgentGPT(第 1 章的内容)
- 安装了 Docker 和 Docker Compose(版本 2.x 以上)
- 有一台云服务器(或者能跑 Docker 的 Linux 机器)
- 有一个域名(比如
myagent.example.com),并且 DNS 已经指向你的服务器 IP - 准备好 OpenAI API Key 和 Serper API Key(第 2 章的内容)
第一步:理解项目自带的 Docker 配置
AgentGPT 的根目录下有个 docker-compose.yml 文件,打开看看:
version: '3.9'
services:
backend:
build: ./platform
ports:
- "8000:8000"
env_file:
- .env
depends_on:
- db
frontend:
build: ./next
ports:
- "3000:3000"
env_file:
- .env
depends_on:
- backend
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_PASSWORD}
MYSQL_DATABASE: agentgpt
volumes:
- mysql_data:/var/lib/mysql
volumes:
mysql_data:这个配置定义了三个服务:backend(FastAPI)、frontend(Next.js)和 db(MySQL)。但注意——它直接把后端和前端的端口暴露到了宿主机上。这在开发环境没问题,但生产环境里,直接暴露应用端口是不安全的,而且你也不想让用户通过 http://你的IP:3000 来访问吧?
第二步:准备生产环境的 .env 文件
在项目根目录创建一个 .env.production 文件(不要跟开发用的 .env 搞混):
# 数据库配置
MYSQL_PASSWORD=你的强密码
MYSQL_USER=agentgpt
MYSQL_DATABASE=agentgpt
# OpenAI
OPENAI_API_KEY=sk-你的key
# Serper(可选,但建议加上)
SERPER_API_KEY=你的serperkey
# NextAuth 配置(生产环境必须改)
NEXTAUTH_SECRET=生成一个随机字符串
NEXTAUTH_URL=https://你的域名.com
# 后端配置
BACKEND_URL=https://你的域名.com/api
FRONTEND_URL=https://你的域名.comNEXTAUTH_SECRET 可以用这个命令生成一个随机字符串:
openssl rand -base64 32第三步:添加 Nginx 反向代理
现在我们要在 Docker Compose 里加一个 Nginx 服务,让它充当所有请求的入口。修改 docker-compose.yml,在 services 下面新增:
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./ssl:/etc/nginx/ssl:ro
depends_on:
- frontend
- backend然后在项目根目录创建 nginx.conf:
events {
worker_connections 1024;
}
http {
upstream frontend {
server frontend:3000;
}
upstream backend {
server backend:8000;
}
server {
listen 80;
server_name 你的域名.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
server_name 你的域名.com;
ssl_certificate /etc/nginx/ssl/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/privkey.pem;
# 前端静态文件
location / {
proxy_pass http://frontend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# API 请求转发到后端
location /api/ {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}这个配置做了三件事:
- 把所有 HTTP 请求重定向到 HTTPS
- 把
/路径的请求转发给前端容器 - 把
/api/路径的请求转发给后端容器
第四步:配置 SSL 证书
在项目根目录创建 ssl 文件夹,然后把你的证书放进去。如果你还没有证书,用 Let's Encrypt 免费申请一个:
# 先安装 certbot
sudo apt install certbot
# 申请证书(需要你的域名已经指向服务器 IP)
sudo certbot certonly --standalone -d 你的域名.com
# 把证书复制到项目目录
sudo cp /etc/letsencrypt/live/你的域名.com/fullchain.pem ./ssl/
sudo cp /etc/letsencrypt/live/你的域名.com/privkey.pem ./ssl/第五步:修改前端配置让它知道生产环境地址
打开 next/.env.production(如果没有就创建),写入:
NEXT_PUBLIC_API_URL=https://你的域名.com/api
NEXT_PUBLIC_NEXTAUTH_URL=https://你的域名.com然后修改 next/next.config.js,加上允许的域名:
module.exports = {
images: {
domains: ['你的域名.com'],
},
async headers() {
return [
{
source: '/:path*',
headers: [
{ key: 'X-Frame-Options', value: 'DENY' },
{ key: 'X-Content-Type-Options', value: 'nosniff' },
{ key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
],
},
];
},
};第六步:构建并启动
现在万事俱备,可以启动了。在项目根目录执行:
# 先构建镜像(第一次会比较慢)
docker-compose build
# 启动所有服务
docker-compose -f docker-compose.yml up -d-d 参数让容器在后台运行。第一次启动时,Docker 会下载 MySQL 镜像、构建前端和后端的镜像,可能需要几分钟。
启动后检查服务状态:
docker-compose ps你应该看到四个服务都在运行:nginx、frontend、backend、db。
第七步:验证部署
打开浏览器访问 https://你的域名.com。如果一切正常,你应该能看到 AgentGPT 的登录页面。试着创建一个 Agent 跑一下,看看 API 调用是否正常。
如果遇到问题,先检查日志:
# 查看所有服务的日志
docker-compose logs
# 只看某个服务的日志
docker-compose logs backend
docker-compose logs frontend常见问题排查
问题 1:前端能打开,但 Agent 执行时报错 "Network Error"
这通常是前端找不到后端 API。检查 next/.env.production 里的 NEXT_PUBLIC_API_URL 是否正确,以及 Nginx 配置里的 /api/ 路径转发是否写对了。
问题 2:数据库连接失败
检查 .env.production 里的 MYSQL_PASSWORD 是否跟 docker-compose.yml 里的 MYSQL_ROOT_PASSWORD 一致。另外,MySQL 容器启动需要时间,如果后端启动太快可能会连不上——depends_on 只保证容器启动了,不保证 MySQL 已经准备好接受连接。
问题 3:HTTPS 证书报错
如果用的是 Let's Encrypt 证书,记得证书有效期只有 90 天。可以加个定时任务自动续期:
# 编辑 crontab
crontab -e
# 添加这行,每月 1 号凌晨 3 点续期并重启 Nginx
0 3 1 * * certbot renew --quiet && docker-compose restart nginx问题 4:前端页面样式错乱或功能异常
这通常是因为前端构建时用了开发环境的配置。确保你构建镜像前,next/.env.production 文件存在且内容正确。如果还是不行,试试清理构建缓存:
docker-compose down -v
docker system prune -a
docker-compose build --no-cache
docker-compose up -d小贴士:用 Docker Compose 管理生产环境
部署完成后,日常维护就靠这几个命令:
# 查看实时日志
docker-compose logs -f
# 重启某个服务
docker-compose restart backend
# 更新代码后重新部署
git pull
docker-compose build
docker-compose up -d
# 停止所有服务
docker-compose down注意:docker-compose down 会停止并删除容器,但不会删除数据卷(volumes),所以数据库数据还在。如果你要彻底清理(包括数据库),用 docker-compose down -v。
一个真实场景
假设你给公司部署了一个 AgentGPT 实例,用来自动生成周报。部署完成后,团队成员只需要打开 https://weekly-report.company.com,登录后输入"生成本周工作总结",Agent 就会自动从 Jira 拉取任务、分析完成情况、生成 Markdown 格式的周报。
这个部署方案的好处是:所有服务都在 Docker 容器里,互不干扰;Nginx 统一管理流量和 HTTPS;数据库数据持久化在 Docker 卷里,重启不会丢失。以后要升级版本,只需要 git pull 然后重新构建就行了。
现在你的 AgentGPT 已经是一个正经的线上服务了。下一章我们会聊聊怎么监控它的运行状态——毕竟线上服务出了故障,你得第一时间知道。
12. 12. 监控与日志:集成 Sentry 与 Prometheus
你的 Agent 跑起来了,用户也玩得挺开心。但有个问题:它到底在后台干了什么?如果某天它突然不干活了,或者回答变得莫名其妙,你只能干瞪眼——重启一下碰碰运气。这就像开车没有仪表盘,全凭感觉踩油门。
这一章就是给你的 Agent 装上仪表盘和行车记录仪。我们会集成两个工具:Sentry 用来抓代码层面的异常和性能问题,Prometheus + Grafana 用来监控系统运行指标(比如请求量、响应时间、内存占用)。装好之后,你不仅能知道“出事了”,还能知道“哪里出事了”以及“什么时候开始出事的”。
前置条件
- 你已经按照第 11 章(或之前的部署流程)用 Docker Compose 把 AgentGPT 跑起来了。
- 你有一个 Sentry 账号(免费额度够用)。
- 你有一个能跑 Docker 的服务器或本地环境。
- 基本的
docker-compose.yml文件修改权限。
第一步:给后端(FastAPI)接入 Sentry
Sentry 主要帮我们抓后端 Python 代码里的异常。比如某个 API 调用 OpenAI 超时了,或者数据库连接断了,Sentry 会记录下完整的堆栈信息。
安装 Sentry SDK 进入
platform/目录(你的后端代码所在目录),在终端执行:pip install sentry-sdk然后把
sentry-sdk添加到requirements.txt里,这样 Docker 构建时也会装上。初始化 Sentry 打开
platform/main.py(FastAPI 的入口文件),在文件顶部附近加入:import sentry_sdk from sentry_sdk.integrations.fastapi import FastApiIntegration from sentry_sdk.integrations.sqlalchemy import SqlAlchemyIntegration sentry_sdk.init( dsn="https://你的DSN@sentry.io/项目ID", # 从 Sentry 项目设置里复制 integrations=[ FastApiIntegration(), SqlAlchemyIntegration(), ], traces_sample_rate=1.0, # 生产环境可以调低,比如 0.2 environment="production", # 或 "staging" )预期结果:重启后端服务后,手动制造一个错误(比如故意让一个 API 除以零),去 Sentry 后台的 Issues 页面应该能看到这条错误记录。
配置环境变量 把
SENTRY_DSN加到你的.env文件里,然后在docker-compose.yml中传给后端容器:services: platform: environment: - SENTRY_DSN=${SENTRY_DSN}常见报错:如果 Sentry 没收到数据,检查 DSN 是否拼写正确,以及网络是否能访问
sentry.io(有些内网环境需要配置代理)。
第二步:给前端(Next.js)接入 Sentry
前端错误同样重要——用户可能遇到白屏、按钮点不动,这些都需要 Sentry 来捕获。
安装 Sentry 的 Next.js SDK 在
next/目录下执行:npm install @sentry/nextjs创建 Sentry 配置文件 在
next/目录下新建sentry.client.config.js:import * as Sentry from "@sentry/nextjs"; Sentry.init({ dsn: "https://你的DSN@sentry.io/项目ID", tracesSampleRate: 1.0, environment: process.env.NODE_ENV, });再新建
sentry.server.config.js(内容基本一样,用于服务端渲染的错误捕获)。修改
next.config.js在next.config.js中引入 Sentry 的插件:const { withSentryConfig } = require("@sentry/nextjs"); const moduleExports = { // 你原有的配置 }; module.exports = withSentryConfig(moduleExports, { silent: true, // 构建时不要打印太多日志 });预期结果:重新构建前端(
docker-compose up --build),然后在浏览器控制台手动抛一个错误(比如throw new Error("测试")),Sentry 后台应该能收到。实用技巧:Sentry 的免费版每月有 5000 个事件额度,对于个人项目完全够用。如果担心超量,可以把
tracesSampleRate降到 0.1。
第三步:部署 Prometheus + Grafana 监控系统指标
Sentry 管代码异常,Prometheus 管系统指标——比如你的 Agent 每秒处理多少个请求、API 响应时间是不是变慢了。
在 FastAPI 中暴露 Prometheus 指标 安装
prometheus-fastapi-instrumentator:pip install prometheus-fastapi-instrumentator在
platform/main.py中添加:from prometheus_fastapi_instrumentator import Instrumentator # 在创建 FastAPI 实例之后 Instrumentator().instrument(app).expose(app)这会自动在
/metrics端点暴露指标数据。预期结果:访问
http://你的服务器:8000/metrics,应该能看到一堆以# HELP和# TYPE开头的文本,那就是 Prometheus 能读懂的指标。在
docker-compose.yml中添加 Prometheus 和 Grafana 在services下面新增两个服务:services: prometheus: image: prom/prometheus:latest volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml ports: - "9090:9090" restart: unless-stopped grafana: image: grafana/grafana:latest ports: - "3001:3000" # 注意:前端已经用了 3000,所以 Grafana 用 3001 environment: - GF_SECURITY_ADMIN_PASSWORD=admin # 改成你自己的密码 volumes: - grafana_data:/var/lib/grafana restart: unless-stopped volumes: grafana_data:创建 Prometheus 配置文件 在项目根目录新建
prometheus.yml:global: scrape_interval: 15s scrape_configs: - job_name: "agentgpt-backend" static_configs: - targets: ["platform:8000"] # 注意:这里用 Docker 内部的服务名预期结果:执行
docker-compose up -d启动所有服务。访问http://你的服务器:9090,在 Prometheus 的 Status -> Targets 页面应该能看到agentgpt-backend状态为 UP。常见报错:如果 Prometheus 显示
connection refused,检查targets里的地址是否正确。在 Docker 内部,服务名就是platform,端口是8000。配置 Grafana 数据源和仪表盘
- 访问
http://你的服务器:3001,用admin/ 你设置的密码登录。 - 点击左侧齿轮图标 -> Data Sources -> Add data source -> 选择 Prometheus。
- URL 填
http://prometheus:9090(Docker 内部地址),点击 Save & Test。 - 回到首页,点击 + 号 -> Import,输入仪表盘 ID
1860(这是一个通用的 FastAPI 监控仪表盘),加载后选择你的 Prometheus 数据源。
预期结果:Grafana 里应该能看到请求速率、延迟分布、错误率等图表。如果数据是空的,等一两分钟让 Prometheus 先采集几轮数据。
- 访问
一个小例子串起来
假设你部署了一个“自动调研竞品”的 Agent。某天用户反馈说“Agent 跑了一半卡住了”。没有监控时,你只能重启。现在你可以:
- 打开 Sentry,看有没有新的错误——发现是 OpenAI 返回了一个
rate_limit_error。 - 打开 Grafana,看
http_requests_total指标——发现请求量在某个时间点突然飙升,触发了 OpenAI 的限流。 - 于是你决定给 Agent 加上重试逻辑和请求排队,问题解决。
这就是监控的价值:从“猜”变成“看”。
注意事项
- 不要在生产环境用默认的 Grafana 密码,改掉它。
- Prometheus 的数据默认存在容器里,重启会丢失。如果需要持久化,挂载一个外部卷或目录。
- Sentry 的
traces_sample_rate在生产环境建议设为 0.1 或更低,否则可能产生大量数据,吃掉免费额度。 - 如果你的服务器内存有限(比如 1GB),Prometheus 和 Grafana 加起来大概会占用 200-300MB,注意预留。
13. 13. 安全加固:API 密钥管理、速率限制与输入验证
把 API 密钥直接写死在代码里,就像把银行卡密码贴在显示器上——方便是方便,但迟早要出事。AgentGPT 跑起来之后,你至少得跟 OpenAI、Serper、Replicate 三家服务打交道,每个都有自己的密钥。如果这些密钥被偷了,轻则账单爆炸,重则被人拿去干坏事,你的 IP 都可能被拉黑。
这一章我们就干三件事:把密钥藏好、给 API 加上限速、把用户输入过滤干净。做完之后,你的 AgentGPT 实例才算真正能见人。
前置条件
- 你已经成功部署了 AgentGPT(不管是本地开发环境还是生产环境)
- 你手头有 OpenAI API Key、Serper API Key(可选)、Replicate API Token(可选)
- 你熟悉
.env文件的基本用法
第一步:把密钥从代码里赶出去
AgentGPT 项目根目录下有个 .env.example 文件,里面列出了所有需要的环境变量。我们的原则是:密钥只存在于环境变量和密钥管理服务里,绝不硬编码。
先看看项目里是怎么加载密钥的。打开 platform/.env(如果没有就复制 .env.example 创建),你会看到类似这样的内容:
# 必须填
OPENAI_API_KEY=sk-your-key-here
# 可选,但推荐填
SERPER_API_KEY=your-serper-key
REPLICATE_API_TOKEN=your-replicate-token
# 数据库
DATABASE_URL=mysql://user:password@localhost:3306/agentgpt重点来了:永远不要把 .env 文件提交到 Git。项目自带的 .gitignore 已经帮你把 .env 排除了,但你自己要养成习惯——每次 git status 的时候扫一眼,确认没有密钥文件混进去。
如果你用的是 Docker 部署,密钥可以通过 Docker Compose 的环境变量传进去。打开 docker-compose.yml,找到 backend 服务那块:
services:
backend:
environment:
- OPENAI_API_KEY=${OPENAI_API_KEY}
- SERPER_API_KEY=${SERPER_API_KEY}这样你只需要在宿主机上设好环境变量,容器启动时自动继承。比把密钥写在 Dockerfile 里安全一百倍。
常见翻车现场:有人把 .env 改成了 .env.local 然后忘了加进 .gitignore,结果一 push 密钥全网裸奔。解决方案:在项目根目录跑一遍 echo ".env.local" >> .gitignore,然后 git rm --cached .env.local 把它从 Git 追踪里移除。
第二步:给 API 加上限速器
密钥藏好了,但如果你不限制调用频率,别人可以拿你的 API 端点当免费代理用。AgentGPT 后端用的是 FastAPI,加限速最方便的方式是用 slowapi 这个库。
先安装:
cd platform
pip install slowapi然后在 platform/main.py 里加上限速配置。找到文件开头,在 app 定义之后加入:
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address
limiter = Limiter(key_func=get_remote_address)
app.state.limiter = limiter
app.add_exception_handler(429, _rate_limit_exceeded_handler)接着给关键的 API 端点加上装饰器。比如 Agent 执行任务的端点,我们限制每分钟最多 10 次请求:
@app.post("/api/agent/execute")
@limiter.limit("10/minute")
async def execute_agent(request: Request, agent_data: AgentInput):
# 原有的业务逻辑
...如果你想让不同用户有不同的限额(比如付费用户 100 次/分钟,免费用户 10 次/分钟),可以自定义 key_func。举个简单的例子,从请求头里拿 API Key 来区分:
def get_api_key(request: Request):
return request.headers.get("X-API-Key", "anonymous")
limiter = Limiter(key_func=get_api_key)这样每个 API Key 独立计数,互不影响。
预期结果:在 1 分钟内连续发 11 次请求到 /api/agent/execute,第 11 次会收到 HTTP 429 响应,内容类似 {"detail": "Rate limit exceeded: 10 per 1 minute"}。
常见报错:如果你遇到 ImportError: cannot import name 'Limiter' from 'slowapi',说明你装的版本不对。用 pip install slowapi==0.1.9 指定版本试试。
第三步:把用户输入过滤干净
AgentGPT 允许用户输入目标、任务描述这些自由文本。如果不做过滤,攻击者可以塞进去 SQL 注入语句或者 XSS 脚本。虽然 FastAPI 自带的 Pydantic 模型已经做了类型校验,但还不够——我们需要对字符串内容做进一步清洗。
项目里已经用了 Pydantic 做 schema 验证,打开 platform/schemas/agent.py,你会看到类似这样的模型:
from pydantic import BaseModel, Field
import re
class AgentInput(BaseModel):
name: str = Field(..., min_length=1, max_length=50)
goal: str = Field(..., min_length=1, max_length=500)
@validator("name", "goal")
def sanitize_input(cls, v):
# 移除 HTML 标签
v = re.sub(r'<[^>]*>', '', v)
# 移除危险字符(根据你的业务需求调整)
v = re.sub(r'[<>"\'%;()&]', '', v)
# 限制长度
if len(v) > 500:
v = v[:500]
return v.strip()这个 @validator 会在每次创建 AgentInput 实例时自动运行,把脏东西挡在门外。
对于数据库查询,AgentGPT 用的是 Prisma ORM,它本身已经做了参数化查询,SQL 注入的风险很低。但如果你在代码里写了原生 SQL(比如某些复杂查询),一定要用参数绑定,不要拼字符串:
# ❌ 危险写法
cursor.execute(f"SELECT * FROM agents WHERE name = '{user_input}'")
# ✅ 安全写法
cursor.execute("SELECT * FROM agents WHERE name = %s", (user_input,))预期结果:如果你在 Agent 名称里输入 <script>alert('xss')</script>,保存后这个标签会被自动移除,数据库里存的是干净的字符串。
实用技巧:不要只依赖后端过滤,前端也要做一层。在 Next.js 的前端代码里,用 zod(项目已经装了)对表单输入做同样的校验:
import { z } from 'zod';
const agentSchema = z.object({
name: z.string().min(1).max(50).transform(val => val.replace(/<[^>]*>/g, '')),
goal: z.string().min(1).max(500).transform(val => val.replace(/<[^>]*>/g, '')),
});双层过滤,双重保险。
小例子串起来:给 Agent 注册加个安全门
假设你要做一个用户注册功能,让用户输入 API Key 来激活 Agent。我们可以把这三步安全措施都用上:
- 密钥管理:用户的 API Key 不存明文,用哈希加密后存数据库
- 限速:每个 IP 每小时只能注册 3 次,防止暴力破解
- 输入验证:用户名和 API Key 都做过滤,不允许特殊字符
代码大概长这样:
from passlib.hash import bcrypt
from slowapi import Limiter
limiter = Limiter(key_func=get_remote_address)
@app.post("/api/register")
@limiter.limit("3/hour")
async def register(request: Request, user: UserInput):
# 输入已经在 UserInput 的 validator 里过滤过了
hashed_key = bcrypt.hash(user.api_key)
# 存到数据库
db.execute("INSERT INTO users (name, api_key_hash) VALUES (%s, %s)",
(user.name, hashed_key))
return {"status": "ok"}这样就算数据库被拖库,攻击者拿到的也是哈希值,解不出原始 API Key。
别忘了日志审计
安全措施加完了,还得知道有没有人撞墙。在限速和输入验证的地方加日志,方便事后排查:
import logging
logger = logging.getLogger(__name__)
@app.post("/api/agent/execute")
@limiter.limit("10/minute")
async def execute_agent(request: Request, agent_data: AgentInput):
logger.info(f"Agent execution from {request.client.host}: {agent_data.name}")
# 业务逻辑日志里不要记录完整的 API Key 或密码,只记 IP、时间、操作类型就够了。
做完这三步,你的 AgentGPT 实例至少能挡住 90% 的常见攻击。剩下的 10% 靠你保持依赖库更新——记得每个月跑一次 pip list --outdated 和 npm outdated,把有安全漏洞的包升上去。
14. 14. 完整项目实战:构建一个自动生成周报的 Agent 系统
把前面学的全串起来:一个自动写周报的 Agent
前面十三章,我们拆开了 AgentGPT 的每个零件:环境搭建、API 配置、工具注册、记忆管理、参数调优、多 Agent 协作、前端定制、后端扩展、性能优化、部署上线、监控告警、安全加固……现在该把它们拧成一台能真正干活的机器了。
这一章的目标很具体:构建一个能自动生成周报的 Agent 系统。你给它一个团队名称和本周的关键事件,它自己去查资料、整理要点、生成 Markdown 格式的周报,最后保存到数据库里。整个过程不需要你手动复制粘贴任何东西。
前置条件
- 你已经完成了第 1-13 章的所有步骤,本地或服务器上跑着 AgentGPT
- 数据库里有
reports表(我们马上建) - OpenAI API Key 和 Serper API Key 都配置好了
- 你大概知道 FastAPI 和 Next.js 的项目结构长什么样
第一步:设计周报的数据结构
周报需要存哪些字段?最少要有:团队名称、报告周期、内容(Markdown 文本)、创建时间。打开 platform/db/models.py,加一个模型:
from datetime import datetime
from sqlmodel import SQLModel, Field
class WeeklyReport(SQLModel, table=True):
id: int = Field(default=None, primary_key=True)
team_name: str
week_start: str # 格式 "2024-01-01"
week_end: str # 格式 "2024-01-07"
content: str # Markdown 正文
created_at: datetime = Field(default_factory=datetime.utcnow)然后跑迁移。如果你用的是 Prisma,在 prisma/schema.prisma 里加:
model WeeklyReport {
id Int @id @default(autoincrement())
teamName String
weekStart String
weekEnd String
content String
createdAt DateTime @default(now())
}接着 npx prisma migrate dev --name add_weekly_report。预期结果是数据库里多了一张 WeeklyReport 表。
第二步:写一个“周报生成器”工具
Agent 需要知道怎么生成周报。我们给它注册一个自定义工具,叫 generate_weekly_report。在 platform/tools/ 下新建 weekly_report_tool.py:
from langchain.tools import BaseTool
from typing import Optional, Type
from pydantic import BaseModel, Field
class WeeklyReportInput(BaseModel):
team_name: str = Field(description="团队名称")
week_start: str = Field(description="周开始日期,格式 YYYY-MM-DD")
week_end: str = Field(description="周结束日期,格式 YYYY-MM-DD")
highlights: str = Field(description="本周关键事件,用逗号分隔")
class WeeklyReportTool(BaseTool):
name = "generate_weekly_report"
description = "根据团队名称、日期范围和关键事件生成 Markdown 格式的周报"
args_schema: Type[BaseModel] = WeeklyReportInput
def _run(self, team_name: str, week_start: str, week_end: str, highlights: str) -> str:
# 这里只是模板,真正的生成逻辑由 Agent 调用 LLM 完成
report = f"""# {team_name} 周报
**周期**: {week_start} 至 {week_end}
## 本周完成
- {highlights.replace(',', '\n- ')}
## 下周计划
- (待补充)
## 风险与问题
- (待补充)
"""
return report
async def _arun(self, *args, **kwargs):
raise NotImplementedError注意:这个工具本身只返回一个模板,真正的“智能生成”要靠 Agent 调用 LLM 来填充内容。工具的作用是定义接口——告诉 Agent 它可以用什么参数、返回什么格式。
第三步:把工具注册到 Agent 系统
打开 platform/services/agent_service.py(或者你项目里注册工具的地方),把 WeeklyReportTool 加进去:
from tools.weekly_report_tool import WeeklyReportTool
# 在初始化 Agent 的工具列表里加上
tools = [
# ... 已有的工具
WeeklyReportTool(),
]如果你用的是第 4 章那种动态注册方式,在配置界面里加一行就行。预期结果是 Agent 现在知道有 generate_weekly_report 这个工具可以调用。
第四步:创建保存周报的 API 端点
Agent 生成周报后,需要存到数据库。在 platform/routers/ 下新建 reports.py:
from fastapi import APIRouter, Depends, HTTPException
from sqlmodel import Session, select
from db.models import WeeklyReport
from db.database import get_session
router = APIRouter(prefix="/api/reports", tags=["reports"])
@router.post("/")
def create_report(report: WeeklyReport, session: Session = Depends(get_session)):
session.add(report)
session.commit()
session.refresh(report)
return report
@router.get("/")
def list_reports(session: Session = Depends(get_session)):
reports = session.exec(select(WeeklyReport).order_by(WeeklyReport.created_at.desc())).all()
return reports
@router.get("/{report_id}")
def get_report(report_id: int, session: Session = Depends(get_session)):
report = session.get(WeeklyReport, report_id)
if not report:
raise HTTPException(status_code=404, detail="Report not found")
return report然后在 platform/main.py 里注册这个路由:
from routers import reports
app.include_router(reports.router)重启后端,用 curl 测试一下:
curl -X POST http://localhost:8000/api/reports/ \
-H "Content-Type: application/json" \
-d '{"team_name":"研发部","week_start":"2024-01-01","week_end":"2024-01-07","content":"# 测试周报"}'预期返回 200 和刚创建的记录。
第五步:写一个“周报助手”Agent 配置
现在让 Agent 自己干活。打开前端页面,创建一个新的 Agent,配置如下:
- 名称: 周报助手
- 目标: 生成研发部 2024-01-01 至 2024-01-07 的周报,关键事件包括:完成用户模块重构、修复三个线上 bug、开始性能优化调研
- 工具: 勾选
generate_weekly_report和search(让它能查资料补充内容) - 最大迭代: 5(够了,周报不需要跑太多轮)
- 温度: 0.3(低一点,保持输出稳定)
点击“部署 Agent”。你会看到它开始思考:
- 先调用
search搜索“用户模块重构 最佳实践 2024” - 再调用
generate_weekly_report生成初稿 - 可能还会再调一次
search补充下周计划
最终输出应该是一份像模像样的 Markdown 周报。
第六步:自动保存到数据库
Agent 生成的周报现在只显示在界面上,我们需要让它自动调用保存 API。有两种做法:
做法 A:在工具里直接调用 API
修改 WeeklyReportTool._run,让它生成内容后自动 POST 到 /api/reports/:
import requests
def _run(self, team_name, week_start, week_end, highlights):
# 先让 LLM 生成内容(这里简化了,实际要调 LLM)
content = self._generate_content(team_name, week_start, week_end, highlights)
# 保存到数据库
response = requests.post("http://localhost:8000/api/reports/", json={
"team_name": team_name,
"week_start": week_start,
"week_end": week_end,
"content": content
})
return f"周报已保存,ID: {response.json()['id']}"做法 B:在 Agent 完成回调里保存
如果你不想让工具直接依赖 HTTP 请求,可以在 Agent 执行完毕后,由后端自动保存。在 agent_service.py 里找到 Agent 完成后的回调:
async def on_agent_complete(agent_result):
if "generate_weekly_report" in agent_result.tool_calls:
# 解析结果,保存到数据库
report_data = parse_report_from_result(agent_result.output)
await save_report(report_data)我推荐做法 A,更直观,而且工具本身就是一个完整的“生成+保存”单元。
第七步:前端展示历史周报
在 Next.js 里加一个页面 /reports,列出所有已生成的周报。新建 pages/reports.tsx:
import { useEffect, useState } from 'react';
export default function ReportsPage() {
const [reports, setReports] = useState([]);
useEffect(() => {
fetch('/api/reports/')
.then(res => res.json())
.then(setReports);
}, []);
return (
<div className="p-4">
<h1 className="text-2xl font-bold mb-4">历史周报</h1>
{reports.map(report => (
<div key={report.id} className="border p-3 mb-2 rounded">
<h2>{report.teamName} - {report.weekStart} 至 {report.weekEnd}</h2>
<pre className="whitespace-pre-wrap">{report.content}</pre>
</div>
))}
</div>
);
}别忘了在导航栏加个链接。预期结果是访问 /reports 能看到所有已保存的周报。
常见翻车点
Agent 不调用周报工具:检查工具描述是否清晰。把 description 改成更明确的句子,比如“当你需要生成或保存周报时,使用此工具。参数包括团队名称、开始日期、结束日期和关键事件。”
保存时报 500:检查数据库迁移是否成功。跑 npx prisma db push 或 alembic upgrade head 确保表结构最新。
周报内容太短:降低温度到 0.2-0.3,或者在目标里写得更具体,比如“每部分至少写 3 个要点”。
Agent 循环调用搜索:把最大迭代设小一点,比如 3。周报不需要反复查资料。
小技巧
- 可以在
WeeklyReportTool里加一个format参数,支持markdown和html两种输出 - 如果团队每周的关键事件差不多,可以写一个“周报模板”工具,让 Agent 先加载模板再填充
- 把周报生成做成定时任务:用 Celery 或 APScheduler,每周五下午 5 点自动触发一个 Agent
现在你有了一个能自动写周报的系统。下次周五下午,你只需要打开 /reports 页面,复制粘贴到邮件里就行。如果老板问“这周干了啥”,你甚至可以让 Agent 再跑一遍,生成一份更详细的版本。
FAQ
问题 1:安装时 ./setup.sh 或 ./setup.bat 报错“Permission denied”或“无法识别”
解答
- Linux/macOS:先给脚本执行权限:
chmod +x setup.sh,再运行./setup.sh。 - Windows:确保以管理员身份打开终端(PowerShell 或 CMD),然后执行
./setup.bat。如果提示“无法加载文件”,请先运行Set-ExecutionPolicy RemoteSigned -Scope CurrentUser允许执行脚本。 - 如果仍然失败,检查是否已安装 Docker 并确保 Docker Desktop 正在运行。
问题 2:启动后访问 http://localhost:3000 显示空白页或“连接失败”
解答
- 确认所有服务都已启动:Docker 容器(
docker ps)应包含agentgpt-db、agentgpt-backend、agentgpt-frontend等。 - 检查
.env文件是否已正确配置:至少需要OPENAI_API_KEY,可选SERPER_API_KEY和REPLICATE_API_TOKEN。 - 如果后端报错,查看 Docker 日志:
docker logs agentgpt-backend。常见错误是 API Key 无效或数据库连接失败。 - 前端默认端口是 3000,后端是 8000,确保没有端口冲突。
问题 3:AgentGPT 和 AutoGPT 有什么区别?为什么选择 AgentGPT?
解答
- 部署方式:AgentGPT 是 Web 应用,直接在浏览器中配置和运行;AutoGPT 是命令行工具,需要本地 Python 环境。
- 易用性:AgentGPT 提供图形界面,无需编写代码;AutoGPT 需要手动管理文件、API Key 和循环逻辑。
- 目标:AgentGPT 强调“一键部署自主 AI 代理”,适合快速实验;AutoGPT 更灵活但配置复杂。
- 技术栈:AgentGPT 使用 Next.js + FastAPI + LangChain;AutoGPT 基于 Python 和 LangChain。
- 如果你希望快速在浏览器中体验自主 AI,选 AgentGPT;如果需要深度定制或离线运行,考虑 AutoGPT。
问题 4:为什么 AgentGPT 需要 Docker?能不能不用 Docker 直接运行?
解答
- Docker 用于统一管理数据库(MySQL)、后端(FastAPI)和前端(Next.js)的依赖,避免手动安装多个环境。
- 如果不想用 Docker,可以手动安装:
- 安装 Node.js、Python 3.9+、MySQL。
- 分别启动后端(
cd platform && pip install -r requirements.txt && uvicorn main:app)和前端(cd next && npm install && npm run dev)。 - 配置
.env中的数据库连接和 API Key。
- 但官方推荐使用 Docker,因为 setup 脚本会自动处理所有步骤,减少环境问题。
问题 5:运行 AgentGPT 时提示“OpenAI API Key 无效”或“速率限制”
解答
- 检查
.env中的OPENAI_API_KEY是否正确(格式为sk-...)。 - 确保 OpenAI 账户有余额(免费额度已用完或未绑定支付方式)。
- 如果遇到速率限制(
RateLimitError),可以:- 降低任务并发数(在 Agent 配置中调整)。
- 使用更便宜的模型(如
gpt-3.5-turbo而非gpt-4)。 - 等待一段时间再试。
- 注意:AgentGPT 默认使用
gpt-3.5-turbo,如需gpt-4需在代码中修改模型名称(但需要 API 权限)。
问题 6:Agent 执行任务时卡住或无限循环,怎么办?
解答
- AgentGPT 的自主循环机制是:思考 → 执行 → 学习 → 重复。如果任务目标过于模糊(如“探索宇宙”),Agent 可能陷入无限循环。
- 解决方法:
- 在创建 Agent 时,将目标拆分为具体、可衡量的子任务(例如“搜索关于 X 的 5 篇文章并总结”)。
- 设置最大循环次数(在代码或配置中调整
max_iterations)。 - 如果卡住,可以手动停止 Agent(界面上的“Stop”按钮),然后重新配置。
- 如果 Agent 一直调用相同 API 而不推进,可能是 LangChain 的 LLM 链设计问题,可尝试更新项目版本。
问题 7:如何添加自定义工具或 API(例如 Google 搜索、图像生成)?
解答
- AgentGPT 默认集成了 Serper API(搜索)和 Replicate API(图像生成)。
- 添加新工具:
- 在后端代码(
platform/目录)的tools/文件夹中创建新的工具类,继承 LangChain 的BaseTool。 - 在
agent.py中注册该工具。 - 在前端界面中,添加对应的配置选项(如 API Key 输入框)。
- 在后端代码(
- 如果不想修改代码,可以:
- 在 Agent 的目标中直接要求使用外部 API(例如“调用 https://api.example.com 获取数据”),但 Agent 需要具备 HTTP 请求能力(默认支持)。
- 注意:自定义工具需要重新构建 Docker 镜像(
docker-compose build)。
问题 8:AgentGPT 是否支持多语言?如何让 Agent 用中文输出?
解答
- AgentGPT 的界面支持多语言(通过 i18n),但 Agent 的输出语言由 LLM 模型决定。
- 让 Agent 用中文:
- 在创建 Agent 时,在“目标”或“提示”中明确指定语言,例如:“请用中文回答所有问题”。
- 如果使用 GPT-4,中文支持更好;GPT-3.5 也能输出中文,但可能偶尔混用英文。
- 注意:Agent 的思考过程(内部日志)可能仍是英文,但最终输出会遵循你的语言指令。
- 如果希望界面完全中文,可以贡献翻译文件(
next/public/locales/目录)。