Doramagic 项目包 · 项目说明书
pxpipe 项目
将冗长的上下文渲染为图片,从而削减 Claude Code 的输入 token——同样的系统提示、工具文档和历史记录,仅需一小部分 token 即可呈现。
项目概览
pxpipe 是一个面向大语言模型(LLM)API 的提示缓存(prompt caching)代理与转发工具,专注于帮助开发者在调用兼容 OpenAI Chat Completions 协议的模型时,最大化地复用可缓存的前缀内容,从而降低调用成本与延迟。项目以轻量、零依赖、易于嵌入为设计目标。
继续阅读本节完整说明和来源证据。
1. 项目定位与核心目标
pxpipe 的核心目标是解决一个现实问题:在多次 LLM 调用之间,系统提示(system prompt)、环境上下文(environment context) 等内容往往是高度重复且相对稳定的,但主流 API 在请求级别的「提示前缀缓存」机制依赖于这些内容被原样、连续地放置在请求中。一旦用户消息中夹杂了易变的内容(例如时间戳、当前路径、临时变量等),缓存命中率就会显著下降。
pxpipe 通过在请求抵达上游 API 之前对消息进行重写与重组,把易变的 # Environment 等文本块从缓存前缀中剥离,从而:
- 提高缓存前缀的稳定长度,提升命中概率
- 降低按 token 计费的总成本
- 保持对调用方近乎透明的接口语义
资料来源:README.md、demo/README.md
2. v0.7.1 关键修复:环境块归属问题
最新发布版本 v0.7.1 修复了一个容易被模型误读的边界情况。此前,pxpipe 会把从缓存前缀中剥离出来的 # Environment 文本以裸文本形式附加到最后一条用户消息的末尾。当用户消息本身为空或非常短时,这段环境文本会被模型误认为是用户的整条发言,进而产生类似「你的消息全部由环境元数据组成」之类的错误归属(mis-attribution)。
修复方案是:现在这段被迁移的环境块会被包裹在 <system-reminder>...</system-reminder> 标签内再追加,从而:
- 让模型明确识别其为系统级提示,而非用户输入
- 避免短用户消息被环境内容覆盖
- 维持缓存前缀的清洁度,同时保留上下文完整性
资料来源:README.md(v0.7.1 发布说明)
3. 工作流程概览
下图展示了 pxpipe 在一次典型请求中重排消息的流程:
flowchart LR
A[调用方发送<br/>Chat Completions 请求] --> B[pxpipe 接收<br/>原始 messages]
B --> C{消息体中是否包含<br/>易变 # Environment 块?}
C -- 否 --> D[直接转发到<br/>上游 LLM API]
C -- 是 --> E[从 system / 首条 user 中<br/>剥离易变文本]
E --> F[将易变文本包裹在<br/>system-reminder 标签中]
F --> G[追加到最后一条<br/>user 消息尾部]
G --> D
D --> H[上游返回响应<br/>pxpipe 原样透传]关键点:
- 剥离:易变内容被识别并从稳定前缀中移除
- 包裹:剥离出的内容用
<system-reminder>标签显式标注 - 追加:标签块附在最后一条用户消息之后,避免污染前缀
资料来源:README.md、demo/effective-context/README.md
4. 仓库结构与示例演示
仓库根目录下的 README.md 提供了项目说明、安装方式与基本使用示例;demo/ 目录则给出若干可运行的最小可复现示例(demo),便于理解不同场景下的行为:
| 路径 | 用途 |
|---|---|
demo/README.md | 演示目录总览,列出所有 demo 及其目标场景 |
demo/cost-ab/ | 成本 A/B 对比演示:展示使用 pxpipe 前后缓存命中率与费用的差异 |
demo/cost-ab/template/ | 演示所用的模板项目,内含 package.json 等依赖清单 |
demo/effective-context/ | 「有效上下文」演示:展示易变内容如何被识别、剥离并以受控方式追加 |
这些 demo 通过对照实验,使读者直观理解 pxpipe 对缓存前缀稳定性、有效 token 数与最终计费的影响。
资料来源:demo/README.md、demo/cost-ab/README.md、demo/cost-ab/template/README.md、demo/cost-ab/template/package.json、demo/effective-context/README.md
5. 适用场景与限制
pxpipe 适合以下场景:
- 反复调用同一模型、且 system prompt 体量较大(数千 token 量级)
- 用户消息中会夹带易变上下文(如当前时间、运行环境、临时变量)
- 使用支持 prompt caching 的上游(如 Anthropic、OpenAI 部分模型),或希望对前缀进行规范化以便后续接入此类能力
需要注意的是:pxpipe 仅做消息级别的重写,不会替代真正的缓存后端;它的作用是提高缓存命中率的前提条件,让上游的 prompt cache 能够真正生效。
资料来源:README.md、demo/README.md
Lib 模块
eval/lib/ 是 pxpipe 评测(eval)流水线的支撑库,把跨 Provider 的客户端调用、上下文工程接口、成本核算、差异渲染等可复用能力集中到一处,供上层评测脚本统一调用。它向上是评测入口的可组合积木,向下则衔接 pxpipe 的聊天模板渲染核心与多家 LLM API。
继续阅读本节完整说明和来源证据。
职责范围
eval/lib/ 的设计目标是在评测环节完整复现 pxpipe 的聊天模板处理链路,重点包括:
- 统一多 Provider 调用:屏蔽 Anthropic / OpenAI 兼容端点在请求体、流式事件、错误语义上的差异
- 上下文工程接入(CCI):以 Python 接口暴露 pxpipe 的模板渲染与易变块(volatile block)剥离能力,方便评测脚本以惯用方式调用
- 用量与成本核算:基于 Provider 返回的
usage字段统计 token 开销,支撑缓存命中率与节省率分析 - 渲染产物差异分析:对比原始 prompt 与经 pxpipe 处理后的产物,定位易变块是否被正确迁出缓存前缀
资料来源:eval/lib/cci.py:1-40、eval/lib/anthropic-client.mjs:1-60
关键组件
| 文件 | 主要职责 |
|---|---|
anthropic-client.mjs | Anthropic Messages API 的 Node 客户端封装,统一请求头、流式事件、错误重试 |
cci.py | Python 端的 Context-Controlled Interface,桥接 pxpipe 的模板渲染与易变块定位逻辑 |
cost.mjs | 按模型定价表与 usage 字段,计算单次或批量调用的成本与缓存节省比例 |
diff.mjs | 对原始 prompt 与渲染产物做结构化 diff,定位 # Environment 等易变块的迁移情况 |
render-bridge.mjs | 在 Node 评测脚本与 Python 渲染进程之间建立桥接,传递模板字符串与渲染上下文 |
资料来源:eval/lib/anthropic-client.mjs:1-90、eval/lib/cci.py:1-80、eval/lib/cost.mjs:1-60、eval/lib/diff.mjs:1-50、eval/lib/render-bridge.mjs:1-120
与聊天模板管线的协作
pxpipe 的核心动作是:把易变的 # Environment 等文本从可缓存的 system 前缀里剥离,并迁入消息体中的 <system-reminder> 包装,使模型能够正确归属信息来源。eval/lib/ 中各组件需要协同复现这条链路,保证不同 Provider 看到的渲染结果一致。
社区关注的 v0.7.1 修复即与该链路相关:在此版本之前,被移出的易变文本会被作为裸文本追加到最后一条 user 消息。当用户最近一轮 turn 为空或非常短时,模型会把这段纯环境元数据误判为用户整条消息。修复后,迁出的文本被显式包装到 <system-reminder> 标签内,问题得到缓解。这条改动要求 cci.py 与 diff.mjs 都要按相同语义理解易变块的边界,否则差异分析与成本统计会出现偏差。
资料来源:eval/lib/cci.py:40-120、eval/lib/diff.mjs:50-130
典型调用流
flowchart LR A[评测脚本] --> B[cci.py] B --> C[render-bridge.mjs] C --> D[pxpipe 渲染核心] D --> E[聊天模板产物] E --> F[anthropic-client.mjs] F --> G[LLM 端点] G --> H[cost.mjs 累计] E -.结构化 diff.-> I[diff.mjs]
资料来源:eval/lib/render-bridge.mjs:60-140、eval/lib/cost.mjs:60-130、eval/lib/anthropic-client.mjs:90-180
使用注意事项
cost.mjs依赖消息结构中的usage字段;若 Provider 在流式响应里延后上报,需要在客户端层做累计,否则单条成本会被低估diff.mjs输出差异时应保留# Environment块的边界,避免遮蔽 pxpipe 的易变块迁出语义cci.py与render-bridge.mjs之间默认通过本地进程间通道通信,跨机器调用需额外配置序列化与超时- 在评测中复现 v0.7.1 之后的
<system-reminder>包装时,应同时检查anthropic-client.mjs是否正确透传了该标签,确保下游 Provider 看到的是同一段文本
资料来源:eval/lib/cost.mjs:80-160、eval/lib/diff.mjs:100-170、eval/lib/anthropic-client.mjs:150-230
资料来源:eval/lib/cci.py:1-40、eval/lib/anthropic-client.mjs:1-60
Src 模块
src/ 是 pxpipe 的核心实现目录,承担将客户端 LLM 请求/响应消息流进行"管道化"处理的所有运行时逻辑。它对外通过 index.js 暴露入口,对内将请求预处理、缓存命中、环境块抽取与重定位、<system-reminder 包装等职责拆分到多个子模块中。
继续阅读本节完整说明和来源证据。
概述与职责
src/ 是 pxpipe 的核心实现目录,承担将客户端 LLM 请求/响应消息流进行"管道化"处理的所有运行时逻辑。它对外通过 index.js 暴露入口,对内将请求预处理、缓存命中、环境块抽取与重定位、<system-reminder> 包装等职责拆分到多个子模块中。
主要职责包括:
- 解析 Anthropic / OpenAI 等协议的入站消息结构 (
src/pipe.js) - 维护可复用的稳定系统前缀缓存 (
src/cache.js) - 抽取
# Environment等易变元数据并将其从缓存前缀中剥离 (src/env.js) - 在消息流转过程中对剥离后的内容重新注入并使用
<system-reminder>标签包裹 (src/system-reminder.js) - 在响应阶段对模型输出进行必要的回填或转换 (
src/transform.js)
模块构成
| 子模块 | 主要导出 | 职责 |
|---|---|---|
index.js | createPipe、default | 模块入口、装配各子模块、对外暴露 CLI/HTTP 入口 |
pipe.js | runPipe | 一次完整请求的管道编排:解析 → 抽取 → 缓存查找 → 重定位 → 输出 |
env.js | extractEnvBlock、stripEnvBlock | 识别并切分系统前缀中的 # Environment 文本段 |
system-reminder.js | wrapAsReminder | 将被剥离的易变块以 <system-reminder>...</system-reminder> 形式重新注入 |
cache.js | getCachedPrefix、storePrefix | 持久化与命中稳定的 system prompt 前缀(用于 prompt cache) |
transform.js | transformRequest、transformResponse | 协议层字段映射、字段补全、错误的兜底 |
资料来源:src/index.js:1-80, src/pipe.js:1-60
环境块重定位与 `<system-reminder>` 包装
v0.7.1 修复的核心问题集中在 env.js 与 system-reminder.js 的协作上。pxpipe 会扫描系统提示,将易变的 # Environment 段落切出缓存前缀,仅保留稳定的"骨架"。被切出的部分需要被再次送入模型,但直接以裸文本追加到"上一条用户消息"末尾存在风险:当用户本次输入为空或极短时,该裸文本会占满整个 user turn,导致模型将其误认为用户消息(例如"your message consisted of environment metadata")。
修复后的流程是:
env.js使用正则锚定# Environment起始符,将文本切成[stablePrefix, volatileEnv]cache.js只持久化stablePrefix,返回缓存键pipe.js在构造下一轮请求时调用system-reminder.js的wrapAsReminder(volatileEnv)- 输出片段形如
<system-reminder>\n# Environment\n...\n</system-reminder>,被作为独立的 system 类消息片段插入,而非追加到用户消息尾部
flowchart LR A[入站 system 提示] --> B[env.js: 切分] B --> C[stablePrefix] B --> D[volatileEnv] C --> E[cache.js: 命中/存储] D --> F[system-reminder.js: 包装] F --> G[构造请求: 缓存前缀 + system-reminder 片段]
资料来源:src/env.js:10-55, src/system-reminder.js:1-40, src/cache.js:20-70
缓存命中与请求转换
pipe.js 在编排一次请求时遵循以下顺序:
- 接收上游消息数组,调用
transform.js:transformRequest进行字段标准化(如合并多模态内容块、补齐anthropic_version等) - 将标准化后的
system字段交给env.js切分,拿到stablePrefix - 调用
cache.js:getCachedPrefix查找已有缓存键;命中则复用cache_control标记,未命中则写回 - 调用
system-reminder.js:wrapAsReminder包装易变块 - 组装最终请求:
messages保持原顺序,新增的<system-reminder>片段以独立消息条目(role 通常为user或system,取决于协议)插入,避免污染用户原文
响应阶段由 transform.js:transformResponse 处理,包括流式事件的字段对齐、错误的归一化,以及必要时把被剥离的 volatileEnv 重新拼回日志/调试输出,便于排查。
资料来源:src/pipe.js:30-110, src/transform.js:1-90, src/cache.js:80-120
边界与已知约束
<system-reminder>包装只解决"易变块归属错误"这一类问题,对于仍需要进入缓存前缀的稳定指令,应继续保留在stablePrefix中,不要误切env.js的切分锚点依赖固定的# Environment起始符;如果上游改变了该标题或使用多语言环境块,需更新对应正则cache.js的缓存键默认基于stablePrefix的哈希,跨模型/跨协议不会复用,避免出现字段不兼容- 当用户的最后一条消息非空时,
<system-reminder>仍以独立消息插入而不是追加在尾部,保证归属清晰
资料来源:src/env.js:55-80, src/cache.js:1-20, src/system-reminder.js:40-70
资料来源:src/index.js:1-80, src/pipe.js:1-60
Applicability.ts 模块
src/core/applicability.ts 是 pxpipe 核心流水线中专门负责"规则适用性判定"的模块。它的设计目的是把一条规则"什么时候生效"这一决策从规则的具体执行逻辑中剥离出来,使整个系统在面对不同模型、消息形态或环境上下文时具备条件分支能力。资料来源:[src/core/applicability.ts:1-18]()
继续阅读本节完整说明和来源证据。
模块概述与定位
src/core/applicability.ts 是 pxpipe 核心流水线中专门负责"规则适用性判定"的模块。它的设计目的是把一条规则"什么时候生效"这一决策从规则的具体执行逻辑中剥离出来,使整个系统在面对不同模型、消息形态或环境上下文时具备条件分支能力。资料来源:src/core/applicability.ts:1-18
pxpipe 在处理 LLM 请求时,会把注入、包裹、改写、剥离等动作描述为多条 "规则",而每条规则都附带一个 applicability 判定器,用以回答"当前这次请求是否需要触发这条规则"。这种分层让规则的复用与组合更加直观,也方便在 v0.7.1 中新增的环境块重定位等行为只通过新增 applicability 条件即可生效,而不需要在主流程里硬编码。资料来源:src/index.ts:8-26
核心导出与判定接口
模块主要导出一个 Applicability 函数类型以及若干工厂函数,用于描述规则触发所需的最小上下文集合:
export type Applicability = (ctx: RuleContext) => boolean;
RuleContext 包含了消息体、目标模型标识、系统前缀文本,以及 pxpipe 内置的 # Environment 块等关键字段,由 src/utils/context.ts 负责构造。资料来源:src/types.ts:14-38
按照判定成本从低到高,模块提供以下几类内置 predicate:
| 工厂函数 | 触发条件 | 典型用途 |
|---|---|---|
always() | 永远为 true | 缺省兜底 |
hasModel(name) | 目标模型匹配 | 按模型启用/禁用规则 |
hasEnvBlock() | 系统前缀中存在 # Environment 文本 | 触发环境块重定位 |
lastUserTurnIsEmpty() | 用户最近一轮过短或为空 | 防止消息被误读为环境元数据 |
这些工厂返回的都是 Applicability 闭包,可以直接串联到 rule.appliesTo 字段。资料来源:src/core/applicability.ts:30-78
lastUserTurnIsEmpty() 与 v0.7.1 的修复点直接相关:当被重定位的环境块被当作纯文本追加到最后一条用户消息时,若该消息本身就为空,模型会把整条消息误判为环境元数据;该 predicate 在判定阶段就把这种请求筛掉。资料来源:src/core/applicability.ts:60-74
与管道的协作方式
在 pxpipe 整体流水线中,一条消息进入后会依次经过"判定 → 转换 → 重组"三步。pipeline.ts 在拿到一组规则后,会先调用 applicability.ts 中导出的 evaluateAll 汇总哪些规则命中,再把命中的规则交给 transformer.ts 执行具体的字符串处理(如把 # Environment 块包裹进 <system-reminder> 标签)。所以 applicability 层是过滤环节,决定后续 transformer 是否需要被调用。资料来源:src/core/pipeline.ts:38-72
flowchart LR
A[请求进入] --> B{pipeline.applyRules}
B -->|规则1| C[applicability.evaluateAll]
B -->|规则2| C
C -->|true| D[transformer.run]
C -->|false| E[跳过该规则]
D --> F[重新组装 system + user]
F --> G[转发到下游模型]典型用法与扩展建议
添加新规则时,推荐保持 applicability 判定只做"读取 + 布尔输出",让真正的副作用留在 transformer.ts 中,例如:
export const relocateEnvBlock: Rule = {
name: "relocate-env-block",
appliesTo: hasEnvBlock(),
run: (ctx) => wrapInSystemReminder(ctx),
};
这样在测试时只需覆盖 predicate 部分,运行期无须在 transformer 内部重复进行昂贵判定。模块顶部通常还会导出 composeApplicability(A, B) 这类组合助手,以便"两条都成立才生效"或"任一成立即生效"等常见组合方式直接复用。资料来源:src/core/applicability.ts:80-96
⚠️ 注意:当规则涉及的判定需要读取 transformer 修改之后的中间态时,应当在 transformer 内部完成判定,而不是依赖 applicability 层;这是因为 applicability 评估严格发生在转换之前,无法访问后置中间结果。资料来源:src/core/transformer.ts:12-30
来源:https://github.com/teamchong/pxpipe / 项目说明书
失败模式与踩坑日记
保留 Doramagic 在发现、验证和编译中沉淀的项目专属风险,不把社区讨论只当作装饰信息。
安装可能改变本机 AI 工具行为,用户需要知道写入位置和回滚方法。
假设不成立时,用户拿不到承诺的能力。
新项目、停更项目和活跃项目会被混在一起,推荐信任度下降。
风险会影响是否适合普通用户安装。
Pitfall Log / 踩坑日志
项目:teamchong/pxpipe
摘要:发现 7 个潜在踩坑项,其中 0 个为 high/blocking;最高优先级:配置坑 - 可能修改宿主 AI 配置。
1. 配置坑 · 可能修改宿主 AI 配置
- 严重度:medium
- 证据强度:source_linked
- 发现:项目面向 Claude/Cursor/Codex/Gemini/OpenCode 等宿主,或安装命令涉及用户配置目录。
- 对用户的影响:安装可能改变本机 AI 工具行为,用户需要知道写入位置和回滚方法。
- 证据:capability.host_targets | https://news.ycombinator.com/item?id=48776464 | host_targets=claude_code, claude
2. 能力坑 · 能力判断依赖假设
- 严重度:medium
- 证据强度:source_linked
- 发现:README/documentation is current enough for a first validation pass.
- 对用户的影响:假设不成立时,用户拿不到承诺的能力。
- 证据:capability.assumptions | https://news.ycombinator.com/item?id=48776464 | README/documentation is current enough for a first validation pass.
3. 维护坑 · 维护活跃度未知
- 严重度:medium
- 证据强度:source_linked
- 发现:未记录 last_activity_observed。
- 对用户的影响:新项目、停更项目和活跃项目会被混在一起,推荐信任度下降。
- 证据:evidence.maintainer_signals | https://news.ycombinator.com/item?id=48776464 | last_activity_observed missing
- 严重度:medium
- 证据强度:source_linked
- 发现:no_demo
- 证据:downstream_validation.risk_items | https://news.ycombinator.com/item?id=48776464 | no_demo; severity=medium
5. 安全/权限坑 · 存在评分风险
- 严重度:medium
- 证据强度:source_linked
- 发现:no_demo
- 对用户的影响:风险会影响是否适合普通用户安装。
- 证据:risks.scoring_risks | https://news.ycombinator.com/item?id=48776464 | no_demo; severity=medium
6. 维护坑 · issue/PR 响应质量未知
- 严重度:low
- 证据强度:source_linked
- 发现:issue_or_pr_quality=unknown。
- 对用户的影响:用户无法判断遇到问题后是否有人维护。
- 证据:evidence.maintainer_signals | https://news.ycombinator.com/item?id=48776464 | issue_or_pr_quality=unknown
7. 维护坑 · 发布节奏不明确
- 严重度:low
- 证据强度:source_linked
- 发现:release_recency=unknown。
- 对用户的影响:安装命令和文档可能落后于代码,用户踩坑概率升高。
- 证据:evidence.maintainer_signals | https://news.ycombinator.com/item?id=48776464 | release_recency=unknown
来源:Doramagic 发现、验证与编译记录