- 装配只认 prompt_order.enabled;squash_system_messages 只合并相邻 system(新增 system 档,连接符按酒馆用单换行)
- 包装层:new_chat_prompt、示例对话(new_example_chat_prompt + <START> 切段 + name)、角色卡三块与 personality_format/scenario_format、{{user}}/{{char}} 取值、任务契约并进预设条目
- 工具协议:按 ToolBindings / 伪工具协议数据声明真 tools(presetToolPolicy=preset),工具描述用到的条目不再重复作为消息发出
- 正则:promptOnly 作用于对话历史(含 depth 过滤)、写入时脚本改写回复;{{//}} 注释按配平扫描
- tools/st-request-diff:真假上游抓包对比工具、三份预设的机制结论与实测报告
249 lines
9.5 KiB
Markdown
249 lines
9.5 KiB
Markdown
# 上下文拼接
|
||
|
||
## 1. 定位
|
||
|
||
Worker / skill 执行时,Runtime 将黑板 tag 与固定体裁说明拼成 LLM prompt。
|
||
**拼接规则在 skill 定义期定制;拼接执行由 Runtime 机械完成;agent 不临场改 inputTags。**
|
||
|
||
详见 `docs/worker-skill-format.md`(字段)、`docs/tag-blackboard.md`(标签原则)。
|
||
|
||
---
|
||
|
||
## 2. 上半固定、下半动态
|
||
|
||
每条 worker prompt 自上而下拼接(**一段式 stack,越稳定越靠上**):
|
||
|
||
```text
|
||
┌─ Preset(会话 presetId)────────────────────────────┐
|
||
│ 生成参数、prompt 条目(system / 文风片段等) │
|
||
│ 见 preset-format.md;与 skill 包正交 │
|
||
└────────────────────────────────────────────────────┘
|
||
┌─ 上半:固定上下文(Static)────────────────────────┐
|
||
│ shared-context.md(包级体裁约束) │
|
||
│ worker SKILL.md 正文(能力说明、自检) │
|
||
│ contextSegments 中 tier=static 的 tag │
|
||
│ 例:角色卡.确认稿、世界.蓝图、设计.worker集 切片 │
|
||
│ (含 narrator 的 presentation,无单独美学纲领 tag)│
|
||
└────────────────────────────────────────────────────┘
|
||
┌─ 下半:动态上下文(Dynamic)────────────────────────┐
|
||
│ contextSegments 中 tier=dynamic 的 tag │
|
||
│ 例:运行.事件流、可见信息、用户.最新输入 │
|
||
│ 按 policy 裁剪(tail_lines、tail_tokens、concat) │
|
||
└────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
原则:
|
||
|
||
```text
|
||
越稳定、越少改 → 越靠上(preset / static)
|
||
越增量、每轮变 → 越靠下(dynamic)
|
||
```
|
||
|
||
创作期若产出了 `context_order`(见 `context-fragment-design.md`):
|
||
|
||
```text
|
||
按 inserts 扁平 order 顺序拼装(不再按 static/dynamic 重排)
|
||
「对话.历史」是排序表中的普通标签,按 projection 动态裁剪后插入
|
||
```
|
||
|
||
「对话.历史」不只是文本块:装配时它被切成**真多轮 message[]**(user / assistant 轮)进预设的 `chatHistory` 洞;
|
||
分袋时它之前的块进 `worldBookBefore`、之后的进 `worldBookAfter`。
|
||
|
||
`order 0` 建议为槽位人设(`worker.persona`)。
|
||
`tier` 仅缓存提示;权威顺序是投影排序表。
|
||
|
||
**不是** agent 在游玩时自由往 prompt 里插段落;agent 只决定 **invoke 哪个 skill**;该 skill 的契约决定看见什么。
|
||
|
||
### 2.1 落档不进游玩投影
|
||
|
||
对话落盘绑定时(`src/dictate/play-bind.ts`)下列 tag **不**写入 `设计.上下文投影排序`:
|
||
|
||
| 类别 | 例 | 原因 |
|
||
|------|----|------|
|
||
| 创作中转 `feeds: design_only` | `设计.本局创作方案`、`设计.美学纲领与交互范式` | 只指导后续写作 |
|
||
| 呈现壳 `feeds: program` | `设计.正文组成`、`设计.0层正文组成` | 程序持有 html/css/js;模型只经 `contractOutputInstruction` 看见数据契约 |
|
||
| 开场 / 编排 | `设计.开场白#*`、`设计.worker集`、排序表自身 | 开场进历史;编排不重复挂 |
|
||
|
||
游玩填楼时:程序读壳并灌 `present.v1`;主世界/转述 system 里只追加契约区块列表,不附 frontend 源码。
|
||
|
||
---
|
||
|
||
## 3. 三分工
|
||
|
||
| 谁 | 管什么 | 何时定 |
|
||
|----|--------|--------|
|
||
| **Skill 定义**(`workers/*/SKILL.md`) | inputTags、contextSegments、tier、policy、隔离 | 写 skill 时 |
|
||
| **实例 manifest** | 启用哪些 run skill、`contextProfile` 选哪档 variant | 实例化时 agent 产出 |
|
||
| **Agent** | 何时 invoke 哪个 skill;可用 read_blackboard 辅助决策 | 运行中 |
|
||
| **Runtime** | `assembleWorkerContext()` 唯一拼接点 | 每次 invoke |
|
||
|
||
---
|
||
|
||
## 4. contextSegments(Worker Skill 字段)
|
||
|
||
在 `SKILL.md` frontmatter 声明(`inputTags` 仍保留,作为取数白名单):
|
||
|
||
```yaml
|
||
contextSegments:
|
||
- id: persona
|
||
tier: static
|
||
tags: ["角色卡.确认稿"]
|
||
label: "## 角色设定"
|
||
- id: world
|
||
tier: static
|
||
tags: ["世界.蓝图"]
|
||
label: "## 世界"
|
||
- id: history
|
||
tier: dynamic
|
||
tags: ["运行.事件流"]
|
||
policy: tail_lines_80
|
||
- id: turn
|
||
tier: dynamic
|
||
tags: ["可见信息", "用户.最新输入"]
|
||
label: "## 本轮"
|
||
```
|
||
|
||
| 字段 | 含义 |
|
||
|------|------|
|
||
| `tier` | `static`(上半)或 `dynamic`(下半) |
|
||
| `tags` | 从黑板取的 pattern,须在 `inputTags` 内 |
|
||
| `label` | 拼进 prompt 的 Markdown 标题(可选) |
|
||
| `policy` | 动态段裁剪,见 §5 |
|
||
|
||
未声明 `contextSegments` 时,Runtime 回退:按 `inputTags` 顺序输出 JSON `inputs`。
|
||
|
||
有 `contextSegments` 时:按 static → dynamic 顺序拼 Markdown(含 `label` 标题);实现见 `src/skills/context-segments.ts` → `assembleWorkerContext()`。
|
||
|
||
创作前情:`创作.已验收内容` 存各单位**最后一次验收**的内容切片,拼装时格式化为只读前情提要。
|
||
|
||
---
|
||
|
||
## 5. 动态段裁剪 policy
|
||
|
||
| policy | 行为 |
|
||
|--------|------|
|
||
| `latest` | 每 pattern 取最新一条(默认) |
|
||
| `concat` | 同 pattern 多条合并 |
|
||
| `tail_lines_N` | 事件流等取最后 N 行 |
|
||
| `tail_tokens_N` | 按估算 token 截断(预留) |
|
||
|
||
上下文过长时(**本节管 Run worker 拼装**;创作会话见 `design-orchestrator-guide.md` §7.2):
|
||
|
||
1. 优先靠 policy 裁剪动态段
|
||
2. **Run 验收后压缩**:过程 tag 归档,仅终产物 + `上下文.定稿摘要` 进入下一 worker(`compress-after-worker.ts`)
|
||
3. 实例 manifest 可覆盖 variant(如 `historyPolicy: last_10_turns`)
|
||
4. 长线再考虑显式 compress-history / RAG,禁止「完整历史喂一个 LLM 再筛给另一个」
|
||
|
||
**创作**不走本拼装栈:讨论放 session `messages`;单位验收后 **删交互、留产物**。Worker 执行仍始终按契约从黑板重装。
|
||
|
||
---
|
||
|
||
## 6. contextProfile(实例 manifest)
|
||
|
||
实例化阶段产出(写入 `设计.worker集` 或 Book manifest),agent **只选预置档位**,不列 tag:
|
||
|
||
```json
|
||
{
|
||
"runSkills": ["world-simulator", "narrator"],
|
||
"contextProfile": {
|
||
"narrator": { "variant": "card_rp", "historyPolicy": "last_15_turns" },
|
||
"world-simulator": { "variant": "light_rules" }
|
||
}
|
||
}
|
||
```
|
||
|
||
`variant` 在 skill 包内预定义多组 `contextSegments` 覆盖或 policy 差异。
|
||
例:`narrator` 的 `card_rp` 强制 static 含 `角色卡.确认稿`;`short_emotion_flow` 缩短 dynamic 历史。
|
||
|
||
---
|
||
|
||
## 7. 隔离
|
||
|
||
与 `inputTags` 正交,由 skill 声明 `contextIsolation`:
|
||
|
||
```yaml
|
||
contextIsolation: none | role_pov | blind_review
|
||
```
|
||
|
||
- `role_pov`:role-decide 等,Runtime 调用 `filterInputsForRolePerspective`
|
||
- `blind_review`:review 不可见指定 tag(如 `核心.危险.隐藏`)
|
||
|
||
隔离在 **取数之后、拼接之前** 应用。
|
||
|
||
---
|
||
|
||
## 8. 与 agent tool loop 的边界
|
||
|
||
两套上下文 **不得混用**:
|
||
|
||
| | Agent tool loop `messages[]` | Worker prompt |
|
||
|--|------------------------------|---------------|
|
||
| 用途 | 总管推理、选 skill | 具体 skill 执行 |
|
||
| 内容 | tool 结果、read_blackboard | assembleWorkerContext 输出 |
|
||
| 增长 | 两次用户操作之间的 burst 内累积 | 每次 invoke 按契约重建 |
|
||
|
||
总管 `read_blackboard` **不注入** worker prompt;只帮助 agent 决定下一个 `run_worker`。
|
||
|
||
---
|
||
|
||
## 9. 拼接结果形态
|
||
|
||
worker 先给出**分段结果**,再由预设决定最终 `messages[]` 的形状:
|
||
|
||
```text
|
||
assembleWorkerContextSections()
|
||
├─ chunks: block|history|turn (按投影排序表顺序)
|
||
└─ tail: 本步任务 / 定稿摘要 / 待改底稿 …
|
||
|
||
workerContextToBags()
|
||
├─ before → presetPack.worldBookBefore
|
||
├─ history → presetPack.history【真多轮 message[]】
|
||
├─ after → presetPack.worldBookAfter
|
||
├─ turn → presetPack.currentTurn
|
||
└─ postTurn → presetPack.postTurn
|
||
|
||
PresetLlmProvider(options.presetPack)→ assemblePlayWorkerMessages()
|
||
```
|
||
|
||
发出去的形式(有历史时):
|
||
|
||
```text
|
||
system 预设条目(main / 文风 / 破限)
|
||
system worldBookBefore:契约 + 史前资料
|
||
system worldBookAfter:变量 / 真值
|
||
assistant 历史轮…
|
||
user 历史轮…
|
||
user currentTurn:用户.最新输入
|
||
system postTurn:本步任务
|
||
```
|
||
|
||
`flat`(`assembleWorkerContext()` 的返回值)仍保留,作为无 historical 分段时的单包形式;
|
||
`contextSegments` 里没有 `对话.历史` 的 worker(创作期产出 JSON 那些)继续走单包。
|
||
|
||
实现:`src/skills/context-segments.ts` 与 `src/preset/play-frame.ts`;由 `src/worker/executor.ts` 调用。
|
||
|
||
---
|
||
|
||
## 10. 设计 checklist
|
||
|
||
```text
|
||
□ 列出 static / dynamic 各需要哪些 tag
|
||
□ static 写入 contextSegments tier=static
|
||
□ dynamic 写入 tier=dynamic 并选 policy
|
||
□ inputTags 覆盖 segments 中全部 pattern
|
||
□ 画隔离表:谁不可见哪些 tag
|
||
□ 若有多游玩模式,在包内预置 contextProfile variant
|
||
□ 实例化 manifest 只选 variant,不临场改 tag 列表
|
||
```
|
||
|
||
---
|
||
|
||
## 11. 相关文档
|
||
|
||
| 文档 | 关系 |
|
||
|------|------|
|
||
| `worker-skill-format.md` | frontmatter 字段定义 |
|
||
| `skill-design-guide.md` | 如何倒推 tag 与 skill 能力 |
|
||
| `tag-blackboard.md` | 标签命名与黑板 |
|
||
| `tool-contracts.md` | agent 不得传 inputTags |
|