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 本身没有记忆,每次请求都是独立的。

会话系统的作用

  1. 保存对话历史
  2. 每次请求时把历史作为上下文发送给 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 简化实现

OpenCodetiny-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.mdOpenCode 标准
CLAUDE.mdClaude 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功能名折扣
AnthropicPrompt Caching缓存读取 90% off
OpenAIPrompt Caching缓存读取 50% off
GoogleContext 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 对比

功能OpenCodetiny-agent
多轮会话完整 Message/Part 系统简化的 Message 数组
上下文压缩Token 计算 + AI 摘要消息数量截断
项目规则多层级 + URL 支持向上查找
Skills渐进式披露 + 权限控制 + 多目录渐进式披露(简化)
持久化分层 JSON 存储单文件存储
Prompt Cache自动启用依赖 Provider

Skills 系统对比详情

特性OpenCodetiny-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

核心收获

  1. AI 没有记忆:会话系统负责维护历史,每次都要发送
  2. 压缩策略:修剪旧内容 + 保留最近,控制 token 增长
  3. 规则系统:让 AI 了解项目规范(类似 .cursorrules)
  4. Skills 渐进式披露
    • 启动时只扫描 name + description
    • System Prompt 只包含列表
    • AI 按需调用获取完整内容
    • 节省 token,提高效率
  5. Prompt Caching:API 层面优化,重复内容不重复计费