摘要: 本文给出一套可落地的 Persistent AI Agent 项目架构:Agent 可以全天候接收事件、按计划主动执行任务,在进程或服务器重启后从持久状态恢复,跨会话调用长期记忆,并在发邮件、发布内容、删除数据、付款或修改权限前暂停等待人工审批。最重要的结论是,“24 小时持续运行”不应依赖一条永不结束的模型连接,而应由任务队列、持久化状态机、定时触发器、幂等工具、租约心跳、记忆治理、审批门禁和审计日志共同实现。本文适合开发者、自动化团队、AI Stack Nav 项目搭建者和企业技术负责人,可直接作为 Python+PostgreSQL+Redis+Worker 项目的设计蓝图。
核心结论
Persistent AI Agent 是一种“可暂停、可恢复、可主动唤醒、可长期记忆、可人工接管”的耐久任务系统,而不是一个持续占用模型连接的聊天机器人。要让它稳定运行 24 小时甚至数月,必须把模型推理与任务生命周期解耦:每一步完成后写入数据库,下一步由事件、定时器、Webhook 或队列重新唤醒;遇到敏感工具调用则保存运行状态,等待审批后继续。
- 值得搭建: 适合网站内容运营、工单跟进、销售线索、监控告警、研究任务和跨天项目推进。
- 关键架构: PostgreSQL 保存任务、检查点、记忆和审批;Redis 或消息队列负责分发;Worker 执行短步骤;Scheduler 负责主动触发。
- 真正的持续性: Worker 可以下线,任务仍然存在;恢复依靠事件历史和检查点,而不是依靠内存中的对话对象。
- 长期记忆边界: 会话记录、任务状态、用户事实和知识文档应分层存储,并设置来源、置信度、保留期限与删除机制。
- 安全实施建议: 读取、搜索等低风险操作可自动执行;发布、发送、购买、删除、转账和权限修改必须进入人工审批。
背景与主要变化
结论先说:Agent 产品正在从“用户问一句、模型答一句”转向“接受长期目标、等待外部条件、主动继续工作”。这带来三个新问题:进程重启后任务是否还在;Agent 如何在没有用户新消息时被可靠唤醒;执行真实动作时如何控制权限与责任。
普通聊天应用把会话历史留在内存或一次 HTTP 请求中。只要部署重启、网络断开或用户关闭页面,执行上下文就可能丢失。Persistent Agent 则把任务视为状态机:created、queued、running、waiting_event、waiting_approval、retry_scheduled、completed、failed 或 cancelled。每次状态变化都形成可审计事件,Worker 只负责领取一个有界步骤。
OpenAI Agents SDK 官方文档提供了人机协同暂停与恢复模式:需要审批的工具调用会出现在 interruptions 中,应用可将 RunState 序列化保存,批准或拒绝后再恢复原始运行。官方运行指南也将 Dapr、Temporal、DBOS 等列为长等待、重试、进程重启和 human-in-the-loop 场景的耐久编排集成。Temporal 官方则把 Workflow 描述为可持续数秒到数年的耐久执行,Worker 故障后可通过事件历史重放恢复。
因此,“24 小时 Agent”应理解成服务可随时响应、任务可跨时间延续,而不是每个任务持续消耗 Token。更多同类方案可查看 AI Stack Nav 的长任务 Agent 教程和Agent 人工审批实战。
系统架构与核心组件
核心结论是:生产级 Persistent Agent 至少需要七个互相解耦的组件。模型只是决策层,耐久性由外围运行时提供。
| 组件 | 主要职责 | 持久化内容 | 关键风险控制 |
|---|---|---|---|
| API / Webhook Gateway | 接收用户目标、外部事件和审批结果 | 请求 ID、来源、签名验证结果 | 鉴权、限流、防重放 |
| Scheduler | 定时扫描、延迟唤醒、周期任务 | 下次执行时间、时区、规则版本 | 防重复触发、错过补偿 |
| Queue | 分发可执行步骤,吸收流量峰值 | 消息 ID、投递次数 | 可见性超时、死信队列 |
| Agent Worker | 读取上下文、调用模型、规划下一步 | 检查点、模型使用量、决策摘要 | 步骤超时、预算、最大循环数 |
| Tool Gateway | 封装邮件、WordPress、CRM、MCP 等工具 | 调用参数摘要、结果、幂等键 | 最小权限、参数校验、审批策略 |
| Memory Service | 管理会话、事实、知识与经验 | 内容、来源、置信度、有效期 | 隐私过滤、可删除、避免污染 |
| Approval / Audit | 暂停敏感动作并记录决策 | 审批人、理由、时间、状态快照 | 双人审批、过期、不可抵赖日志 |

一次典型执行如下:Scheduler 发现任务到期,把 task_id 写入队列;Worker 取得租约,读取最近检查点与必要记忆;模型产生下一步动作;策略引擎判断工具风险;低风险工具立即执行,高风险工具创建审批单并把任务转为 waiting_approval;审批结果通过 Webhook 写入事件表,再次唤醒同一任务。
边界是:Redis 队列本身不应成为唯一事实来源。消息可能重复投递、过期或丢失,因此任务状态、检查点和工具调用结果必须以数据库为准。队列只负责“提醒 Worker 有活要干”。
24 小时持续任务如何实现
真正可靠的做法是“短执行+持久等待”。单个 Worker 步骤应在几十秒或几分钟内完成;需要等待两小时、明天上午或外部回复时,保存 wake_at 或订阅事件,然后释放计算资源。
建议采用以下状态转换:
CREATED → QUEUED → RUNNING
RUNNING → WAITING_EVENT | WAITING_APPROVAL | RETRY_SCHEDULED
WAITING_EVENT → QUEUED
WAITING_APPROVAL → QUEUED | CANCELLED
RETRY_SCHEDULED → QUEUED
RUNNING → COMPLETED | FAILED
数据库最小表结构可以这样设计:
CREATE TABLE agent_tasks (
id UUID PRIMARY KEY,
tenant_id UUID NOT NULL,
goal TEXT NOT NULL,
status TEXT NOT NULL,
step_no INTEGER NOT NULL DEFAULT 0,
wake_at TIMESTAMPTZ,
lease_owner TEXT,
lease_until TIMESTAMPTZ,
budget_cents INTEGER NOT NULL DEFAULT 0,
spent_cents INTEGER NOT NULL DEFAULT 0,
max_steps INTEGER NOT NULL DEFAULT 30,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE task_events (
id BIGSERIAL PRIMARY KEY,
task_id UUID NOT NULL REFERENCES agent_tasks(id),
event_type TEXT NOT NULL,
payload JSONB NOT NULL DEFAULT '{}',
idempotency_key TEXT UNIQUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE task_checkpoints (
task_id UUID NOT NULL REFERENCES agent_tasks(id),
version INTEGER NOT NULL,
run_state BYTEA NOT NULL,
state_hash TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
PRIMARY KEY (task_id, version)
);
Worker 领取任务时必须使用租约而不是永久锁。若 Worker 崩溃,lease_until 到期后其他 Worker 可以重新领取。工具调用则用幂等键避免重复发送邮件、重复发文或重复扣款:同一 task_id + step_no + tool_name + normalized_args_hash 只能产生一次业务副作用。
async def execute_step(task_id: str, worker_id: str):
task = await repo.claim_with_lease(task_id, worker_id, ttl_seconds=120)
if not task:
return
try:
context = await context_builder.build(task)
decision = await agent.plan(context)
if decision.kind == "WAIT":
await repo.save_wait(task.id, decision.wake_at, decision.reason)
return
await policy.enforce_budget(task, decision)
result = await tool_gateway.execute_or_request_approval(task, decision)
await repo.checkpoint_and_transition(task, decision, result)
except RetryableError as exc:
await repo.schedule_retry(task, exc, backoff="exponential+jitter")
finally:
await repo.release_lease(task.id, worker_id)
注意:租约、状态更新、检查点和待发送消息最好使用事务性 Outbox,避免“数据库已更新但消息没发出”或“消息发出但状态未提交”。
主动执行与触发机制
结论是:主动执行必须由明确的触发器驱动,不能让模型自行无限轮询。触发器应可配置、可暂停、可审计,并受频率与预算约束。
常见触发方式包括:Cron 定时任务、数据库状态变化、Webhook、消息队列事件、邮件或日历事件、监控阈值,以及人工创建的“稍后继续”。每个触发器都要映射到唯一事件 ID;Scheduler 即使重复扫描,也只会插入一次事件。
triggers:
- id: daily_ai_news_scan
type: cron
schedule: "0 8 * * *"
timezone: "Asia/Shanghai"
task_template: ai_news_research
catch_up: true
max_concurrent_runs: 1
daily_budget_cents: 500
- id: wordpress_draft_reviewed
type: webhook
path: /events/wordpress/reviewed
signature_secret_env: WP_WEBHOOK_SECRET
dedupe_window_hours: 72
对 AI Stack Nav,可将主动 Agent 设计为:每天扫描官方更新,生成候选选题;只把文章保存为 WordPress 草稿;编辑确认事实、SEO 和配图后,再由发布工具执行。Agent 可以主动发现任务和准备交付物,但公开发布权仍属于人。
长期记忆设计
结论是:长期记忆不是一个无限增长的聊天记录,而是四层不同用途的数据。
- 运行记忆: 当前任务状态、已完成步骤、工具结果与下一次唤醒条件,必须精确、不可由模型随意改写。
- 会话记忆: 用户与 Agent 的交互历史,可通过 Session 保存,但需要压缩与长度控制。
- 事实记忆: 用户偏好、项目约束、明确决定等结构化事实,包含来源、确认状态、置信度和有效期。
- 知识记忆: 文档、网页、规范与历史交付物,通过关键词或向量检索按需召回,并保留原始来源。
OpenAI Agents SDK 的 Sessions 能自动维护跨运行会话历史,但这只解决对话连续性,不等于完整的长期记忆治理。生产系统还要决定什么值得写入、谁可读取、何时过期、如何更正和删除。
{
"memory_id": "mem_01J...",
"tenant_id": "YOUR_TENANT_ID",
"subject": "project:aistacknav",
"type": "confirmed_preference",
"content": "WordPress内容默认保存为草稿,发布必须人工审批",
"source_event_id": "evt_01J...",
"confidence": 1.0,
"valid_from": "2026-09-01T00:00:00Z",
"expires_at": null,
"sensitivity": "internal",
"status": "active"
}
记忆写入前应检查价值、来源、隐私和冲突。未经用户确认的模型推断应标记为 inferred,不能覆盖已确认事实;检索结果应附来源,避免错误记忆持续污染后续决策。
人工审批与权限门禁
核心原则是:审批不是弹窗装饰,而是一个可持久化的暂停点。系统必须在工具执行之前保存准确参数、风险等级和可恢复状态;审批人看到的内容要足够具体,例如“向谁发送哪封邮件”,而不是模糊的“允许 Agent 继续”。

建议按风险分级:
| 风险级别 | 示例 | 默认策略 |
|---|---|---|
| L0 只读 | 搜索公开资料、读取授权范围内文档 | 自动执行并记录 |
| L1 可逆写入 | 创建草稿、添加内部标签 | 自动或抽样审批 |
| L2 外部影响 | 发邮件、发布文章、创建工单 | 每次审批 |
| L3 高风险 | 删除数据、付款、修改权限、生产数据库写入 | 双人审批或禁止 |
OpenAI Agents SDK 的 HITL 模式允许工具通过 needs_approval 声明审批要求;运行暂停后,应用把 RunState 保存到检查点。简化示例如下:
from agents import Agent, Runner, function_tool
@function_tool(needs_approval=True)
async def publish_wordpress(post_id: int) -> str:
"""Publish an already reviewed WordPress draft."""
return await wp.publish(post_id, idempotency_key=f"publish:{post_id}")
agent = Agent(
name="Persistent Content Agent",
instructions="Prepare drafts autonomously. Publishing always requires approval.",
tools=[publish_wordpress],
)
result = await Runner.run(agent, "Publish reviewed draft 1683")
if result.interruptions:
state = result.to_state()
await checkpoint_store.save(state) # serialize and encrypt at rest
await approval_service.create(result.interruptions)
审批单必须有过期时间。过期、参数变化或工具版本变化后,旧批准不得继续复用;恢复前重新核对审批时看到的参数哈希与即将执行的参数哈希是否一致。
完整部署步骤
推荐先用单机 Docker Compose 完成验证,再根据任务量拆分 Worker。最小项目目录如下:
persistent-agent/
├── app/ # API、审批回调与管理接口
├── worker/ # Agent步骤执行器
├── scheduler/ # 定时扫描与延迟唤醒
├── tools/ # WordPress、邮件、搜索、MCP适配器
├── memory/ # 记忆写入、检索、冲突与删除
├── migrations/ # PostgreSQL表结构
├── policies/ # 工具风险、预算和权限策略
├── tests/ # 崩溃恢复、重复投递、审批与安全测试
├── docker-compose.yml
└── .env.example
services:
postgres:
image: postgres:16
environment:
POSTGRES_DB: persistent_agent
POSTGRES_USER: agent
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- pgdata:/var/lib/postgresql/data
redis:
image: redis:7-alpine
command: ["redis-server", "--appendonly", "yes"]
api:
build: .
command: uvicorn app.main:app --host 0.0.0.0 --port 8000
env_file: .env
depends_on: [postgres, redis]
worker:
build: .
command: python -m worker.main
env_file: .env
restart: unless-stopped
depends_on: [postgres, redis]
scheduler:
build: .
command: python -m scheduler.main
env_file: .env
restart: unless-stopped
depends_on: [postgres, redis]
volumes:
pgdata:
部署时按以下顺序执行:
- 创建
.env,只写环境变量名与本地密钥,不把真实 API Key 提交到 Git。 - 启动 PostgreSQL 与 Redis,执行数据库迁移并创建最小权限数据库账户。
- 启动 API、Worker 和 Scheduler,创建一条只读测试任务。
- 人为终止 Worker,确认租约过期后新 Worker 能从最后检查点继续,而不是重做已成功的工具调用。
- 重复投递同一事件,确认幂等键阻止重复副作用。
- 创建需要发布的测试任务,确认状态停在
waiting_approval,未审批前不会调用发布工具。 - 分别测试批准、拒绝、审批过期和参数被修改四种路径。
- 设置单任务步骤上限、Token/金额预算、工具超时、重试上限与死信告警。
- 接入日志、指标和告警,至少监控队列积压、租约超时、失败率、审批等待时长和预算消耗。
- 完成备份恢复演练、记忆删除测试和安全评审后,才允许接入真实生产工具。
实际工作流示例:AI Stack Nav 持续内容 Agent
该 Agent 的目标不是自动把未经核验的文章发到网站,而是全天候发现更新、准备草稿、等待编辑审批并持续维护台账。
每天 08:00,Scheduler 触发 collect_ai_updates;研究 Worker 只访问官方博客、文档、GitHub 和可信媒体,记录事件发生时间与发布时间;选题 Agent 根据重复度、搜索价值和资料包潜力打分;写作 Agent 生成 Markdown、SEO 信息与三图元数据;图片任务独立入队;WordPress 工具仅创建 draft;编辑审批后才允许发布。
若某官方页面暂时无法访问,任务进入 retry_scheduled,采用指数退避与随机抖动。超过最大重试次数后转入死信队列并通知人工,而不是让模型根据记忆补齐“可能的价格”。发布后,Agent 可在 24 小时后主动检查图片、链接和结构,但任何删除或覆盖操作仍需审批。
这一流程特别适合与现有 n8n 配合:n8n 负责 SaaS 连接、通知和简单路由;Persistent Agent Runtime 负责跨天状态、检查点、预算和审批。两者不是互相替代关系。
对比与选型建议
| 方案 | 优点 | 局限 | 适用场景 |
|---|---|---|---|
| Cron+单脚本 | 简单、成本低 | 崩溃恢复、审批和长期状态弱 | 每次独立的只读任务 |
| n8n 工作流 | 连接器丰富、可视化 | 超长状态与复杂 Agent 循环需额外设计 | 内容和办公自动化 |
| 队列+自研状态机 | 控制精细、易贴合业务 | 需要自行实现大量可靠性机制 | 中等复杂生产系统 |
| OpenAI Agents SDK+DBOS/Dapr/Temporal | Agent、审批与耐久执行组合清晰 | 学习与运维成本更高 | 长任务、人工门禁、企业项目 |
| Temporal 原生编排 | 恢复、定时器和事件历史成熟 | Workflow 确定性约束与基础设施复杂 | 高价值、跨天跨月流程 |
小团队可从 PostgreSQL+Redis+Python Worker 开始;当任务链跨多天、包含大量等待、需要强恢复保证时,再引入 Temporal 或其他耐久编排框架。不要因为“Agent”概念流行,就把本来一个 Cron 脚本能完成的任务复杂化。
风险、限制与故障排查
- 无限循环: 为单任务设置
max_steps、截止时间和预算;连续产生相同动作时立即暂停。 - 重复副作用: 所有写操作使用业务幂等键;重试前先查询工具侧结果。
- 记忆污染: 保存来源与置信度,推断不得覆盖确认事实;提供更正和删除入口。
- Prompt Injection: 外部网页、邮件和文档均视为不可信数据,不能改变系统权限或审批策略。
- 权限扩大: 每个工具使用独立服务账户与最小作用域,禁止把管理员凭据交给通用 Agent。
- 审批绕过: 策略在 Tool Gateway 强制执行,不能只靠系统提示词要求模型“记得审批”。
- 预算失控: 统计模型、搜索、图像和第三方工具成本;达到阈值后进入等待审批,而不是继续重试。
- 状态不兼容: 检查点保存 schema 与代码版本;升级时提供迁移策略,旧运行必要时保持旧 Worker。
- 隐私与保留: 敏感记忆加密、分租户隔离,设置保留期限,并验证删除是否覆盖索引和备份生命周期。
常见故障判断:任务重复执行,先查事件幂等键与 Outbox;任务永久卡住,查租约、wake_at、审批过期与死信队列;重启后无法恢复,查检查点版本和序列化兼容;Agent 忘记决定,查记忆是否未写入、检索过滤是否过严或召回内容是否超出 Token 预算。
事实依据与来源
本文关于 OpenAI Agents SDK 审批暂停、RunState 序列化与恢复,来自官方 Human-in-the-loop、Results 和 Running agents 文档;关于 Sessions 自动维护跨运行会话历史,来自官方 Sessions 文档;关于 MCP 工具可配置审批策略,来自 Agents SDK MCP 文档。关于事件历史重放、Worker 故障恢复、长等待与 Signal 修正,来自 Temporal 官方文档。
本文中的 PostgreSQL 表结构、Redis 队列、租约、Outbox、记忆分层、风险等级、AI Stack Nav 内容流程和 Docker Compose 属于参考实现与实施建议,不代表 OpenAI 或 Temporal 官方唯一架构。成本、性能、最大并发和恢复时间必须根据实际模型、数据库、云平台与任务负载测试。本文未宣称某框架能保证模型输出正确,也未把耐久执行等同于业务上的“恰好一次”副作用。
内容核验日期:2026 年 09 月 01 日。
FAQ
Persistent AI Agent 是什么?
它是能把任务状态持久化、根据事件主动继续、跨进程恢复并在敏感动作前等待人工审批的 Agent 系统。核心不是模型持续在线,而是运行时能够保存和恢复任务。
24 小时运行是否会持续消耗 Token?
正确设计不会。等待期间任务保存在数据库或耐久工作流中,不调用模型;只有触发器到期、外部事件到达或审批完成后,Worker 才执行下一个有限步骤并产生相应费用。
长期记忆和聊天记录有什么区别?
聊天记录只是会话历史。长期记忆还包括结构化事实、项目决定、任务状态和可检索知识,并需要来源、置信度、权限、有效期、更正及删除机制。
Redis 可以单独保存所有任务吗?
不建议。Redis 可用于队列、缓存和短期租约,但核心任务、事件、检查点、审批和审计记录应保存在具有可靠持久化与事务能力的数据库或耐久工作流系统中。
是否必须使用 Temporal?
不是。小规模项目可以使用 PostgreSQL、Redis 和自研 Worker;当流程跨天、长时间等待、故障恢复和事件历史要求提高时,Temporal、Dapr 或 DBOS 等耐久编排方案更有价值。
哪些操作必须人工审批?
公开发布、发送外部邮件、付款、删除数据、修改权限、生产数据库写入和任何难以撤销的动作应默认审批。高风险操作可要求双人审批或完全禁用。
Agent 重启后如何从原处继续?
每一步结束后保存状态检查点与事件。新 Worker 获取到任务后读取检查点,恢复运行上下文,并用幂等键确认已成功的工具调用不会重复执行。
如何防止 Agent 无限主动执行?
设置最大步骤数、总截止时间、每日预算、单工具频率、连续相同动作检测和人工暂停开关。主动触发必须来自明确规则或事件,不能让模型自行无限轮询。
人工审批能否只写在系统提示词里?
不能。提示词可能被忽略或遭 Prompt Injection。审批必须由 Tool Gateway 或运行时策略强制执行,在调用真实工具之前阻断并持久化状态。
参考来源
- OpenAI Agents SDK:Human-in-the-loop
- OpenAI Agents SDK:Running agents 与耐久执行集成
- OpenAI Agents SDK:Sessions
- OpenAI Agents SDK:MCP 与工具审批
- Temporal:Workflow Execution overview
- Temporal:How Temporal works
- Temporal:Resumable Activity
工具选型与提示词资料
适合阅读工具评测、工具推荐、对比测评类文章后继续转化。