现在位置: 首页 > Skills 教程 > 正文

Skills 上下文与状态管理

Claude 的每次 API 调用都是无状态的,它不会自动记住上一次会话的内容。

但在一次连续对话中,所有历史消息都在上下文窗口里。理解这一点,能帮助你写出在对话中表现稳定的 Skill。


Skills 的状态存在于哪里

状态类型 存储位置 有效范围
对话历史 上下文窗口 当前会话,关闭后消失
中间文件 /home/claude/ 当前会话,任务完成后可能清除
输出文件 /mnt/user-data/outputs/ 持久化,用户可下载
已安装的 Skill /mnt/skills/ 跨会话持久化

Skills 本身不具备数据库或持久存储能力。需要跨会话保存的数据,应由用户自己保存(如下载文件),或写入持久化输出目录。


在 SKILL.md 中管理多轮对话状态

对于需要多轮交互的 Skill,应在 SKILL.md 中明确定义对话状态的流转逻辑。

实例

## 多轮交互流程

本 Skill 分三个阶段运行:

### 阶段一:信息收集
询问用户提供以下信息:
1. 数据文件路径
2. 分析目标

在获得全部信息前,不执行分析。
将已收集的信息以列表形式展示,告知用户还缺少什么。

### 阶段二:确认执行
收集完成后,展示执行计划,等待用户确认:
> 我将对 {文件名} 执行 {分析目标},预计需要约 {时间} 秒。确认继续吗?

### 阶段三:执行并输出
用户确认后执行,实时告知进度,完成后输出结果。

如果用户在任意阶段说"重新开始",清除当前收集的信息,回到阶段一。

使用文件保存中间状态

对于复杂的多步骤任务,可以将中间状态写入 JSON 文件,实现步骤间的状态传递。

实例

# 文件路径:scripts/state_manager.py
import json
import os
from datetime import datetime

# 状态文件存储路径(当前会话工作目录)
STATE_FILE = "/home/claude/skill_state.json"

def save_state(state: dict) -> None:
    """保存当前执行状态到文件"""
    state["updated_at"] = datetime.now().isoformat()
    with open(STATE_FILE, "w", encoding="utf-8") as f:
        json.dump(state, f, ensure_ascii=False, indent=2)
    print(f"状态已保存:{STATE_FILE}")

def load_state() -> dict:
    """加载上次保存的状态,若不存在则返回初始状态"""
    if not os.path.exists(STATE_FILE):
        return {
            "phase":      "collecting",  # 当前阶段:collecting / confirming / executing / done
            "file_path":  None,
            "target":     None,
            "result":     None,
            "created_at": datetime.now().isoformat()
        }
    with open(STATE_FILE, "r", encoding="utf-8") as f:
        return json.load(f)

def clear_state() -> None:
    """清除状态(用于"重新开始"场景)"""
    if os.path.exists(STATE_FILE):
        os.remove(STATE_FILE)
    print("状态已清除,重新开始")

# 使用示例
if __name__ == "__main__":
    # 加载或初始化状态
    state = load_state()
    print(f"当前阶段:{state['phase']}")

    # 更新状态:已收集文件路径
    state["file_path"] = "/mnt/user-data/uploads/runoob_data.csv"
    state["phase"]     = "confirming"
    save_state(state)
状态已保存:/home/claude/skill_state.json
当前阶段:collecting
状态已保存:/home/claude/skill_state.json

防止上下文污染

当用户在同一对话中多次触发 Skill,历史对话中的旧参数可能"污染"新的执行。

在 SKILL.md 中明确规定优先级,可以避免这类问题。

实例

## 参数优先级规则

同一次对话中若存在多组参数,按以下优先级处理:

1. **用户最新消息中明确指定的参数** → 最高优先级,始终使用
2. **本次请求中上传的文件** → 高优先级
3. **对话历史中提到的参数** → 低优先级,仅在当前消息未指定时使用
4. **Skill 定义的默认值** → 兜底

若对参数来源有疑问,在执行前向用户确认:"我将使用 runoob_v2.csv(您刚上传的文件),而非之前的 runoob_v1.csv,是否正确?"

上下文长度与性能的关系

随着对话变长,上下文窗口中的内容越来越多,Claude 处理的成本也会增加。

对于长时间运行的多轮 Skill,应当注意以下优化策略:

策略 做法 效果
避免重复输出大块内容 引用之前输出的文件路径,而非重新输出内容 减少上下文占用
使用文件传递中间数据 将大型数据集写入文件,对话中只传递路径 避免大数据占满上下文
及时告知用户阶段性完成 每个阶段结束后明确说"第一步完成" 让用户知道进度,减少追问

上下文窗口是有限的资源。Skill 中传递的数据量越大,剩余给推理和生成的空间就越少,响应质量可能下降。对于大文件,始终通过文件路径而非内容传递。