[!TIP] 本篇章文档基于 Maybe 大佬提供的 PR 和函数~
window.callGenerate(options): Promise<GenerateResult>
为 iframe 内宿主页面提供基于酒馆底层 API 的自由度大于酒馆原生 generate() 和 generateRaw() 的调用酒馆生成并返回生成结果的桥接 API。
以“组件列表 + 行内覆写 + 注入”为核心语义,支持预览 messages 便于可视化审阅与调试,提供高度自由的提示词构建功能。
主要功能
- 单一入口:
window.callGenerate(options): Promise<GenerateResult>。 - 组件列表驱动:
components.list同时决定启用集合与顺序;支持ALL(任意位置出现即表示“启用全部”)。 - 覆写与创建:行内覆写支持
disable/replace/order,未命中replace时按锚点“无则创建”。 - 历史统一:
chatHistory支持selector/replaceAll/replace[]的消息级替换与筛选流水线。 - 注入:内联注入(默认
AFTER_COMPONENT,邻接历史 →IN_CHAT,首项+prev →BEFORE_PROMPT)与高级注入。 - 预览/蓝图:可导出
messages与blueprint(组件顺序/注入/覆写)。 - 发送:统一经
ChatCompletionService,流式/非流式;标准事件回传。
这是嵌入到消息里的 iframe 页面中使用最小示例:
// 在 iframe 宿主页面代码里直接调用
// 首先构建生成请求选项,包括提示词和各种设置
const options ={
components: { list: ['ALL_PREON'] }, // 启用酒馆预设里所有开启组件当基座
userInput: '请总结要点并给出下一步建议。', // 本次用户输入
streaming: { //流式输出设置
enabled: true, //是否启用流式
onChunk: (chunk, acc) => {
// 可选:流式过程中实时拿到增量(chunk)与累计文本(acc)
// console.log('[chunk]', chunk);
},
debug: { enabled: true } // 开启调试预览
};
// 2) 发送请求并取得最终结果
const res = await window.callGenerate(options);
/*
res 的结构如下:
{
success: true,
result: '模型最终输出的完整文本', // 例如一段 JSON 或自然语言
sessionId: 'xb1',
metadata: { duration: 1234, model: 'gemini/claude/GPT...', finishReason: 'stop' }
}
*/window.postMessage(iframe → 宿主)
本桥接为 iframe 内的宿主页面提供对 SillyTavern 世界书(worldbook/lorebook)的读写与管理能力,语义尽量对齐 STscript,但实现基于底层 API。
- 通信协议:
window.postMessage(iframe → 宿主) - 事件推送:宿主 → iframe(
worldbookEvent)
API 总览
说明中返回值如果为“字符串”,通常会把非字符串值做 toString;数组会常以 JSON 字符串或数组返回,详见各 API。
文件级(worldbook):
listWorldbooks() → string[]
getGlobalBooks() → string(JSON 字符串化后的数组)
getChatBook({ name? }) → string(已绑定或新建文件名)
getPersonaBook() → string
getCharBook({ type: 'primary'|'additional'|'all', name? }) → string | string(JSON)
world({ state?: 'on'|'off'|'toggle', silent?: boolean, name?: string }) → ''(空字符串)
条目(entry)基础:
listEntries({ file }) → Array<{ uid, comment, key, keysecondary, position, depth, order, probability, useProbability, disable }>
createEntry({ file, key?, content? }) → string(新 uid)
findEntry({ file, field?: string, text: string }) → string(uid 或空字符串)
getEntryField({ file, uid, field?: string }) → string(字段值)
setEntryField({ file, uid, field, value }) → ''(空字符串)
deleteEntry({ file, uid }) → 'ok' | ''(空字符串)
条目(entry)增强:
getEntryAll({ file, uid }) → Record<field, string>(按模板字段批量返回)
batchSetEntryFields({ file, uid, fields: Record<field, value> }) → 'ok'
cloneEntry({ file, uid, newKey? }) → string(新 uid)
moveEntry({ sourceFile, targetFile, uid }) → string(新 uid)
reorderEntry({ file, uid, newOrder }) → 'ok'
计时效果(最小对齐 STscript):
wiGetTimedEffect({ file, uid, effect: 'sticky'|'cooldown', format?: 'bool'|'number' }) → string
wiSetTimedEffect({ file, uid, effect: 'sticky'|'cooldown', value?: 'toggle'|'true'|'false'|boolean }) → ''(空字符串)
绑定/解绑:
bindWorldbookToChat({ worldbookName, autoCreate?: boolean }) → { name }
unbindWorldbookFromChat() → { name: '' }
bindWorldbookToCharacter({ character?, worldbookName, target: 'primary'|'additional', autoCreate?: boolean }) → { primary?: string, additional?: string[] }
unbindWorldbookFromCharacter({ character?, worldbookName?, target: 'primary'|'additional'|'all' }) → { primary?: string, additional?: string[] }
导入/导出与管理:
exportWorldbook({ file }) → string(JSON)
importWorldbook({ name, data: JSONstring, overwrite?: boolean }) → 'ok'
renameWorldbook({ oldName, newName }) → 抛出 NOT_IMPLEMENTED
deleteWorldbook({ name }) → 抛出 NOT_IMPLEMENTED(需 ST 核心支持)如何构建提示词
components.list 是一个“积木清单”,按顺序从上到下处理。支持三种元素(可混搭):
1) 字符串“引用一个组件”
- 常见键:
'ALL','ALL_PREON','chatHistory','worldInfoBefore','worldInfoAfter','charDescription','personaDescription','scenario'… - 也可以用带前缀的精确引用:
'id:charDescription'、'name:世界观'。id是指代的提示词的identifier,而name就是指的你在预设里每个组件的name。如果不带前缀的话,默认你写的是name,如果name找不到则回退搜索是否有符合的条件identifier。 'ALL'和'ALL_PREON'的意思:以“启用全部组件”/“启用全部你在酒馆的预设里设置为启用组件”为基础条件;否则默认“只用你列出来的子集”。
2) 覆写一个组件(开关/替换/排序参与)
- 语法:
{ '<ref>': { ...配置 } },<ref>用法同上(如'id:scenario'或'dialogueExamples') - 常用字段:
disable: true关掉该组件replace: '新的文本'替换该组件内容(即便该组件没有内容也会将你设置的文本填入进去)order: false在'ALL'基座下,表示“不参与重排”,保持原位
- 特别的
chatHistory(聊天历史)还能做“选择/替换”:selector选历史子集(按角色/包含词/范围等)replaceAll或replace用你的消息替换全部或者指定历史段
3) 内联“插一条自定义消息”
- 语法:
{ role: 'system'|'assistant'|'user', content: '...', position?: 'BEFORE_PROMPT'|'IN_PROMPT'|'IN_CHAT', depth?: number } - 放在
list的哪个位置,就会影响它贴近谁(有时会自动判定“插在某组件后面”) - 常用位置:
BEFORE_PROMPT:放最前面当“总前言”IN_PROMPT:放在“历史对话之前”,当系统规则/背景IN_CHAT:插到历史附近(depth: 0表示插入在最底层;大于 0 表示在更浅的位置)
如何构建一个 list
1) 先决定基座
- 要“继承酒馆所有组件” → 用
'ALL' - 要“只继承酒馆所有预设里设置为启用组件” → 用
'ALL_PREON' - 要“只用若干关键组件” → 不写
'ALL'或者'ALL_PREON',按需求列出它们(子集模式)
2) 需要强调顺序的组件写成字符串按顺序列出来
- 在
'ALL'或者'ALL_PREON'下,你列出来的这些会被按照你list里的顺序进行重新列排列(未列出的保持原位) - 不想被重排的,给它
{ '<ref>': { order: false } }
3) 用覆写对象做开关/替换
- 关掉:
{ 'id:scenario': { disable: true } } - 替换:
{ 'id:authorsNote': { replace: '注意简洁、可执行。' } } - 历史选择与替换:
{ 'id:chatHistory': { selector: {...}, replace: [...] } }
4) 用内联注入插“自定义规则/提示”
- 开场总规则:
{ role: 'system', content: '...', position: 'BEFORE_PROMPT' } - 体系化要求:
{ role: 'system', content: '输出包含摘要/清单/下一步', position: 'IN_PROMPT' } - 历史附近提醒:
{ role: 'assistant', content: '...', position: 'IN_CHAT', depth: 0 }
模板示例 1:ALL 基座 + 关掉场景 + 替换作者注 + 注入总规则
const options = {
components: {
list: [
'ALL', // 以“全部组件”为基座
// 需要强调顺序的几个(其余保持原位)
'charDescription',
'worldInfoBefore',
'worldInfoAfter',
'dialogueExamples',
// 覆写:关掉场景;替换作者注
{ 'id:scenario': { disable: true } },
{ 'id:authorsNote': { replace: '简洁、结构化、可执行。' } },
// 注入:最前面加一个总规则
{ role: 'system', content: '回答需包含:摘要、清单、下一步。', position: 'BEFORE_PROMPT' },
],
},
userInput: '基于当前上下文给出行动建议。',
streaming: { enabled: true },
debug: { enabled: true }
};
window.callGenerate(options);模板示例 2:子集模式(只用人设 + 世界观 + 历史片段)
const options = {
components: {
list: [
'charDescription',
'worldInfoBefore',
{
'id:chatHistory': {
selector: {
roles: { include: ['user', 'assistant'] },
last: 8 // 只取最后 8 条
}
}
},
{ role: 'system', content: '先思考再作答,最后列出下一步。', position: 'IN_PROMPT' },
],
},
userInput: '总结当前局势并给出计划。',
streaming: { enabled: false }, // 不流式也可
debug: { enabled: true }
};
window.callGenerate(options);chatHistory 选择与覆写
{
'id:chatHistory': {
selector: {
roles: { include: ['user', 'assistant'] }, // 角色筛选,这里就是只使用role为user和assistant的消息
filter: { contains: ['线索'], regex: 'Boss' }, // 内容筛选(或用正则)
anchorWindow: { anchor: 'lastUser', before: 4, after: 2 }, // 锚点窗口
takeEvery: 1, // 每隔几条取一条
limit: { count: 12, truncateStrategy: 'even' }, // 限条数(first/middle/even/last)
},
// 替换最后X条历史,这里是最后一条
replace: [
{ indices: { values: [-1] }, with: [{ role: 'user', content: '(系统)聚焦新线索。' }] }
]
}
}常见问答
- 我只想快速“全套原生提示 + 自己的输入”?
list: ['ALL']或者list: ['ALL_PREON'],加上userInput即可。
- 要确保某组件有内容(没有就补上)?
- 覆写里用
{ '<ref>': { replace: '...' } },缺失时会自动“补出来”。
- 覆写里用
- 引用名分不清?
- 用
'id:xxx'最稳(如id:charDescription、id:worldInfoBefore),如果是自定义组件,则需要你去查看具体identifier,酒馆给自定义组件都是默认分配一个随机identifier。
- 用
- 想看最终发给模型的消息?
- 开
debug.enabled: true,会有“提示预览/蓝图”消息。
- 开
如何对 API 进行覆写
默认行为(inherit=true)
- 不写
api或只写api.overrides时,会继承酒馆里当前聊天设置(来源/模型/代理等),你只“改你写的那几项”。
关闭继承(inherit=false)
- 完全手动指定来源与模型,必要时提供
baseURL。
常用字段(写在 api.overrides 里):
provider:'openai'|'claude'|'gemini'|'google'|'vertexai'|'cohere'|'deepseek'|'xai'|'groq'|'openrouter'|'custom'其中custom就是兼容 OpenAI 格式的来源model: 模型名(如'gpt-4o-mini'、'Gemini 2.5 pro')temperature,topP,topK,frequencyPenalty,presencePenalty,repetitionPenaltymaxTokens: 最大输出令牌数stop: 停止词数组,如['<END>']responseFormat: 如{ type: 'json_object' }(OpenAI 风格)seed: 随机种子baseURL: 覆写接口地址provider='custom'→ 映射到custom_url- 其他
provider→ 映射到reverse_proxy(OpenAI/Claude 等)
额外注意:
- 继承模式会自动透传你在酒馆里配置的代理与自定义头(适配来源)。
- 不支持 SSE 的端点请设
streaming.enabled=false,否则会超时。
典型用法
- 继承现有设置,只改模型与采样参数
window.callGenerate({
components: { list: ['ALL_PREON'] },
api: {
inherit: true,
overrides: {
model: 'Gemini 2.5 pro',
temperature: 0.7,
topP: 0.9,
maxTokens: 1024,
stop: ['<END>']
},
},
userInput: '请总结并给出下一步。',
streaming: { enabled: true },
debug: { enabled: true },
});- 直连自定义 OpenAI 兼容端(CUSTOM)
window.callGenerate({
components: { list: ['ALL'] },
api: {
inherit: false, // 不继承酒馆配置
provider: 'custom',
model: 'my-model-name',
baseURL: 'https://api.example.com/v1/chat/completions', // 映射到 custom_url
overrides: {
responseFormat: { type: 'json_object' },
temperature: 0.3,
},
},
userInput: '请用 JSON 输出结果。',
streaming: { enabled: false }, // 若端点不支持 SSE,关闭流式
debug: { enabled: true },
});获取头像
在你的 HTML 代码块里,直接放这两个类名的 div,即可自动填充用户、角色头像:
- 用户头像:
xb-user-avatar - 角色头像:
xb-char-avatar