OpenCode 学习笔记 03:会话与记忆系统
多轮对话、上下文压缩、项目规则与 Skills
January 19, 2026·8 min read·Yimin
#AI#Agent#OpenCode#TypeScript#Session#Memory
AI Agent 不只是单次问答,它需要"记住"对话历史、理解项目规范、调用可复用知识。
本篇目标
| 目标 | 实现 |
|---|---|
| 多轮会话 | ✅ tiny-agent 实现 |
| 上下文压缩 | ✅ 简化实现 |
| 项目规则 | ✅ tiny-agent 实现 |
| Skills 系统 | ✅ tiny-agent 实现 |
| 会话持久化 | ✅ tiny-agent 实现 |
一、多轮会话
1.1 为什么需要会话?
用户:读取 src/index.ts
AI:[调用 read 工具] 文件内容是...
用户:把第 10 行改成 xxx
AI:[调用 edit 工具] 已修改 src/index.ts ← AI 怎么知道是哪个文件?
关键洞察:AI 本身没有记忆,每次请求都是独立的。
会话系统的作用:
- 保存对话历史
- 每次请求时把历史作为上下文发送给 AI
1.2 OpenCode 的会话架构
┌─────────────────────────────────────────┐
│ Session │
│ ┌─────────────────────────────────────┐│
│ │ Info: id, title, time, projectID ││
│ └─────────────────────────────────────┘│
│ ┌─────────────────────────────────────┐│
│ │ Messages[] ││
│ │ ├─ User Message ││
│ │ │ └─ Parts (text, file, agent) ││
│ │ └─ Assistant Message ││
│ │ └─ Parts (text, tool, reasoning)││
│ └─────────────────────────────────────┘│
└─────────────────────────────────────────┘
| 概念 | 说明 |
|---|---|
| Session | 一次完整的对话,包含元信息和消息列表 |
| Message | 一条消息(User 或 Assistant) |
| Part | 消息的组成部分(文本、文件、工具调用等) |
1.3 消息转换流程
用户输入 存储格式 发送给 AI
│ │ │
▼ ▼ ▼
"读取文件" → MessageV2.User → toModelMessage() → ModelMessage
关键:存储格式和 AI SDK 格式不同,需要转换。
二、上下文压缩(Compaction)
2.1 问题:对话太长了
Token 限制
┌────────────────────────────────────────┐
│ ██████████████████████████████░░░░░░░░ │ 75% 已用
│ │
│ 历史消息占用太多 token │
│ 新消息没有空间了! │
└────────────────────────────────────────┘
2.2 OpenCode 的压缩策略
| 阶段 | 策略 | 说明 |
|---|---|---|
| 1. 检测 | isOverflow() | 计算 token 是否超限 |
| 2. 修剪 | prune() | 清除旧工具调用的输出(保留最近 40K token) |
| 3. 摘要 | process() | 调用 AI 生成对话摘要 |
检测溢出 → prune(修剪)→ 生成摘要 → 继续对话
│ │ │
▼ ▼ ▼
token > limit 清除旧结果 AI 总结历史
2.3 tiny-agent 简化实现
| OpenCode | tiny-agent |
|---|---|
| Token 计算 | 消息数量计算 |
| AI 生成摘要 | 简单截断 |
| 保护 skill 工具 | 不区分 |
策略:消息超过 30 条时,保留最近 80%。
三、项目规则
3.1 类似 .cursorrules
项目根目录
├── AGENTS.md ← OpenCode 规则
├── CLAUDE.md ← Claude Code 规则
├── .cursorrules ← Cursor 规则
├── src/
└── ...
3.2 规则层级
优先级
全局规则 ↓ 低
~/.config/opencode/AGENTS.md
│
▼
项目规则 ↓ 中
/project/AGENTS.md
│
▼
子目录规则 ↓ 高
/project/src/AGENTS.md
3.3 OpenCode 支持的规则文件
| 文件 | 来源 |
|---|---|
AGENTS.md | OpenCode 标准 |
CLAUDE.md | Claude Code 标准 |
CONTEXT.md | 已废弃 |
| URL | 支持 http:// 远程规则 |
3.4 tiny-agent 实现
支持的规则文件:AGENTS.md, CLAUDE.md, .cursorrules
查找顺序:当前目录 → 向上查找到 git 根目录 → 全局目录
四、Skills 系统
4.1 什么是 Skill?
Skill = 可复用的知识模块
.skills/git-commit/SKILL.md
┌─────────────────────────────────────────┐
│ --- │
│ name: git-commit │
│ description: 帮助生成 git commit 消息 │
│ --- │
│ │
│ 当用户请求 git commit 时: │
│ 1. 运行 git diff --cached │
│ 2. 分析变更内容 │
│ 3. 生成符合 Conventional Commits 的消息 │
└─────────────────────────────────────────┘
4.2 Skill vs 规则
| 特性 | 项目规则 (AGENTS.md) | Skills (SKILL.md) |
|---|---|---|
| 加载时机 | 启动时全量加载 | 按需加载 |
| 作用范围 | 整个会话 | 特定任务 |
| 调用方式 | 自动注入 system prompt | 通过 skill 工具 |
| Token 消耗 | 每次都发 | 需要时才发 |
4.3 渐进式披露(Progressive Disclosure)
问题:如果把所有 skill 内容都放进 System Prompt,会浪费大量 token。
解决方案:渐进式披露
┌────────────────────────────────────────────────────────────┐
│ 1. 启动时:扫描所有 SKILL.md,只提取 name + description │
└────────────────────────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────────┐
│ 2. System Prompt 只包含 skills 列表(节省 token) │
│ │
│ <available-skills> │
│ - git-commit: 帮助生成 git commit 消息 │
│ - code-review: 帮助进行代码审查 │
│ - debug: 帮助调试和定位问题 │
│ </available-skills> │
└────────────────────────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────────┐
│ 3. 用户: "帮我 commit" │
│ AI 看到列表,决定需要 git-commit skill │
│ AI 调用: skill("git-commit") │
└────────────────────────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────────┐
│ 4. 工具返回完整 SKILL.md 内容 │
│ AI 根据 skill 内容执行任务 │
└────────────────────────────────────────────────────────────┘
4.4 Token 对比
| 方式 | System Prompt Token | 问题 |
|---|---|---|
| 全量披露 | 6 个 skill × ~500 字 = 3000+ | 每次都浪费 |
| 渐进式披露 | 6 个 skill × ~20 字 = 120 | ✅ 按需加载 |
4.5 多轮对话中的 Skill
第 1 轮:
User: "帮我 commit"
AI: 调用 skill("git-commit") → 获取 500 token 内容
AI: 根据 skill 回复
第 2 轮:
History 包含: skill 结果 (500 token) ← 在历史里
User: "换成英文格式"
AI: 直接基于历史中的 skill 回复(不需要再调用)
第 3 轮:
User: "再帮我 review 代码"
AI: 调用 skill("code-review") → 新的 skill
注意:skill 内容会留在对话历史中,所以对话越长,token 越多,需要 Compaction。
4.6 tiny-agent 实现
目录结构:
.skills/
├── git-commit/SKILL.md # 生成 commit 消息
├── code-review/SKILL.md # 代码审查
├── refactor/SKILL.md # 代码重构
├── debug/SKILL.md # 调试定位
├── test/SKILL.md # 编写测试
└── new-feature/SKILL.md # 新功能开发流程
启动时输出:
📋 加载项目规则: AGENTS.md
🎯 发现 6 个 skills: code-review, debug, git-commit, new-feature, refactor, test
使用方式:
You: 帮我 commit
AI: [调用 skill: git-commit] 读取指导...
AI: 根据 skill 指导生成 commit 消息
五、会话持久化
5.1 OpenCode 的存储设计
~/.local/share/opencode/storage/
├── session/{projectID}/{sessionID}.json ← 会话元信息
├── message/{sessionID}/{messageID}.json ← 消息
└── part/{messageID}/{partID}.json ← 消息部分
特点:分层存储,方便增量更新
5.2 tiny-agent 简化实现
~/.tiny-agent/sessions/{sessionID}.json
特点:单文件存储,简单直接
| 命令 | 功能 |
|---|---|
save | 保存当前会话 |
load | 加载最近会话 |
history | 显示消息数量 |
clear | 清空会话 |
六、完整流程
┌─────────────────────────────────────────────────────────┐
│ 用户输入 │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ 1. 加载项目规则 (AGENTS.md / CLAUDE.md) │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ 2. 获取会话历史 + 检查是否需要压缩 │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ 3. 构建消息: [system, rules, history..., userInput] │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ 4. 调用 AI (可能调用 skill 工具) │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ 5. 保存结果到会话历史 │
└─────────────────────────────────────────────────────────┘
七、Prompt Caching(成本优化)
7.1 问题:重复发送 System Prompt
每次调用 AI 都要发送完整的 System Prompt:
调用 1: System Prompt (500 token) + User 1 → 付 500 token
调用 2: System Prompt (500 token) + User 2 → 又付 500 token
调用 3: System Prompt (500 token) + User 3 → 再付 500 token
累计成本很高!
7.2 Prompt Caching 是什么?
API 层面的优化:重复的前缀内容,只计费一次。
调用 1: System Prompt (500 token) → 付 500 token(写入缓存)
调用 2: System Prompt (缓存命中!) → 付 50 token(90% off)
调用 3: System Prompt (缓存命中!) → 付 50 token(90% off)
7.3 各家支持情况
| Provider | 功能名 | 折扣 |
|---|---|---|
| Anthropic | Prompt Caching | 缓存读取 90% off |
| OpenAI | Prompt Caching | 缓存读取 50% off |
| Context Caching | 需要手动管理 |
7.4 为什么这很重要?
| 场景 | 没有缓存 | 有缓存 |
|---|---|---|
| 长 System Prompt | 每次都付全价 | 首次全价,后续便宜 |
| 多轮对话 | 成本线性增长 | 成本增长放缓 |
| 固定上下文 | 浪费 | 高效 |
7.5 OpenCode 的应用
OpenCode 自动对 System Prompt 启用缓存,在返回的 usage 中可以看到:
首次调用:
cache_creation_input_tokens: 500 ← 写入缓存
后续调用:
cache_read_input_tokens: 500 ← 命中缓存(便宜 90%)
八、OpenCode vs tiny-agent 对比
| 功能 | OpenCode | tiny-agent |
|---|---|---|
| 多轮会话 | 完整 Message/Part 系统 | 简化的 Message 数组 |
| 上下文压缩 | Token 计算 + AI 摘要 | 消息数量截断 |
| 项目规则 | 多层级 + URL 支持 | 向上查找 |
| Skills | 渐进式披露 + 权限控制 + 多目录 | 渐进式披露(简化) |
| 持久化 | 分层 JSON 存储 | 单文件存储 |
| Prompt Cache | 自动启用 | 依赖 Provider |
Skills 系统对比详情
| 特性 | OpenCode | tiny-agent |
|---|---|---|
| 渐进式披露 | ✅ | ✅ |
| 权限控制 | ✅ 按 agent 过滤 | ❌ |
| 多目录扫描 | ✅ .opencode/, .claude/, ~/ | 单一 .skills/ |
| Feature Flag | ✅ 可禁用某类 skills | ❌ |
| 重复检测 | ✅ 同名冲突警告 | ❌ |
| 符号链接 | ✅ | ❌ |
| 错误事件 | ✅ Bus 广播 | ❌ |
九、测试方法
测试多轮对话
You: 读取 package.json
You: 这个项目叫什么名字? ← AI 应该记得
测试规则加载
# 创建 AGENTS.md 后重启
输出: 📋 加载项目规则: AGENTS.md
测试 Skills
# 创建 .skills/git-commit/SKILL.md 后
You: 帮我 commit 代码
AI: [调用 skill: git-commit]
测试持久化
You: save
You: exit
# 重启后
You: load
You: 我们刚才聊了什么?
测试 Debug 模式
You: debug ← 开启调试
📋 当前 System Prompt: ← 显示完整 prompt
...
<available-skills> ← 包含 skills 列表
- git-commit: ...
</available-skills>
十、总结
| 完成项 | 说明 |
|---|---|
| ✅ 多轮会话 | SessionManager 管理消息历史 |
| ✅ 上下文压缩 | 消息数量截断策略 |
| ✅ 项目规则 | 加载 AGENTS.md 等规则文件 |
| ✅ Skills | 渐进式披露 + 按需加载 |
| ✅ 持久化 | save/load 会话到文件 |
| ✅ Debug 模式 | 查看发送给 AI 的完整 prompt |
核心收获:
- AI 没有记忆:会话系统负责维护历史,每次都要发送
- 压缩策略:修剪旧内容 + 保留最近,控制 token 增长
- 规则系统:让 AI 了解项目规范(类似 .cursorrules)
- Skills 渐进式披露:
- 启动时只扫描 name + description
- System Prompt 只包含列表
- AI 按需调用获取完整内容
- 节省 token,提高效率
- Prompt Caching:API 层面优化,重复内容不重复计费