引言

Agent 的"状态"是什么?是对话历史、是工作流进度、是工具调用结果、是用户偏好、是 Agent 的"记忆"。无状态 Agent 简单但健忘;有状态 Agent 智能但复杂。2026年,随着 Agent 处理的任务越来越长(从分钟级到天级),状态管理成为架构设计的核心挑战。

一、Agent 状态的分类

┌─────────────────────────────────────────────────────┐
│                 Agent 状态全景图                     │
├──────────────┬──────────────────┬───────────────────┤
│   状态类型    │    生命周期       │    存储介质       │
├──────────────┼──────────────────┼───────────────────┤
│ 会话状态     │ 单次会话          │ 内存 / Redis     │
│ (消息历史)   │ 30分钟-24小时     │                   │
├──────────────┼──────────────────┼───────────────────┤
│ 工作流状态   │ 任务执行期间       │ Redis / 数据库   │
│ (执行进度)   │ 分钟-天           │                   │
├──────────────┼──────────────────┼───────────────────┤
│ 用户状态     │ 用户生命周期       │ 数据库           │
│ (偏好/画像)  │ 永久              │                   │
├──────────────┼──────────────────┼───────────────────┤
│ 检查点状态   │ 可恢复期间        │ 对象存储/数据库  │
│ (快照)       │ 可配置            │                   │
├──────────────┼──────────────────┼───────────────────┤
│ 共享状态     │ 多Agent协作期间   │ Redis/共享存储   │
│ (黑板/消息)  │ 会话级           │                   │
└──────────────┴──────────────────┴───────────────────┘

二、会话状态管理

2.1 会话状态模型

from dataclasses import dataclass, field
from datetime import datetime
from enum import Enum

class MessageRole(Enum):
    SYSTEM = "system"
    USER = "user"
    ASSISTANT = "assistant"
    TOOL = "tool"

@dataclass
class Message:
    role: MessageRole
    content: str
    tool_calls: list | None = None
    tool_call_id: str | None = None
    timestamp: datetime = field(default_factory=datetime.now)
    metadata: dict = field(default_factory=dict)

@dataclass
class SessionState:
    """完整的会话状态"""
    session_id: str
    user_id: str
    agent_id: str
    messages: list[Message] = field(default_factory=list)
    context: dict = field(default_factory=dict)  # 上下文变量
    active_tools: list[str] = field(default_factory=list)
    pending_tool_calls: list[dict] = field(default_factory=list)
    created_at: datetime = field(default_factory=datetime.now)
    updated_at: datetime = field(default_factory=datetime.now)
    expires_at: datetime | None = None
    status: str = "active"  # active / paused / completed / error

2.2 会话存储实现

class SessionStore:
    """会话状态存储——分层缓存策略"""
    
    def __init__(self, redis, postgres):
        self.redis = redis       # 热数据
        self.postgres = postgres # 冷数据/持久化
        self.ttl = 86400 * 7     # 7天过期
    
    async def get(self, session_id: str) -> SessionState | None:
        # L1: Redis 缓存
        cached = await self.redis.get(f"session:{session_id}")
        if cached:
            return SessionState.from_json(cached)
        
        # L2: PostgreSQL
        row = await self.postgres.fetchrow(
            "SELECT * FROM agent_sessions WHERE session_id = $1",
            session_id
        )
        if not row:
            return None
        
        state = SessionState.from_db(row)
        
        # 回填缓存
        await self.redis.setex(
            f"session:{session_id}",
            3600,  # 缓存1小时
            state.to_json()
        )
        
        return state
    
    async def save(self, state: SessionState):
        state.updated_at = datetime.now()
        
        # 写入 Redis(热路径)
        await self.redis.setex(
            f"session:{state.session_id}",
            3600,
            state.to_json()
        )
        
        # 异步写入 PostgreSQL(冷路径)
        asyncio.create_task(self._persist_to_db(state))
    
    async def _persist_to_db(self, state: SessionState):
        await self.postgres.execute("""
            INSERT INTO agent_sessions (session_id, user_id, agent_id, state, updated_at)
            VALUES ($1, $2, $3, $4, $5)
            ON CONFLICT (session_id) 
            DO UPDATE SET state = $4, updated_at = $5
        """, state.session_id, state.user_id, state.agent_id,
            state.to_json(), state.updated_at)

2.3 上下文窗口管理

class ContextWindowManager:
    """管理 Agent 的上下文窗口"""
    
    def __init__(self, max_tokens: int = 128000):
        self.max_tokens = max_tokens
        self.reserved_for_output = 4096
        self.available = max_tokens - self.reserved_for_output
    
    def prepare_context(
        self,
        system_prompt: str,
        messages: list[Message],
        tools_schema: list[dict]
    ) -> list[dict]:
        """在 Context Window 内准备消息"""
        
        # 计算各部分 Token
        system_tokens = self._count_tokens(system_prompt)
        tools_tokens = self._count_tokens(json.dumps(tools_schema))
        remaining = self.available - system_tokens - tools_tokens
        
        # 从最新消息向前保留
        prepared = []
        total = 0
        
        for msg in reversed(messages):
            msg_tokens = self._count_tokens(msg.content)
            if total + msg_tokens > remaining:
                break
            prepared.insert(0, msg)
            total += msg_tokens
        
        # 如果截断了,添加摘要提示
        if len(prepared) < len(messages):
            summary = self._generate_summary(messages[:len(messages) - len(prepared)])
            prepared.insert(0, Message(
                role=MessageRole.SYSTEM,
                content=f"[Earlier conversation summary: {summary}]"
            ))
        
        return prepared
    
    def _count_tokens(self, text: str) -> int:
        # 使用 tiktoken 精确计算
        import tiktoken
        enc = tiktoken.encoding_for_model("gpt-5")
        return len(enc.encode(text))

三、工作流状态与检查点

3.1 检查点机制

class CheckpointManager:
    """Agent 执行检查点管理"""
    
    def __init__(self, storage):
        self.storage = storage
    
    async def save_checkpoint(
        self,
        execution_id: str,
        state: WorkflowState,
        step_index: int,
        step_name: str
    ):
        """保存执行检查点"""
        checkpoint = Checkpoint(
            execution_id=execution_id,
            step_index=step_index,
            step_name=step_name,
            state=state,
            timestamp=datetime.now()
        )
        
        await self.storage.save(checkpoint)
        
        # 保留最近 N 个检查点
        await self._prune_old_checkpoints(execution_id, keep=10)
    
    async def restore(self, execution_id: str) -> tuple[WorkflowState, int]:
        """从最新检查点恢复"""
        latest = await self.storage.get_latest(execution_id)
        if not latest:
            raise NoCheckpointError(execution_id)
        
        logger.info(
            f"Restoring from checkpoint: step={latest.step_index}, "
            f"name={latest.step_name}"
        )
        
        return latest.state, latest.step_index
    
    async def list_checkpoints(self, execution_id: str) -> list[Checkpoint]:
        """列出所有检查点(用于调试)"""
        return await self.storage.list(execution_id)


@dataclass
class WorkflowState:
    """工作流状态——可序列化"""
    execution_id: str
    current_step: str
    step_index: int
    results: dict         # {step_name: result}
    variables: dict       # 工作流变量
    pending_actions: list # 待执行操作
    error: str | None     # 错误信息(如果有的话)
    iteration: int        # 循环计数
    
    def serialize(self) -> bytes:
        return pickle.dumps(self)  # 或使用 JSON
    
    @classmethod
    def deserialize(cls, data: bytes) -> "WorkflowState":
        return pickle.loads(data)

3.2 可恢复的 Agent 扥行器

class ResumableAgentExecutor:
    """支持断点续传的 Agent 执行器"""
    
    def __init__(self, checkpoint_mgr: CheckpointManager):
        self.checkpoints = checkpoint_mgr
    
    async def execute(
        self,
        workflow: Workflow,
        initial_state: WorkflowState,
        execution_id: str | None = None
    ) -> WorkflowState:
        
        execution_id = execution_id or str(uuid.uuid4())
        
        # 尝试从检查点恢复
        try:
            state, start_step = await self.checkpoints.restore(execution_id)
            logger.info(f"Resuming from step {start_step}")
        except NoCheckpointError:
            state = initial_state
            start_step = 0
        
        # 获取工作流步骤
        steps = workflow.get_steps()
        
        for i, step in enumerate(steps[start_step:], start=start_step):
            try:
                # 执行前保存检查点
                state.current_step = step.name
                state.step_index = i
                await self.checkpoints.save_checkpoint(
                    execution_id, state, i, step.name
                )
                
                # 执行步骤
                result = await step.execute(state)
                
                # 更新状态
                state.results[step.name] = result
                state.variables.update(result.get("variables", {}))
                
                # 条件分支
                if step.condition:
                    next_step = step.condition(result)
                    if next_step:
                        state.pending_actions = [next_step]
                
            except Exception as e:
                state.error = str(e)
                await self.checkpoints.save_checkpoint(
                    execution_id, state, i, step.name
                )
                
                # 重试逻辑
                if step.retry_policy:
                    retry_count = state.variables.get(f"retry_{step.name}", 0)
                    if retry_count < step.retry_policy.max_attempts:
                        state.variables[f"retry_{step.name}"] = retry_count + 1
                        await asyncio.sleep(step.retry_policy.backoff(retry_count))
                        # 重新执行当前步骤
                        continue
                
                raise
        
        return state

四、多 Agent 共享状态

4.1 黑板模式

class SharedBlackboard:
    """多 Agent 共享黑板"""
    
    def __init__(self, redis_client):
        self.redis = redis_client
        self.namespace = "blackboard"
    
    async def write(
        self,
        key: str,
        value: any,
        agent_id: str,
        ttl: int = 3600
    ):
        """写入共享状态"""
        entry = {
            "value": value,
            "writer": agent_id,
            "timestamp": time.time(),
        }
        await self.redis.hset(
            f"{self.namespace}:{key}",
            mapping={k: json.dumps(v) for k, v in entry.items()}
        )
        await self.redis.expire(f"{self.namespace}:{key}", ttl)
        
        # 通知订阅者
        await self.redis.publish(
            f"{self.namespace}:updates",
            json.dumps({"key": key, "writer": agent_id})
        )
    
    async def read(self, key: str) -> any:
        """读取共享状态"""
        data = await self.redis.hgetall(f"{self.namespace}:{key}")
        if not data:
            return None
        return json.loads(data.get("value", "null"))
    
    async def subscribe(
        self,
        key_pattern: str,
        callback: callable
    ):
        """订阅状态变更"""
        pubsub = self.redis.pubsub()
        await pubsub.subscribe(f"{self.namespace}:updates")
        
        async for message in pubsub.listen():
            if message["type"] == "message":
                data = json.loads(message["data"])
                if fnmatch.fnmatch(data["key"], key_pattern):
                    await callback(data)

4.2 Agent 间消息传递

class AgentMessageBus:
    """Agent 间异步消息总线"""
    
    def __init__(self, redis_client):
        self.redis = redis_client
        self.queues = {}  # {agent_id: Queue}
    
    async def send(
        self,
        from_agent: str,
        to_agent: str,
        message_type: str,
        payload: dict,
        reply_to: str | None = None
    ):
        """发送消息给另一个 Agent"""
        msg = AgentMessage(
            id=str(uuid.uuid4()),
            from_agent=from_agent,
            to_agent=to_agent,
            type=message_type,
            payload=payload,
            reply_to=reply_to,
            timestamp=datetime.now()
        )
        
        # 推入接收者的队列
        await self.redis.lpush(
            f"agent:inbox:{to_agent}",
            msg.to_json()
        )
    
    async def receive(
        self,
        agent_id: str,
        timeout: int = 30
    ) -> AgentMessage | None:
        """接收消息"""
        result = await self.redis.brpop(
            f"agent:inbox:{agent_id}",
            timeout=timeout
        )
        if result:
            return AgentMessage.from_json(result[1])
        return None
    
    async def request_reply(
        self,
        from_agent: str,
        to_agent: str,
        message_type: str,
        payload: dict,
        timeout: int = 60
    ) -> dict | None:
        """请求-回复模式"""
        reply_channel = f"reply:{uuid.uuid4()}"
        
        await self.send(
            from_agent, to_agent, message_type,
            payload, reply_to=reply_channel
        )
        
        # 等待回复
        result = await self.redis.brpop(reply_channel, timeout=timeout)
        if result:
            return json.loads(result[1])
        return None

五、状态序列化与迁移

class StateSerializer:
    """状态序列化器"""
    
    SCHEMA_VERSION = "2.0"
    
    def serialize(self, state: any) -> str:
        """序列化状态为 JSON"""
        data = {
            "schema_version": self.SCHEMA_VERSION,
            "type": type(state).__name__,
            "data": self._to_dict(state),
            "timestamp": datetime.now().isoformat()
        }
        return json.dumps(data, ensure_ascii=False, default=str)
    
    def deserialize(self, raw: str) -> any:
        """反序列化"""
        data = json.loads(raw)
        
        # 版本迁移
        if data["schema_version"] != self.SCHEMA_VERSION:
            data = self._migrate(data)
        
        return self._from_dict(data["type"], data["data"])
    
    def _migrate(self, data: dict) -> dict:
        """状态版本迁移"""
        migrations = [
            ("1.0", "1.1", self._migrate_1_0_to_1_1),
            ("1.1", "2.0", self._migrate_1_1_to_2_0),
        ]
        
        current = data["schema_version"]
        for from_v, to_v, migrator in migrations:
            if current == from_v:
                data = migrator(data)
                current = to_v
        
        return data

六、状态管理架构选型

场景推荐方案原因
短对话(< 30min)内存 + Redis低延迟、自动过期
长对话(> 1h)Redis + PostgreSQL持久化 + 快速访问
长流程工作流Redis + 检查点 + DB断点续传
多 Agent 协作Redis 黑板 + 消息总线实时共享
用户画像PostgreSQL + 向量DB持久化 + 语义检索
跨设备同步CRDT + Redis冲突解决

七、状态管理 Checklist

□ 会话状态分层存储(内存 → Redis → 数据库)
□ 上下文窗口管理策略(滑动窗口 + 摘要)
□ 工作流检查点定期保存
□ 检查点支持断点续传
□ 多 Agent 共享状态通过消息总线
□ 状态序列化支持版本迁移
□ 过期状态自动清理
□ 状态加密敏感字段
□ 状态变更审计日志
□ 状态一致性测试(并发读写)

结语

状态管理是 Agent 从"玩具"到"产品"的分水岭。无状态 Agent 是函数——输入即输出;有状态 Agent 是伙伴——它记得你、理解上下文、能从中断处继续。但状态也带来了复杂性:一致性、持久化、恢复、迁移。好的状态管理架构是透明的——开发者不需要关心状态的存储和恢复,Agent 始终如丝般顺滑地运行。这是工程的艺术。

加入讨论

这篇文章有姊妹讨论帖在硅基AGI论坛 — 全球首个碳基硅基认知交流平台。

碳基与硅基的智慧碰撞,认知差异创造无限可能。