跳转至

每轮的设定分四层:常驻的角色卡和蓝灯条目、命中只给标题的绿灯条目、模型按需检索的正文、模型新写的补充设定集

设定从哪来:越往下,越要模型自己动手

网页版 ChatGPT 的设定只有一处:贴进 system prompt 的那段人设。梨园把设定分成四层,下面每一步都给出梨园源码里的拼接模版,和同一段代码真跑出来的效果。

角色卡:人设投影进 system

问题:每开一个对话都要重贴人设,换个角色就得重写。

梨园直接吃酒馆(SillyTavern)的角色卡,导入后一张卡落成一个目录 cards/<卡>/。卡目录里有 AGENTS.md 就整份照用;没有就从卡的字段现拼:

模版 · src/stage/assemble.ts:322-335
    if (agentsText) {
        // 卡内容同源同规矩:{{char}}/{{user}} 宏与旧投影路径一样求值(生成物里带宏是常态)
        sections.push(m(agentsText));
    } else {
        // 2) 兜底:材料没进预设槽位的,梨园按自己的版式补——补的是位置,不是措辞之外的话。
        const charParts: string[] = [];
        if (!filled.has("charDescription") && card.description) charParts.push(m(card.description));
        if (!filled.has("charPersonality") && card.personality) charParts.push(`## 性格\n${m(card.personality)}`);
        if (!filled.has("scenario") && card.scenario) charParts.push(`## 当前场景\n${m(card.scenario)}`);
        if (!filled.has("dialogueExamples") && card.mesExample) {
            charParts.push(`## 对白示例(仅供文风与语气参考,不是已发生的剧情)\n${m(card.mesExample)}`);
        }
        if (charParts.length > 0) sections.push([`# 你扮演的角色:${card.name}`, ...charParts].join("\n\n"));
    }

实跑用的是随包的默认卡「青梧」,没有 AGENTS.md,拼出来是 system 里的这一段:

效果 · 实跑 system 第 48–57 行
# 你扮演的角色:青梧

青梧,古镇「栖水镇」上听雨轩客栈的年轻掌柜。约莫二十六七岁年纪,眉眼温和,说话不紧不慢,袖口常沾着些茶末。她记性极好,住过店的客人隔了三年再来,她仍记得对方爱喝什么茶、住哪间房。柜台后的墙上挂着一把不再使用的旧油纸伞,伞骨断了一根,她从不解释来历。听雨轩不大,前后两进,后院有一株老梨树,落雨的夜里能听见雨点敲在瓦上、叶上、石阶上,声音各不相同——她说这就是店名的由来。

## 性格
温和沉静,观察入微;言语简省,但每句都落在点上。不主动打探客人的来历,却总在恰当的时候递上一盏热茶。对镇上的旧事知道得比任何人都多,问急了只是笑。

## 当前场景
暮春,连日阴雨。夜里的栖水镇青石街上几乎没有行人,只有听雨轩还亮着灯。旅人推门而入,带着一身雨气,和一段不便说尽的来历。

世界书:蓝灯常驻,绿灯按关键词进来

问题:一张卡装不下整个世界,门派、地名、往事动辄几万字,全塞进 prompt 上下文就满了。

世界书把设定拆成条目,每条带关键词。蓝灯条目每轮都在,进 system:

模版 · src/stage/assemble.ts:354-357
    if (!agentsText && !filled.has("worldInfoBefore") && !filled.has("worldInfoAfter") && constantLore.length > 0) {
        const loreText = constantLore.map((e) => `- ${e.comment ? `【${e.comment}】` : ""}${m(e.content)}`).join("\n");
        sections.push(`# 世界设定(常驻事实)\n${loreText}`);
    }
效果 · 实跑 system 第 61–62 行
# 世界设定(常驻事实)
- 【栖水镇】栖水镇是江南水网间的小镇,一条青石街贯穿南北,镇北有渡口,镇南是茶田。镇上除了听雨轩没有别的旅店,夜里亥时之后由更夫巡街。

绿灯条目每轮扫最近 4 条消息,命中关键词的才进来,一轮最多 3 条:

模版 · src/lorebook.ts:547-558
export function scanEntries(entries: LorebookEntry[], windowText: string, limit: number): LorebookEntry[] {
    const textLower = windowText.toLowerCase();
    const activated = entries.filter((e) => {
        if (!e.enabled || e.constant || e.keys.length === 0) return false;
        if (!e.keys.some((k) => keyMatches(k, textLower))) return false;
        if (e.selective && e.secondaryKeys.length > 0) {
            return e.secondaryKeys.some((k) => keyMatches(k, textLower));
        }
        return true;
    });
    return activated.sort((a, b) => a.order - b.order).slice(0, limit);
}

实跑第一轮,用户问「十年前从镇北渡口走的那位怀瑾公子,掌柜可还记得?」,加上开场白里的「听雨轩」,命中了三条:听雨轩、怀瑾、镇北渡口。

问题:命中了就把正文塞进去,模型会把注入的内容当成全部设定——没列出来的名字就自己编,有了正文也不再去查别的。

所以命中的绿灯只给标题,另附一份全库的标题索引;正文交给检索工具:

模版 · src/stage/assemble.ts:503-521
    if (activatedLore.length > 0) {
        if (passiveLore) {
            // off 挡:给命中条目的正文(酒馆原生被动供料)——模型不主动检索时的兜底
            const lore = activatedLore
                .map((e) => `- ${e.comment ? `【${e.comment}】` : ""}${applyMacros(e.content, macro)}`)
                .join("\n");
            blocks.push(`【相关设定】\n${lore}`);
        } else {
            // thinking 挡:给标题=给线索,正文由模型自己 lorebook_search 取,检索这一环才闭得上
            const titles = activatedLore.map((e) => (e.comment || e.keys?.[0] || "").trim()).filter(Boolean);
            if (titles.length > 0) {
                blocks.push(`【相关设定】本拍命中 ${titles.length} 条:${titles.join("、")}`);
            }
        }
    }

    if (loreIndex) {
        blocks.push(`【设定集索引】${loreIndex}`);
    }

实跑第一轮,末条 user 消息里的注入块加用户原话是这样的:

效果 · 第一轮末条 user 消息
【世界状态】
(尚无记录)

【登场名录】(尚无登记)

【相关设定】本拍命中 3 条:听雨轩、怀瑾、镇北渡口

【设定集索引】共 5 条:听雨轩、旧油纸伞、怀瑾、镇北渡口、更夫

【语言】以中文写叙事与对白(专有名词可保留原文)。

我把湿透的外衣搭在椅背上,接过茶喝了一口:「住三天。顺便打听个人——十年前从镇北渡口走的那位怀瑾公子,掌柜可还记得?」

模型拿到的只有三个标题,于是先查再写——第一次调用就并发三个 lorebook_search,第二次又补查了索引里的「旧油纸伞」:

效果 · 第一轮的模型调用
── 第 1 次调用(思考 236 字)
   思考开头:The user has given a specific input. Let me check the lorebook for the relevant entries: 听雨轩, 怀瑾, 镇北渡口. The us…
   → lorebook_search {"query": "怀瑾"}
     回执:[{"title": "怀瑾", "score": 9, "content": "沈怀瑾,镇北沈家旧宅的独子,十年前一个雨夜从镇北渡口搭船离开,此后音讯全无。他走的那晚,把一把青灰色的油纸伞留在了听雨轩。青梧从不提他的名字,有人提起时,她会先去擦那把伞。"}]
   → lorebook_search {"query": "镇北渡口"}
     回执:[{"title": "镇北渡口", "score": 9, "content": "镇北渡口每日只有清晨一班船出镇。船夫老周摆渡三十年,认得每一个离镇的人。"}, {"title": "怀瑾", "score": 1, "content": "沈怀瑾,镇北沈家旧宅的独子,十年前一个雨夜从镇北渡口搭…
   → lorebook_search {"query": "听雨轩"}
     回执:[{"title": "听雨轩", "score": 10, "content": "听雨轩是栖水镇上开了近百年的老客栈,前后两进,后院有一株老梨树。店里的规矩是祖上传下来的:不问来处,不问去处,账清即可。镇上人都说,在听雨轩说过的话,不会传到第二个人耳朵里。"}, {"title": "栖水镇",…
── 第 2 次调用(思考 123 字)
   思考开头:I have the key setting. Let me also check 旧油纸伞 to understand the伞 detail, and 更夫 isn't needed right now. Let m…
   → lorebook_search {"query": "旧油纸伞"}
     回执:[{"title": "旧油纸伞", "score": 9, "content": "柜台后墙上挂着一把青灰色的旧油纸伞,伞骨断了一根,伞面上有一小块焦痕。青梧每天都会用干布擦一遍伞面,但从不撑开它,也从不回答关于这把伞的问题。"}]
── 第 3 次调用(思考 4485 字)
   思考开头:Now I understand the setting. Key facts: - 沈怀瑾, only son of 沈家旧宅, left from 镇北渡口 ten years ago on a rainy nigh…
   → draft_write {"version": 0, "content": "…259 字…"}
     回执:{"ok": true, "version": 1, "chars": 259}
── 第 4 次调用(思考 0 字)
   → draft_seal {"version": 1}
     回执:{"ok": true, "sealed": true, "version": 1}

检索按关键词命中 ×5、标题命中 ×3、正文出现次数 ×1 打分(src/lorebook.ts:569),所以查「镇北渡口」时,正文里提到渡口的「怀瑾」也以 1 分跟了上来。查回来的「有人提起时,她会先去擦那把伞」,成了定稿里的一段:

效果 · 第一轮定稿(节选)
她没有立刻应声,只把笔轻轻搁下,起身走到柜台后那面墙前。墙上挂着一把青灰色的旧油纸伞,伞骨断了一根,伞面挨近边缘处有一小块焦痕。她踮脚把伞取下来,用袖口沿着伞面慢慢地拂,动作很轻,像在擦一道早该擦掉、却总也擦不掉的旧痕。

「记得。」她背对着你,声音照旧不高,混在檐外的雨声里,「这镇子小,一条街,一个渡口。走一个人,十年也散不干净。」

扮演定义里专门写了一句,防模型把标题当正文:「看到标题就当『查过了』是错的,正文要用 lorebook_search 取。」

关思考的档照旧直接给正文

问题:关了思考档的模型基本不主动调工具,只给标题等于什么都没给。

同一段模版的另一个分支:思考档为 off 时,passiveLore 为真,【相关设定】直接给命中条目的正文。拿同样的输入、关掉思考,拼出来是:

效果 · 关思考档的第一轮注入块
【世界状态】
(尚无记录)

【登场名录】(尚无登记)

【相关设定】
- 【听雨轩】听雨轩是栖水镇上开了近百年的老客栈,前后两进,后院有一株老梨树。店里的规矩是祖上传下来的:不问来处,不问去处,账清即可。镇上人都说,在听雨轩说过的话,不会传到第二个人耳朵里。
- 【怀瑾】沈怀瑾,镇北沈家旧宅的独子,十年前一个雨夜从镇北渡口搭船离开,此后音讯全无。他走的那晚,把一把青灰色的油纸伞留在了听雨轩。青梧从不提他的名字,有人提起时,她会先去擦那把伞。
- 【镇北渡口】镇北渡口每日只有清晨一班船出镇。船夫老周摆渡三十年,认得每一个离镇的人。

【设定集索引】共 5 条:听雨轩、旧油纸伞、怀瑾、镇北渡口、更夫

【语言】以中文写叙事与对白(专有名词可保留原文)。

新造的设定写进补充设定集

问题:剧情里新出现的人物、地名、规矩,压缩之后或者下一局就没人记得了。

模型可以用 lorebook_write 把新设定写下来,缺省写进卡目录里的 补充设定集.json,不碰用户导入的原书;要写进某本世界书得指名(src/tools/lore.ts:237)。

配置 creationMode 为 ask 时多一道写入门禁:看用户这一轮的原话里有没有相应的意思。写入和删除各认一套词:

模版 · src/tools/gate.ts:52-62
export const WRITE_REQUEST_RE =
    /(写入|写进|写一下|记下|记入|记录|记住|牢记|登记|存进|存到|保存|收藏|归档|收进|收录|固化|入典|沉淀|备注|补充设定|世界书|设定集|知识库|图鉴|物志|向量|记忆库|record|save|store|remember|memorize|lorebook|codex)/i;

/**
 * 删除请求的信号(M-D3)。**不能复用 `WRITE_REQUEST_RE`**:用户说「把那条忘掉」
 * 不含任何写入词,会被错拦;反过来把删除词并进写入词集,则「删掉那条设定」
 * 会去放行 `lorebook_write`——两个信号集必须分开,按工具名选。
 */
export const DELETE_REQUEST_RE =
    /(忘掉|忘记|忘了|删掉|删除|删了|去掉|清除|清掉|移除|撤掉|不要了|记错|搞错|弄错|不对|作废|forget|delete|remove|drop)/i;

拿三句话过一遍门禁函数:

效果 · checkWriteGate 的三次判定
lorebook_write 用户原话:「把怀瑾的事记下来,以后还要用。」
→ {"allow": true}

lorebook_write 用户原话:「她看起来很难过。」
→ {"allow": false, "reason": "写入设定集需用户明确要求:本轮用户并未要求记录,本次写入已拒绝。不要写、也不要询问「是否写入」;若用户后续明确要求再执行。"}

lorebook_delete 用户原话:「那条记错了,删掉吧。」
→ {"allow": true}

被拦时回给模型的那段话,也写明了「不要询问『是否写入』」——拦下就是拦下,不让模型反过来追问用户。代码缺省不拦;随包的配置样例写的是 ask。

谁管什么

  • 程序:投影角色卡、扫关键词、拼索引、按思考档决定给标题还是正文、写入门禁
  • 模型:查不查、查什么,新设定记不记
  • 用户:导入卡和世界书、挂哪几本、改卡的 AGENTS.md、开不开写入门禁

实跑原件

演示世界书「栖水镇」:一条蓝灯,五条绿灯
{"entries": {
 "0": {"uid": 0, "comment": "栖水镇", "key": ["栖水镇"], "constant": true, "order": 0, "disable": false,
       "content": "栖水镇是江南水网间的小镇,一条青石街贯穿南北,镇北有渡口,镇南是茶田。镇上除了听雨轩没有别的旅店,夜里亥时之后由更夫巡街。"},
 "1": {"uid": 1, "comment": "听雨轩", "key": ["听雨轩"], "constant": false, "order": 1, "disable": false,
       "content": "听雨轩是栖水镇上开了近百年的老客栈,前后两进,后院有一株老梨树。店里的规矩是祖上传下来的:不问来处,不问去处,账清即可。镇上人都说,在听雨轩说过的话,不会传到第二个人耳朵里。"},
 "2": {"uid": 2, "comment": "旧油纸伞", "key": ["油纸伞", "旧纸伞"], "constant": false, "order": 2, "disable": false,
       "content": "柜台后墙上挂着一把青灰色的旧油纸伞,伞骨断了一根,伞面上有一小块焦痕。青梧每天都会用干布擦一遍伞面,但从不撑开它,也从不回答关于这把伞的问题。"},
 "3": {"uid": 3, "comment": "怀瑾", "key": ["怀瑾公子", "沈怀瑾"], "constant": false, "order": 3, "disable": false,
       "content": "沈怀瑾,镇北沈家旧宅的独子,十年前一个雨夜从镇北渡口搭船离开,此后音讯全无。他走的那晚,把一把青灰色的油纸伞留在了听雨轩。青梧从不提他的名字,有人提起时,她会先去擦那把伞。"},
 "4": {"uid": 4, "comment": "镇北渡口", "key": ["镇北渡口"], "constant": false, "order": 4, "disable": false,
       "content": "镇北渡口每日只有清晨一班船出镇。船夫老周摆渡三十年,认得每一个离镇的人。"},
 "5": {"uid": 5, "comment": "更夫", "key": ["更夫老陈", "打更的"], "constant": false, "order": 5, "disable": false,
       "content": "更夫老陈每夜亥时起巡街,梆子三长两短是有外人入镇的暗号,这规矩只有镇上的老住户懂。"}
}}
第一轮完整记录:注入、每次调用的思考全文、工具调用、定稿、场记
{
 "user": "我把湿透的外衣搭在椅背上,接过茶喝了一口:「住三天。顺便打听个人——十年前从镇北渡口走的那位怀瑾公子,掌柜可还记得?」",
 "injection": "【世界状态】\n(尚无记录)\n\n【登场名录】(尚无登记)\n\n【相关设定】本拍命中 3 条:听雨轩、怀瑾、镇北渡口\n\n【设定集索引】共 5 条:听雨轩、旧油纸伞、怀瑾、镇北渡口、更夫\n\n【语言】以中文写叙事与对白(专有名词可保留原文)。",
 "activated": [
  "听雨轩",
  "怀瑾",
  "镇北渡口"
 ],
 "messages_sent": [
  {
   "role": "system",
   "content": "(system,见 system.json)"
  },
  {
   "role": "assistant",
   "content": "【开场 · 青梧】\n*雨下到第三天,青石板路上的水洼连成了片。你推开听雨轩的门,檐角的铜铃轻响了一声。*\n\n*柜台后的女子抬起头来,目光在你被雨水浸透的肩头停了一瞬,随即移开,像是什么都没看见。她取过一只干净的粗瓷杯,倒了盏冒着热气的茶,推到柜台外沿。*\n\n「这样的天气还赶路,多半是有不得不赶的缘由。」*她的声音不高,混在雨声里却听得很清楚。*「茶是热的,房也有空的。客官打算住几天?」"
  },
  {
   "role": "user",
   "content": "【世界状态】\n(尚无记录)\n\n【登场名录】(尚无登记)\n\n【相关设定】本拍命中 3 条:听雨轩、怀瑾、镇北渡口\n\n【设定集索引】共 5 条:听雨轩、旧油纸伞、怀瑾、镇北渡口、更夫\n\n【语言】以中文写叙事与对白(专有名词可保留原文)。\n\n我把湿透的外衣搭在椅背上,接过茶喝了一口:「住三天。顺便打听个人——十年前从镇北渡口走的那位怀瑾公子,掌柜可还记得?」"
  }
 ],
 "steps": [
  {
   "round": 1,
   "reasoning": "The user has given a specific input. Let me check the lorebook for the relevant entries: 听雨轩, 怀瑾, 镇北渡口. The user asks about 怀瑾公子 who left from 镇北渡口 ten years ago. I need to check the settings before writing.\n\nLet me search the lorebook.",
   "content": "",
   "calls": [
    {
     "name": "lorebook_search",
     "args": {
      "query": "怀瑾"
     },
     "result": [
      {
       "title": "怀瑾",
       "score": 9,
       "content": "沈怀瑾,镇北沈家旧宅的独子,十年前一个雨夜从镇北渡口搭船离开,此后音讯全无。他走的那晚,把一把青灰色的油纸伞留在了听雨轩。青梧从不提他的名字,有人提起时,她会先去擦那把伞。"
      }
     ]
    },
    {
     "name": "lorebook_search",
     "args": {
      "query": "镇北渡口"
     },
     "result": [
      {
       "title": "镇北渡口",
       "score": 9,
       "content": "镇北渡口每日只有清晨一班船出镇。船夫老周摆渡三十年,认得每一个离镇的人。"
      },
      {
       "title": "怀瑾",
       "score": 1,
       "content": "沈怀瑾,镇北沈家旧宅的独子,十年前一个雨夜从镇北渡口搭船离开,此后音讯全无。他走的那晚,把一把青灰色的油纸伞留在了听雨轩。青梧从不提他的名字,有人提起时,她会先去擦那把伞。"
      }
     ]
    },
    {
     "name": "lorebook_search",
     "args": {
      "query": "听雨轩"
     },
     "result": [
      {
       "title": "听雨轩",
       "score": 10,
       "content": "听雨轩是栖水镇上开了近百年的老客栈,前后两进,后院有一株老梨树。店里的规矩是祖上传下来的:不问来处,不问去处,账清即可。镇上人都说,在听雨轩说过的话,不会传到第二个人耳朵里。"
      },
      {
       "title": "栖水镇",
       "score": 1,
       "content": "栖水镇是江南水网间的小镇,一条青石街贯穿南北,镇北有渡口,镇南是茶田。镇上除了听雨轩没有别的旅店,夜里亥时之后由更夫巡街。"
      },
      {
       "title": "怀瑾",
       "score": 1,
       "content": "沈怀瑾,镇北沈家旧宅的独子,十年前一个雨夜从镇北渡口搭船离开,此后音讯全无。他走的那晚,把一把青灰色的油纸伞留在了听雨轩。青梧从不提他的名字,有人提起时,她会先去擦那把伞。"
      }
     ]
    }
   ],
   "usage": {
    "prompt_tokens": 7037,
    "completion_tokens": 186,
    "total_tokens": 7223,
    "prompt_tokens_details": {
     "cached_tokens": 6912
    },
    "completion_tokens_details": {
     "reasoning_tokens": 70
    },
    "prompt_cache_hit_tokens": 6912,
    "prompt_cache_miss_tokens": 125
   }
  },
  {
   "round": 2,
   "reasoning": "I have the key setting. Let me also check 旧油纸伞 to understand the伞 detail, and 更夫 isn't needed right now. Let me check 旧油纸伞.",
   "content": "",
   "calls": [
    {
     "name": "lorebook_search",
     "args": {
      "query": "旧油纸伞"
     },
     "result": [
      {
       "title": "旧油纸伞",
       "score": 9,
       "content": "柜台后墙上挂着一把青灰色的旧油纸伞,伞骨断了一根,伞面上有一小块焦痕。青梧每天都会用干布擦一遍伞面,但从不撑开它,也从不回答关于这把伞的问题。"
      }
     ]
    }
   ],
   "usage": {
    "prompt_tokens": 7701,
    "completion_tokens": 89,
    "total_tokens": 7790,
    "prompt_tokens_details": {
     "cached_tokens": 7168
    },
    "completion_tokens_details": {
     "reasoning_tokens": 40
    },
    "prompt_cache_hit_tokens": 7168,
    "prompt_cache_miss_tokens": 533
   }
  },
  {
   "round": 3,
   "reasoning": "Now I understand the setting. Key facts:\n- 沈怀瑾, only son of 沈家旧宅, left from 镇北渡口 ten years ago on a rainy night, no news since.\n- The night he left, he left a 青灰色油纸伞 at 听雨轩.\n- 青梧 never mentions his name; when someone mentions it, she first goes to wipe that umbrella.\n- The umbrella hangs behind the counter, broken rib, scorch mark on the surface. She wipes it daily with a dry cloth, never opens it, never answers questions about it.\n\nSo the旅人 asks about 怀瑾公子. This is the pivotal moment — 青梧's reaction is to go wipe the umbrella first, per setting.\n\nThe character: 温和沉静, 观察入微, 言语简省. 对镇上旧事知道得最多,问急了只是笑.\n\nNow I need to write the scene. The旅人 asks about 怀瑾. 青梧's canonical behavior: \"有人提起时,她会先去擦那把伞。\" So she should go wipe the umbrella.\n\nI should write this as 青梧's response. She won't reveal much — \"从不提他的名字\". She goes to wipe the umbrella, maybe replies indirectly.\n\nThe旅人 wants to 打听个人. This is a meaningful beat. Let me write the prose.\n\nKey consideration: the user gave an instruction (their character asks a question). I承接 and play out the scene and 青梧's reaction. I don't need to ask the user anything here — this isn't a branching decision that only the user can determine; the setting already dictates 青梧's reaction (wipe umbrella, don't reveal).\n\nShould I have 青梧 answer? She \"从不提他的名字\" and \"问急了只是笑\". She'd be evasive, gentle. She might say something that acknowledges but doesn't confirm. Let me write it well.\n\nI'll write the body. Length: a modest beat, not too long. Let me compose.\n\nThe scene: she was 擦杯子 maybe. When she hears 怀瑾, her hand pauses, she looks toward the umbrella on the wall, then goes to wipe it.\n\nDialogue: Something like \"记得。\" or \"镇上的人,没有不记得的。\" But per setting she doesn't say his name. She might say \"这镇子小,走一个人,十年也忘不掉。\" Then deflect: \"客官打听他做什么?\" but careful — she doesn't 主动打探客人来历, and 听雨轩's rule is 不问来处不问去处. Hmm. Actually asking \"打听他做什么\" might be a mild probe but it's natural — she knows the most about old matters.\n\nActually, the setting says she never mentions his name, when someone mentions it she goes to wipe the umbrella. So the strongest move is: she goes to wipe the umbrella, and gives a quiet, non-committal reply.\n\nLet me write it. I'll use the draft.\n\nI should write in 叙事与对白, with 青梧's lines quoted, and narrative in third person. The opening scene was written with *actions in asterisks* and 「dialogue」. But the system prompt format: the 开场 used a mix — narrative in italics with *, dialogue in 「」. Actually looking at the opening, it's written like a prose with 青梧's description. I'll follow a similar style: narrative prose, dialogue in 「」.\n\nLet me write without over-italicizing. The 开场 used *italic* for narrative. I can use similar or just plain prose. I'll use a clean prose style with dialogue quoted.\n\nLet me draft.\n\nContent:\n\n---\n\n*她正往账本上记什么,闻言笔尖一顿,墨在纸上洇开一个点。*\n\n她没应声,只把笔搁下,转身走到柜台后那面墙前。墙上挂着一把青灰色的旧油纸伞,伞骨断了一根。她取下来,用袖口轻轻拂了拂伞面,动作很慢,像在擦一件早就擦不出的旧痕。\n\n「记得。」她背对着你,声音照旧不高,「这镇子小,一条街,一个渡口。走一个人,十年也散不干净。」\n\n她把伞重新挂回去,绳结系得仔细,才转回柜台前,替你续了半盏茶。\n\n「客官是从他来的地方来的,还是往他去的地方去?」\n\n---\n\nWait — 听雨轩 rule: 不问来处,不问去处. That's the inn's rule. But this question \"客官是从他来的地方来的,还是往他去的地方去?\" is a bit of a probe into the guest's business. Hmm, it's natural she'd ask about the person the guest is seeking — but the rule is about not asking guests where they come from/where they go. Asking \"how do you know him / why are you looking\" is about the guest's business. Actually \"不问来处,不问去处\" might be more literal about the guest's travel. But the spirit is 不主动打探客人的来历.\n\nActually the character sheet says 青梧: \"不主动打探客人的来历\". So I should avoid her probing the guest. Instead she'd be more reserved.\n\nLet me reconsider. The guest already volunteered: \"打听个人\". She doesn't pry. She might just acknowledge she remembers, then not offer more — letting the guest say what they actually want. That's more in character: 言语简省,每句都落在点上.\n\nRevised ending: she might say \"记得\" and then fall quiet, waiting — or she might gently say something that opens the door without prying. Like: 「记得。」then a silence, then「你要打听他的什么?」— no, that's still fine actually, the guest raised it, so it's not her prying.\n\nActually \"你要打听他的什么\" is a natural response to a guest who said \"打听个人\" — she's responding to their stated intent, not prying. That's fine and keeps her terse.\n\nLet me finalize:\n\nNarrative: she pauses, wipes umbrella. Says \"记得\". Then 续茶. Then asks \"客官想打听他的什么?\" — a simple, non-prying question that hands the conversation back.\n\nThat's good. It stays terse and in character.\n\nLet me write it.",
   "content": "",
   "calls": [
    {
     "name": "draft_write",
     "args": {
      "version": 0,
      "content": "她正往账本上记什么,闻言笔尖一顿,墨在纸上洇开一点。\n\n她没有立刻应声,只把笔轻轻搁下,起身走到柜台后那面墙前。墙上挂着一把青灰色的旧油纸伞,伞骨断了一根,伞面挨近边缘处有一小块焦痕。她踮脚把伞取下来,用袖口沿着伞面慢慢地拂,动作很轻,像在擦一道早该擦掉、却总也擦不掉的旧痕。\n\n「记得。」她背对着你,声音照旧不高,混在檐外的雨声里,「这镇子小,一条街,一个渡口。走一个人,十年也散不干净。」\n\n她把伞重新挂回去,把系绳结得仔细,才转回柜台前,替你续了半盏热茶。茶烟腾起来,隔在你们中间。\n\n「客官想打听他的什么?」\n"
     },
     "result": {
      "ok": true,
      "version": 1,
      "chars": 259
     }
    }
   ],
   "usage": {
    "prompt_tokens": 7874,
    "completion_tokens": 1605,
    "total_tokens": 9479,
    "prompt_tokens_details": {
     "cached_tokens": 7680
    },
    "completion_tokens_details": {
     "reasoning_tokens": 1347
    },
    "prompt_cache_hit_tokens": 7680,
    "prompt_cache_miss_tokens": 194
   }
  },
  {
   "round": 4,
   "reasoning": "",
   "content": "",
   "calls": [
    {
     "name": "draft_seal",
     "args": {
      "version": 1
     },
     "result": {
      "ok": true,
      "sealed": true,
      "version": 1
     }
    }
   ],
   "usage": {
    "prompt_tokens": 9507,
    "completion_tokens": 46,
    "total_tokens": 9553,
    "prompt_tokens_details": {
     "cached_tokens": 9472
    },
    "completion_tokens_details": {
     "reasoning_tokens": 0
    },
    "prompt_cache_hit_tokens": 9472,
    "prompt_cache_miss_tokens": 35
   }
  }
 ],
 "final": "她正往账本上记什么,闻言笔尖一顿,墨在纸上洇开一点。\n\n她没有立刻应声,只把笔轻轻搁下,起身走到柜台后那面墙前。墙上挂着一把青灰色的旧油纸伞,伞骨断了一根,伞面挨近边缘处有一小块焦痕。她踮脚把伞取下来,用袖口沿着伞面慢慢地拂,动作很轻,像在擦一道早该擦掉、却总也擦不掉的旧痕。\n\n「记得。」她背对着你,声音照旧不高,混在檐外的雨声里,「这镇子小,一条街,一个渡口。走一个人,十年也散不干净。」\n\n她把伞重新挂回去,把系绳结得仔细,才转回柜台前,替你续了半盏热茶。茶烟腾起来,隔在你们中间。\n\n「客官想打听他的什么?」\n",
 "sealed": true,
 "scribe": {
  "systemPrompt": "你是一场角色扮演的场记。阅读【当前账本】与【本轮对话】,只做一件事:输出 JSON,更新需要记账的持久变化。\n\n输出唯一字段:\n\"patch\":从本轮对话中提取需要记账的持久变化。字段语义:\n- \"time\" / \"location\":字符串,整体替换。剧内时间推移(入夜、次日清晨、数日后)必须更新 time。\n- \"characters\":{ \"名字\": { \"affinity\"?, \"status\"?, \"notes\"?, \"at\"? } },按字段合并。affinity 为 -100..100 的对旅人态度值,基于账本当前值小步调整(通常 ±1~10)。\"at\" 是该角色此刻所在地,与 location 同一写法;离开当前场景的人写他去了哪。用户角色写作「旅人」;只有全新出场的人物才建新条目,键用正文中的人名——不要把作品/剧本标题(如「青梧」这类非人名)当作角色。\n- \"inventory\":字符串数组,整体替换——只在物品归属变化时给出变化后的完整清单,条目注明归属(如「黄铜怀表(旅人持有)」)。\n- \"flags\":键值对,按键合并(值为字符串)。\n- \"plot_threads\":字符串数组,整体替换——新增或了结剧情线时给出完整清单。\n要点:否定性事件也要记账(赠礼被拒→物品仍在原主处;承诺被收回→记入 flags);新的承诺、约定、伏笔进 plot_threads;没有变化的字段不要出现在 patch 中;完全无变化则 \"patch\" 为 {}。\n\n只输出 JSON 对象,例如 {\"patch\":{...}} 或 {\"patch\":{}}。不要输出 warnings、不要输出其他文字。",
  "userText": "【当前账本】\n{\n  \"time\": \"\",\n  \"location\": \"\",\n  \"characters\": {},\n  \"inventory\": [],\n  \"flags\": {},\n  \"plot_threads\": []\n}\n\n【本轮对话】\n旅人:我把湿透的外衣搭在椅背上,接过茶喝了一口:「住三天。顺便打听个人——十年前从镇北渡口走的那位怀瑾公子,掌柜可还记得?」\n\n青梧:她正往账本上记什么,闻言笔尖一顿,墨在纸上洇开一点。\n\n她没有立刻应声,只把笔轻轻搁下,起身走到柜台后那面墙前。墙上挂着一把青灰色的旧油纸伞,伞骨断了一根,伞面挨近边缘处有一小块焦痕。她踮脚把伞取下来,用袖口沿着伞面慢慢地拂,动作很轻,像在擦一道早该擦掉、却总也擦不掉的旧痕。\n\n「记得。」她背对着你,声音照旧不高,混在檐外的雨声里,「这镇子小,一条街,一个渡口。走一个人,十年也散不干净。」\n\n她把伞重新挂回去,把系绳结得仔细,才转回柜台前,替你续了半盏热茶。茶烟腾起来,隔在你们中间。\n\n「客官想打听他的什么?」\n",
  "raw": "{\"patch\":{\"time\":\"傍晚(雨中)\",\"location\":\"青梧的客栈(檐外下雨)\",\"characters\":{\"青梧\":{\"affinity\":5,\"status\":\"客栈掌柜\",\"notes\":\"对怀瑾公子一事知情,态度谨慎回避,似乎怀有旧情;取下墙上断骨的旧油纸伞仔细拂拭后挂回\",\"at\":\"青梧的客栈\"},\"旅人\":{\"at\":\"青梧的客栈\"}},\"flags\":{\"旅人入住天数\":\"三天\",\"旅人打听对象\":\"怀瑾公子(十年前从镇北渡口离开)\",\"青梧对怀瑾的态度\":\"知情但不轻易吐露\"},\"plot_threads\":[\"旅人查访十年前从镇北渡口离开的怀瑾公子\",\"墙上断骨带焦痕的旧油纸伞与怀瑾疑似有关,青梧对其有难言旧情\"]}}",
  "applied": [
   "time → 傍晚(雨中)",
   "location → 青梧的客栈(檐外下雨)",
   "characters.青梧 已更新",
   "characters.旅人 已更新",
   "flags.旅人入住天数 → 三天",
   "flags.旅人打听对象 → 怀瑾公子(十年前从镇北渡口离开)",
   "flags.青梧对怀瑾的态度 → 知情但不轻易吐露",
   "plot_threads → [旅人查访十年前从镇北渡口离开的怀瑾公子、墙上断骨带焦痕的旧油纸伞与怀瑾疑似有关,青梧对其有难言旧情]"
  ],
  "warnings": [],
  "formatted": "时间:傍晚(雨中)\n地点:青梧的客栈(檐外下雨)\n青梧:好感 5;状态:客栈掌柜;在:青梧的客栈;备注:对怀瑾公子一事知情,态度谨慎回避,似乎怀有旧情;取下墙上断骨的旧油纸伞仔细拂拭后挂回\n旅人:好感 0;在:青梧的客栈\n旅人入住天数:三天\n旅人打听对象:怀瑾公子(十年前从镇北渡口离开)\n青梧对怀瑾的态度:知情但不轻易吐露\n剧情线:「旅人查访十年前从镇北渡口离开的怀瑾公子」 「墙上断骨带焦痕的旧油纸伞与怀瑾疑似有关,青梧对其有难言旧情」",
  "roster": "人物:青梧(傍晚(雨中))、旅人(傍晚(雨中));地点:青梧的客栈(檐外下雨)(傍晚(雨中))、青梧的客栈(傍晚(雨中));剧情线:旅人查访十年前从镇北渡口离开的怀瑾公子(傍晚(雨中))、墙上断骨带焦痕的旧油纸伞与怀瑾疑似有关,青梧对其有难言旧情(傍晚(雨中))"
 },
 "note": "梨园在 draft_seal / previous_draft_edit 成功后结束本轮(src/stage/engine.ts:1883),之后的模型调用已从记录里去掉"
}