# 🍻 酒馆模式(Tavern)使用手册
**深夜小酒馆,老板娘倚着吧台等你。进来的人,她都记得——你爱喝什么、上次聊到哪、什么时候会脸红。**
[](https://space.bilibili.com/12644772)
[](https://opensource.org/licenses/MIT)
[](https://github.com/deepseek-ai/deepseek-harness)
---
## 📖 目录
- [⚡ 快速上手](#-快速上手)
- [环境要求](#环境要求)
- [一条命令启动](#一条命令启动)
- [✨ 功能概览](#-功能概览)
- [🔧 配置说明](#-配置说明)
- [config.json 配置项](#configjson-配置项)
- [自定义变量类型](#自定义变量类型)
- [变量表编辑器](#变量表编辑器)
- [🧠 记忆系统](#-记忆系统)
- [三层记忆架构](#三层记忆架构)
- [触发方式](#触发方式)
- [记忆写入流程](#记忆写入流程)
- [记忆衰减策略](#记忆衰减策略)
- [跨模式共享](#跨模式共享)
- [状态栏记忆区块](#状态栏记忆区块)
- [记忆 API](#记忆-api)
- [🖥️ 状态栏](#️-状态栏)
- [完整版](#完整版)
- [折叠展开](#折叠展开)
- [营业时长](#营业时长)
- [🩺 诊断面板](#-诊断面板)
- [❓ 常见问题](#-常见问题)
- [📋 默认配置速查](#-默认配置速查)
- [🏗️ 文件结构](#️-文件结构)
- [📚 相关文档](#-相关文档)
- [🤝 作者](#-作者)
---
## ⚡ 快速上手
### 环境要求
| 依赖 | 版本要求 | 说明 |
|------|----------|------|
| [Node.js](https://nodejs.org/) | ≥ 22.19.0 | DSH 引擎运行时 |
| [pnpm](https://pnpm.io/) | ≥ 11.7.0 | 包管理器(项目指定) |
| 模型 API Key | — | 在 DSH 设置中配置(SiliconFlow / NVIDIA 等) |
| [deepseek-harness](https://github.com/deepseek-ai/deepseek-harness) | ≥ 最新 commit | 宿主框架 |
### 一条命令启动
```bash
# 1. 构建项目(首次或代码变更后)
pnpm run build
# 2. 启动 DSH Web 服务
pnpm dsh web
```
启动成功后,浏览器访问 `http://localhost:3080`,左侧边栏底部点击 **🍻 酒馆模式** 即可进入。
> **📍 配置存储路径**:配置文件全部存储在项目当前目录的 `.dsh/.agent-presets/tavern/` 下,**不会写入 C 盘系统目录**。这符合「配置存当前目录、避免跨盘 junction」的约束。
---
## ✨ 功能概览
| 功能 | 说明 |
|------|------|
| 🍺 **纯对话体验** | 无代码、无工具的沉浸式角色扮演,AI 以老板娘身份自然对话 |
| 🧠 **记忆系统** | 自动记录客人的喜好与过往,下次进入仍记得你 |
| 📊 **状态栏** | 实时展示场景、时间、情绪、亲密度、好感度、信任度等状态 |
| 🎨 **立绘情绪系统** | 正方形立绘、居中破窗效果、情绪边框颜色随状态变化 |
| ⚙️ **自定义变量** | 可在酒馆设置中添加专属状态变量(计数器 / 进度条 / 文本) |
| 🎛️ **设置面板** | 酒馆名称、世界观、氛围、规则、记忆衰减等均可自定义 |
| 🩺 **诊断面板** | 一键展示 API 基址、配置来源、连接状态,报障有据可查 |
| 🔌 **工具调用** | `manage_tavern_state` 工具 + 服务端原子写的状态权威源 |
| 🌐 **跨模式记忆** | 全局记忆扫描器捕获 `【记忆】` 标记,标准模式下也能写入 |
---
## 🔧 配置说明
### config.json 配置项
配置文件路径:`.dsh/.agent-presets/tavern/config.json`
```json
{
"tavernName": "深夜小酒馆",
"worldBook": "",
"atmosphere": "",
"autoMemory": true,
"memoryDecay": "normal",
"greeting": "",
"rules": [],
"customStates": [
{ "key": "接客数", "label": "接客", "type": "counter", "def": "0" },
{ "key": "兴奋度", "label": "兴奋", "type": "meter", "def": "" }
],
"initialState": {
"scene": "深夜小酒馆吧台旁",
"time": "深夜",
"emotion": "平静",
"intensity": "适中",
"intimacy": 20,
"affection": 15,
"trust": 10
}
}
```
| 字段 | 类型 | 说明 |
|------|------|------|
| `tavernName` | string | 酒馆名称,默认「深夜小酒馆」 |
| `worldBook` | string | 世界设定(Markdown 文本,注入系统提示) |
| `atmosphere` | string | 氛围描述 |
| `greeting` | string | 开场白(AI 首次打招呼的参考) |
| `rules` | string[] | 必须遵守的规则列表 |
| `autoMemory` | boolean | 是否自动保存记忆(默认 `true`) |
| `memoryDecay` | string | 记忆衰减策略:`light` / `normal` / `heavy` |
| `customStates` | Array\<{key, label, type, def}\> | 自定义状态变量表 |
| `initialState` | object | 初始状态(scene / time / emotion / intimacy 等) |
### 自定义变量类型
| 类型 | 范围 | 用途 | 示例 |
|------|------|------|------|
| `counter` | ≥ 0 整数 | 计数型,支持 `+N` / `-N` 增量 | 接客数、送礼次数 |
| `meter` | 0~100 | 进度条型,数值化后整数化 | 兴奋度、醉意 |
| `text` | 任意文本 | 文本型,直接覆盖为新字符串 | 当前任务、地点 |
### 变量表编辑器
在酒馆设置面板中可以:
- **新增**:点击「添加变量」,填写键名、显示名、类型、默认值
- **编辑**:直接修改已有变量的任意字段
- **删除**:点击变量右侧的删除按钮
---
## 🧠 记忆系统
酒馆模式内置**三层记忆架构**,自动追踪角色的对话历史与情感变化。
### 三层记忆架构
| 层级 | 名称 | 作用 | 生命周期 |
|------|------|------|----------|
| L1 | **工作记忆** | 当前会话内的上下文对话 | 会话级(关闭即消失) |
| L2 | **长期记忆** | 跨会话持久化的重要记忆(通过 `【记忆】` 标记触发) | 永久 |
| L3 | **背景知识库** | 世界设定、规则、角色档案等静态知识 | 永久 |
### 触发方式
AI 回复中包含 `【记忆】` 标记时,标记后的文本会被自动捕获并写入长期记忆。
**示例**:
```
老板娘轻轻叹了口气:「你上次来的时候喝了三瓶 sake,这次酒量怎么样?」
【记忆】客人偏爱清酒,上次喝了三瓶
```
### 记忆写入流程
```
AI 回复文本
│
▼
extractMemory(text) ──► 识别 【记忆】 标记
│ │
│ 不是记忆 ──► 跳过
│
▼
命中 【记忆】 ?
│
▼
┌───────────────────────────────────────┐
│ 双路径写入(避免重复) │
│ │
│ 路径 A:酒馆模式内 │
│ scanForTavern() → onMemory 回调 │
│ → handleMemory() → memApi('/add') │
│ │
│ 路径 B:全局扫描器(所有模式) │
│ globalMemoryScanner → seenTexts 去重 │
│ → memApi('/add') │
│ (酒馆模式下自动跳过,走路径 A) │
└───────────────────────────────────────┘
│
▼
记忆 API 持久化存储
```
### 记忆衰减策略
通过 `memoryDecay` 字段控制:
| 策略 | 说明 | 适用场景 |
|------|------|----------|
| `light` | 弱衰减,记忆保留时间短 | 一次性/短期体验 |
| `normal` | 标准衰减(默认) | 日常使用 |
| `heavy` | 强衰减,重要记忆几乎永久保留 | 深度角色养成 |
### 跨模式共享
全局记忆扫描器在**任何会话**都会运行:
- ✅ 标准模式下 AI 回复中的 `【记忆】` 也会被捕获
- ✅ 不同会话间的记忆可以互相引用
- ✅ `seenTexts` Set 做文本级去重,避免重复写入
- ✅ 酒馆模式下自动跳过全局扫描,由专属扫描器负责
### 状态栏记忆区块
状态栏底部有**可滚动的记忆展示区**,实时显示已捕获的记忆条目:
- 按时间倒序排列(最新的在最上方)
- 支持折叠/展开
- 窄屏模式下自动限高
### 记忆 API
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/api/memory/{personaId}` | 获取指定角色的全部记忆 |
| POST | `/api/memory/{personaId}/add` | 新增一条记忆 |
| DELETE | `/api/memory/{personaId}/{memoryId}` | 删除指定记忆 |
> **注意**:记忆 API 由 DSH 宿主提供,用户无需单独配置。
---
## 🖥️ 状态栏
### 完整版
场景 | 时间 | 情绪 | 强度 | 亲密度 | 好感度 | 信任度 | 自定义变量(记忆区块可滚动)
### 折叠展开
- 点击 **▾ 收起** → 精简版(仅显示立绘缩略图 + 亲密/好感/信任数值)
- 点击 **▴ 展开** → 完整版
- 窄屏模式下自动限高,聊天记录不会被挤出
### 营业时长
状态栏右侧显示本次进入酒馆的累计时长。
---
## 🩺 诊断面板
在酒馆设置面板底部,点击 **「重新探测」** 可一键采集诊断信息:
| 诊断项 | 含义 | 正常值 |
|--------|------|--------|
| API 基址 | persona 立绘 API 地址 | 显示运行时解析到的地址 |
| 记忆 API 基址 | 记忆系统 API 地址 | 同上 |
| Config 基址 | 配置同步 API 地址 | 同上 |
| 本地变量表 | localStorage 中的变量表数量 | ≥ 0 |
| 本地状态 | localStorage 中的状态版本与数值 | 版本 v1 + 合理范围 |
| config 服务 | 插件内置配置服务连通性 | HTTP 200 |
| 端口探测 | 四层探测链的最终来源 | 预期来源 |
---
## ❓ 常见问题
Q1: 启动后酒馆入口按钮不显示?
**排查步骤**:
1. 确认 `pnpm run build` 已完成(检查 `apps/web/dist/` 是否存在)
2. 确认 `pnpm dsh web` 正在运行(端口 3080 可访问)
3. 打开浏览器 DevTools Console,查找 `[tavern]` 前缀的日志
Q2: 酒馆设置保存后刷新失效?
**排查步骤**:
1. 打开诊断面板 → 检查「config 服务」是否显示 `HTTP 200`
2. 检查 `.dsh/.agent-presets/tavern/config.json` 是否被正确写入
3. 若 config.json 损坏,系统会自动回退到 `.backup/config.last-good.json`(查看 Console 日志确认)
Q3: 状态栏不显示自定义变量?
**排查步骤**:
1. 进入酒馆会话后,确认已点击过酒馆设置面板的「保存」按钮(localStorage 反向同步)
2. 打开诊断面板 → 检查「本地变量表」数量是否正确
3. 若数量为 0:说明 localStorage 未同步,需硬刷新(Ctrl+F5)后重新进入酒馆
Q4: 状态数值在对话中不更新?
**排查步骤**:
1. 检查 AI 回复中是否包含 `【状态更新】` 标记
2. 确认变量表的 `key` 与 AI 回复中的键名一致(区分中英文、繁简体)
3. 若使用工具调用模式:查看会话日志中是否有 `manage_tavern_state` 工具调用记录
Q5: 端口冲突(EADDRINUSE)?
**解决**:
1. 确认没有旧的 config-server 进程残留(M3 起已并入 DSH 插件,不需额外进程)
2. 查看 `__DSH_BOOT__` 注入的端口配置(`window.__DSH_BOOT__?.services`)
Q6: 切换端口后酒馆功能异常?
**排查步骤**:
1. 打开诊断面板 → 检查「API 基址」「Config 基址」是否已更新为新端口
2. 四层探测链优先级:`__DSH_BOOT__` 注入 → 用户配置覆盖 → 同源推导 → 兜底
3. 若兜底端口被使用:在 DSH 设置中配置正确的端口映射
Q7: 立绘 / 立绘破窗效果不显示?
**排查步骤**:
1. 确认 persona API 可达(诊断面板「API 基址」正常)
2. 确认已激活带立绘的角色人设
3. 窄屏模式下立绘会自动缩小以保证聊天记录可见
Q8: 硬刷新(Ctrl+F5)后状态丢失?
**说明**:状态存在两处:
- `localStorage`(前端快速读写)→ 硬刷新不丢
- `state/.json`(后端持久化)→ 硬刷新不丢
如果硬刷新后状态清空,检查:
1. 是否切换了浏览器(localStorage 按域隔离)
2. 后端 state 文件是否正常:`.dsh/.agent-presets/tavern/state/.json`
Q9: 跨模式记忆扫描器重复写入?
**说明**:不会。扫描器内部用 `seenTexts` Set 做去重,且酒馆模式下检测到 `isTavern === true` 会跳过(因为 tavern 自身的扫描器已通过 `onMemory` 回调写入)。
---
## 📋 默认配置速查
首次进入酒馆模式的默认状态:
| 项目 | 默认值 |
|------|--------|
| 酒馆名称 | 深夜小酒馆 |
| 初始场景 | 深夜小酒馆吧台旁 |
| 初始时间 | 深夜 |
| 初始情绪 | 平静 |
| 亲密度 | 20 |
| 好感度 | 15 |
| 信任度 | 10 |
| 默认变量 | 接客数(计数器)、兴奋度(进度条) |
| 记忆自动开启 | 是 |
| 记忆衰减 | normal |
---
## 🏗️ 文件结构
```
.dsh/.agent-presets/tavern/
├── preset.yml # 酒馆预设元数据
├── agent.cordis.yml # 服务端插件装配(tavern-config + persona)
├── config.json # 配置文件(酒馆名称/变量表/初始状态)
├── tavern-config-plugin.mjs # 配置服务插件(GET/POST /api/tavern/config + manage_tavern_state 工具)
├── README-TAVERN.md # 本文档
├── tests/
│ └── state-schema.test.mjs # 状态校验单元测试
├── state/ # 会话状态持久化目录
│ └── .json # 按会话分区的状态文件
└── .backup/ # 配置备份
└── config.last-good.json # 上次好配置(自愈来源)
wan-tavern/ # 插件包(vendored)
├── package.json # 插件包元数据
├── entry.js # 服务端入口
├── client.js # 前端核心(状态栏/设置/诊断面板/记忆扫描)
├── cordis.patch.yml # 前端注入装配
├── install.mjs # 一键安装脚本
└── tests/
└── tool-state.test.mjs # 工具状态解析单元测试(13 用例)
```
---
## 📚 相关文档
| 文档 | 内容 |
|------|------|
| [README.md](../../README.md) | 插件主文档(安装、配置、开发者指南) |
| [CHANGELOG.md](../../CHANGELOG.md) | 版本变更日志 |
| [tests/state-schema.test.mjs](tests/state-schema.test.mjs) | 状态迁移与 Schema 校验单元测试 |
---
## 🤝 作者
**B站星萌Y小郭酱**
- 🏠 B站空间:[https://space.bilibili.com/12644772](https://space.bilibili.com/12644772)
- 📮 UID:12644772
本酒馆模式插件由 **B站星萌Y小郭酱** 独立开发维护。
---
🍻 **Welcome to the Tavern** — 进酒馆的人,老板娘都记得 🍻