17 KiB
17 KiB
SillyTavern 完全兼容优化方案(Go + Gin + Postgres + React)
目标:基于现有 Go + React 系统,构建一个与 SillyTavern(下称 ST)高度兼容的角色卡 / 世界书 / 正则 / 预设 / 对话平台。
1. 总体目标与设计原则
- 技术栈统一:所有核心功能(角色卡、世界书、正则、预设、聊天、AI 集成)全部收敛到:
- 后端:
server/下的 Go + Gin + PostgreSQL - 前端:
projects/web-app下的 React + TypeScript + Tailwind
- 后端:
- SillyTavern 完全兼容:
- 支持 ST 角色卡 V2/V3(chara_card_v2 / v3)导入导出;
- 支持 ST 世界书字段及触发逻辑(keys/secondary_keys/regex/depth/sticky/cooldown/probability/position 等);
- 支持 ST Regex Scripts 配置(placement/runOnEdit/markdownOnly/promptOnly/substituteRegex/min/max depth);
- 支持 ST 风格预设与 prompt 注入顺序(prompt_order / injection depth/position)。
- 单一真相来源(SSOT):
- 数据库即真相:Postgres 负责持久化所有 ST 相关实体;
- 前端只是 UI:React 只做编辑/展示,请求都经过 API,不再有“前端内存版预设/世界书”。
- 可扩展性:
- 提前为插件系统预留 Hook(onUserInput/onWorldInfoScan/beforePromptBuild/onAssistantDone 等);
- 方便接入未来的 WebSocket/SSE 流式聊天、统计系统、市场/分享功能。
2. 当前 Go + React 系统现状(基于现有文档与代码)
2.1 后端(server/)
根据 projects/docs/development-progress.md:
- ✅ 用户系统 已完成(2024-02-26):
- 模型:
AppUser,AppUserSession - API:
/app/auth/register,/app/auth/login,/app/auth/refresh,/app/auth/logout,/app/auth/userinfo等 - JWT、会话、用户资料、密码修改均已实现
- 模型:
- ✅ 角色卡管理(AICharacter) 已完成:
- 模型:
AICharacter(完全兼容 ST V2 格式),使用 JSONB 存储tags/alternateGreetings/characterBook/extensions等复杂结构 - API:
POST /app/characterGET /app/character(分页、搜索、标签筛选)GET /app/character/:idPUT /app/character/:idDELETE /app/character/:idPOST /app/character/upload(PNG/JSON 角色卡)GET /app/character/:id/export(导出 JSON)
- 工具:
utils/character_card.go(PNG tEXt chunk / ST V2 工具)
- 模型:
- 🚧 预设管理:
- 前端页面
/presets已完成(导入 JSON、复制、导出、编辑参数)。 - 后端预设 API 尚未实现(
development-progress.md已给出规划端点)。
- 前端页面
- 📋 对话系统 & AI 集成:
- 前端基础 UI 已完成(
/chat+ 侧边栏 + 输入框)。 - 后端对话 API、AI 流式集成、世界书/正则逻辑尚在规划阶段。
- 前端基础 UI 已完成(
2.2 前端(projects/web-app)
- 用户系统前端:
LoginPage/RegisterPage/ForgotPasswordPage/ProfilePage已完成,api/client.ts + api/auth.ts已完成 token 注入与刷新。 - 角色卡管理前端:
CharacterManagePage+api/character.ts- 功能:
- 上传 PNG/JSON 角色卡(调用
/app/character/upload) - 编辑角色卡核心字段、内嵌
characterBook(世界书)字段 - 导出 JSON(调用
/app/character/:id/export) - 搜索、分页、删除
- 上传 PNG/JSON 角色卡(调用
- 功能:
- 预设管理前端:
PresetManagePage- 当前为 前端内存里的假数据 + 文件导入/导出;尚未接入真实后端
/app/preset。
- 当前为 前端内存里的假数据 + 文件导入/导出;尚未接入真实后端
- 聊天前端:
ChatPage + Sidebar + ChatArea + CharacterPanel + SettingsPanel- 已实现基础布局、会话切换、角色选择、背景图/主题色设置等 UI。
- 消息发送、历史加载、预设切换、世界书/正则开关还需后端配合。
- AI 配置前端:
api/aiConfig.ts(对应/app/ai-config系列)。
结论:角色卡链路基本打通,用户系统成熟;预设/对话/AI/世界书/正则目前主要停留在前端 UI 或规划层面,正好适合作为“集中下沉到 Go 后端”的突破口。
3. 目标架构(SillyTavern 兼容实现)
3.1 核心领域模型(后端)
建议在现有 model/app 中引入或规范以下模型(部分已存在,可扩展):
AICharacter(已存在)- ST 角色卡 V2/V3 的标准化版本 + 原始 JSON 存档。
Worldbook&WorldbookEntry- 支持角色内世界书与全局世界书。
RegexScript- 支持 scope:
global | character | preset。
- 支持 scope:
Preset&PresetPrompt&PresetRegexBinding- 表达 ST preset 的参数、prompt 列表和 regex 绑定。
Conversation&Message- 对话与消息记录,支持与
AICharacter、Preset和 AI 配置关联。
- 对话与消息记录,支持与
3.2 运行时 Pipeline
所有客户端(现阶段只有 React Web,将来可增加其他)统一通过 Go 后端完成以下流程:
- 输入正则脚本处理(global/character/preset)
- 世界书扫描(keys/secondary_keys/regex/depth/sticky/cooldown 等)
- Prompt 构建(角色 system + world info + preset prompts + 历史消息)
- AI 调用(OpenAI/Anthropic/custom via
/app/ai-config) - 输出正则脚本处理
- 持久化消息与统计
React 前端只负责:
- 提供管理与编辑界面;
- 将用户选择的 preset/worldbook/regex 传给后端;
- 使用 SSE/WebSocket 将 AI 流输出展示给用户。
4. 后端详细优化方案(Go + Gin + Postgres)
4.1 模型与数据库设计(概念级)
不强制你立刻改现有表名与字段;这部分作为“目标状态”,可通过迁移脚本或视图逐步对齐。
- AICharacter(已有)
- 新增/规范字段:
raw_card_json JSONB:存原始 ST 角色卡,用于无损导出。bound_worldbook_ids UUID[]:角色绑定世界书 ID 列表(可选)。bound_regex_ids UUID[]:角色绑定正则脚本 ID 列表(可选)。
- 新增/规范字段:
- Worldbook / WorldbookEntry
- Worldbook:
id, name, owner_char_id (nullable), meta JSONB, created_at, updated_at - WorldbookEntry:包含 ST 全字段:
uid, keys, secondary_keys, comment, content, constant, disabled, use_regex, case_sensitive, match_whole_words, selective, selective_logic, position, depth, order, probability, sticky, cooldown, delay, group, extra JSONB
- Worldbook:
- RegexScript
id, name, find_regex, replace_with, trim_stringplacement INT[]disabled, markdown_only, run_on_edit, prompt_onlysubstitute_regex, min_depth, max_depthscope, owner_char_id, owner_preset_id, raw_json
- Preset / PresetPrompt / PresetRegexBinding
- 基本采样参数 + prompt 列表 + regex 绑定。
- Conversation / Message
- Conversation:
id, user_id, character_id, preset_id, ai_config_id, title, settings JSONB, created_at, updated_at - Message:
id, conversation_id, role, content, token_count, created_at
- Conversation:
4.2 角色卡导入/导出(巩固现有实现)
从
development-progress.md看,/app/character模块已经“完全兼容 ST V2”,这里更多是规范与扩展。
- 导入
/app/character/upload已具备:- PNG:使用
utils/character_card.go提取charatEXt chunk → JSON。 - JSON:直接解析,填充
AICharacter。
- PNG:使用
- 优化点:
- 当角色卡中包含
character_book时:- 自动在
worldbooks/worldbook_entries中创建对应记录; - 将 worldbook.id 写入
AICharacter.bound_worldbook_ids(或冗余到characterBook字段中)。
- 自动在
- 当包含
extensions.regex_scripts时:- 自动创建
RegexScript(scope=character, owner_char_id=该角色)。 - 将脚本 id 写入
AICharacter.bound_regex_ids或extensions中。
- 自动创建
- 当角色卡中包含
- 导出
/app/character/:id/export:- 若
raw_card_json存在,优先以它为基础;将 DB 中新增的信息 patch 回去(例如补上最新的 worldbook/regex 变更)。 - 若不存在,则按 ST V2 规范组装 JSON(兼容 V1/V3 的 data 字段)。
- 若
4.3 世界书(World Info)引擎
- 世界书激活来源:
- 全局启用列表(per-user 或全局 settings 中的
active_worldbook_ids)。 - 角色绑定:
AICharacter.bound_worldbook_ids。 - 会话特定选项:
conversation.settings.activeWorldbookIds(从前端设置面板传入)。
- 全局启用列表(per-user 或全局 settings 中的
- 触发与过滤算法:
- 遍历所有激活 worldbook 的 entries:
- 忽略
disabled的 entry。 - 若
constant=true:无视关键词匹配,直接进入候选(仍受 sticky/cooldown/delay/probability 控制)。 - keys 匹配:
use_regex=true:将每个 key 作为正则(考虑caseSensitive、matchWholeWords标志)。- 否则:普通字符串包含匹配(可选大小写敏感)。
- 若
selective=true:根据selectiveLogic结合 secondary_keys:0=AND:secondary_keys 至少一个命中;1=OR:主 keys 或 secondary_keys 任一命中;2=NOT:主 keys 命中,但 secondary_keys 不命中。
- depth:仅在最近
entry.depth条消息(或 tokens)中搜索关键字。 - sticky/cooldown/delay:基于会话级状态(比如 Redis/内存/DB)存储 entry 上次触发时间或 sticky 状态。
- probability:按百分比随机决定最终是否注入。
- 忽略
- 遍历所有激活 worldbook 的 entries:
- 注入到 prompt 中:
- 简化版:将所有命中 entry.content 拼接为
[World Info]段,附加在 system prompt 后; - 高级版:按 ST 行为,依据 position/depth/order,放到不同位置(角色描述前/后、历史中等)。
- 简化版:将所有命中 entry.content 拼接为
4.4 正则脚本(Regex Scripts)引擎
- 脚本来源:
- Global:
scope='global'且disabled=false。 - Character:
scope='character' AND owner_char_id=当前角色。 - Preset:
preset_regex_bindings中绑定到当前 preset 的脚本。
- Global:
- 执行阶段(placement):
- 输入阶段(placement=1):用户消息入库前;
- 输出阶段(placement=2):模型输出生成后、入库/返回前;
- 世界书阶段(placement=3):扫描 / 注入 world info 内容前;
- 推理阶段(placement=4):如有单独 reasoning prompt,可在构建 reasoning 时处理。
- 实现细节(Go):
- 解析 JS 风格正则
/pattern/flags,支持i/m/s。 - 替换宏:
substitute_regex=1→ 用当前用户名称替换{{user}};=2→ 用当前角色名替换{{char}};
trim_string:按行定义需要从文本中删掉的子串。- minDepth/maxDepth:结合消息历史深度决定是否执行脚本。
- runOnEdit:在“消息编辑接口”中也调用该脚本集。
- markdownOnly/promptOnly:通过标志决定作用在 UI 文本 or prompt 文本。
- 解析 JS 风格正则
4.5 Prompt Pipeline 与对话 API
将现有/规划中的对话 API 统一收敛到一个 pipeline,例如 /app/conversation/:id/message(或 /conversations/:id/messages,按统一风格即可):
- 接收请求:
{
"content": "用户输入文本",
"options": {
"presetId": "uuid-xxx",
"overrideModel": "gpt-4",
"stream": true
}
}
- 管线步骤:
- 根据 conversationId 加载:
- Conversation、AICharacter、Preset、AI 配置、世界书/正则等上下文;
- 合并 settings(会话内 + 用户全局)。
- 输入文本经过 regex 引擎(placement=1)。
- 写入一条 user message 到 DB。
- 从最近 N 条消息构造 world info 触发文本,调用世界书引擎得到 entries。
- 构建 prompt:
- system:角色 system + scenario + authorsNote + preset.systemPrompt + world info;
- history:最近若干 user/assistant 消息;
- preset.prompts:按 depth/position 注入额外 messages。
- 调用 AI 服务(依据
/app/ai-config中 baseUrl/apiKey/model):- 支持流式:通过 SSE/WebSocket 对前端推送 tokens。
- 将完整 assistant 输出经过 regex 引擎(placement=2)。
- 写入一条 assistant message 到 DB。
- 返回响应给前端(同步返回最终内容 + 可选流式过程)。
- 根据 conversationId 加载:
5. 前端详细优化方案(React projects/web-app)
5.1 角色卡管理(CharacterManagePage)
目标:完全对齐 ST 角色卡 V2/V3 字段,并为世界书/正则后端拆分打好基础。
优化点:
- 字段映射明确化:
- 确保
Character接口与后端模型一致,并在注释中标明 ST 对应字段:firstMes↔first_mesmesExample↔mes_examplesystemPrompt↔system_promptpostHistoryInstructions↔post_history_instructionscharacterBook↔character_bookextensions↔extensions
- 确保
- 世界书编辑 UI 扩展:
- 目前
WorldBookEntry较简化(keys/content/enabled/insertion_order/position)。 - 建议增加更多高级属性编辑项(可以先折叠到“高级设置”中):
secondary_keys/constant/use_regex/case_sensitive/match_whole_words;selective/selective_logic;depth/order/probability/sticky/cooldown/delay/group。
- 保存时将这些字段一并放入
characterBook.entries,后端负责拆分入 DB。
- 目前
- 导入/导出保持 ST 兼容:
- 当前上传/导出流程基本正确;随着后端增强,无需大改,只要保证前端不破坏 JSON 结构即可。
5.2 预设管理(PresetManagePage)
目标:把当前的“前端内存预设”完全改造成后端驱动的 ST 预设系统。
实施步骤:
- 后端按
development-progress.md规划实现/app/presetAPI:
POST /app/preset
GET /app/preset
GET /app/preset/:id
PUT /app/preset/:id
DELETE /app/preset/:id
POST /app/preset/import
GET /app/preset/:id/export
- 前端新建
src/api/preset.ts对应这些端点。 - 将
PresetManagePage中的useState初始数据删除,改为:const { data } = await presetApi.getPresetList();- 导入、导出、编辑、删除全部通过后端。
- 预设 JSON 的读写字段与 ST 对齐:
temperature/top_p/top_k/frequency_penalty/presence_penalty/system_prompt/stop_sequences/...。
5.3 聊天与设置面板(ChatPage / SettingsPanel / CharacterPanel)
目标:把“选 preset / 选世界书 / 选正则”的入口统一放到设置面板,并通过 conversation.settings 与后端 pipeline 串联。
建议:
- 在
SettingsPanel中增加:- 当前会话使用的 preset 选择器(下拉 list:来自
/app/preset)。 - 可选的世界书列表(来自未来的
/app/worldbook,初期可只展示角色内 worldbook)。 - 可选的全局正则脚本列表(来自未来的
/app/regex)。
- 当前会话使用的 preset 选择器(下拉 list:来自
- 保存时调用
/app/conversation/:id/settings(或PUT /app/conversation/:id):
settings: {
backgroundImage: string
themeColor: string
presetId?: string
activeWorldbookIds?: string[]
activeRegexIds?: string[]
}
- 发送消息时,前端不再参与世界书/正则逻辑,只负责传
content,后端从 conversation/preset/character 中解析所有配置。
6. 分阶段落地路线图(仅 Go + React)
阶段 1:打通所有核心 CRUD 与数据流(短期)
- 后端:
- 巩固
/app/character模块(确保 ST V2/V3 完全兼容)。 - 实现
/app/preset模块(CRUD + 导入/导出)。 - 设计并实现
worldbooks/worldbook_entries与regex_scripts的数据结构与基础 API。
- 巩固
- 前端:
- 改造
PresetManagePage接入真实 API。 - 在
CharacterManagePage中补全世界书 entry 字段,保持 ST 兼容。
- 改造
阶段 2:实现 Prompt Pipeline 与对话 API(中期)
- 后端:
- 聚合世界书与正则逻辑,形成独立的
chatPipelineservice。 - 在
/app/conversation/:id/message(或/conversations/:id/messages)中调用 pipeline,完成一次“完整的 ST 风格对话请求”。 - 引入流式输出(SSE 或 WebSocket)。
- 聚合世界书与正则逻辑,形成独立的
- 前端:
- 在
ChatPage/SettingsPanel中增加 preset/worldbook/regex 的选择与设置保存。 - 调整 ChatArea 接收流式输出并实时渲染。
- 在
阶段 3:高级特性与插件系统(长期)
- 后端:
- 引入插件概念(
plugins表 + manifest + hooks)。 - 实现插件执行沙箱(WASM 或 goja),并在 pipeline 中注入插件 hooks。
- 增加统计、日志与审计功能。
- 引入插件概念(
- 前端:
- 增加插件管理页面与可视化配置。
- 对接统计与调试视图(例如:查看某次回复中哪些 world info/regex/插件生效)。
7. 总结
- 你当前的 Go + React 系统已经完成:
- 用户系统(认证/资料);
- 角色卡管理(完整 ST V2 兼容导入/导出);
- 预设管理与对话 UI 的前端骨架。
- 接下来最重要的三件事是:
- 在后端固化 ST 兼容的领域模型与 Prompt Pipeline;
- 让
/app/conversation成为唯一的“对话真相源”,React 只是 UI 壳。