Skip to content

模型与上下文 ​

ZettCode 能对接任何 OpenAI 兼容的接入点:云上的 API、把多家 provider 聚在一起的网关,或者跑在 你自己机器上的模型。它需要知道的东西都在配置参考里。

切换 ​

/model 会在对话之上弹出选择面板。Enter 选定的是之后的请求 —— 正在跑的那一次不受影响 —— 头部会立刻显示新名字。/model DeepSeek Pro 也可以,它会同时匹配显示名和模型 id,适合你很清楚 想要哪个的时候。

每个模型有各自的 token、接入点和窗口,所以在本地服务和云服务之间切换只要按一个键,而不是改 配置再重启。

例如,按双模型配置添加 DeepSeek Pro 和 DeepSeek Flash, 然后依次尝试:

text
/model DeepSeek Pro
先解释这个模块的设计取舍,不要急着修改。
/model DeepSeek Flash
看看这张截图,说明错误信息是什么意思。

截图请求需要实际附加图片,并且对应模型配置了 multimodal = true。切换模型不会自动附加 图片,也不会清空对话。想从没有历史的状态开始,应使用 /new。

推理强度 ​

/effort 决定模型在回答前愿意想多久:

档位适合什么
off请求不做刻意思考,实际取决于接入点支持。
minimal一点点思考,最快。
low小改动时的快速回答。
medium默认的平衡点。
high难题多想一些。
xhigh难题上长时间思考。
maxprovider 能接受的最高预算。
ultra请求最高档位,是否可用取决于接入点。

档位影响本次程序运行中的后续请求,头部会显示当前选择,不是写入 config.toml 的永久设置。 例如:

text
/effort low
解释这个正则表达式匹配什么。
/effort high
检查这段加锁代码是否可能死锁或发生竞争,先不要修改。

实际思考预算由接入点决定,不是所有接口都支持所有档位。网关可能映射不支持的值,也可能 直接拒绝。DeepSeek 当前的映射规则见 Thinking Mode。 当前客户端在 Chat Completions 下使用 /effort off 时,只会省略 reasoning_effort, 不会发送 DeepSeek 单独的 thinking 开关。因此不能保证关闭默认已开启的供应商思考模式。

上下文窗口 ​

每个模型都有上限。ZettCode 会跟踪用量 —— 状态行里的 ctx 34.0%,以及 /context 里的完整 明细 —— 并按模型配置里的 compact_percent 在溢出之前压缩。

Context  103,241 / 128,000 tokens
  Source              Share    Count
  System prompt        1.9%      (1)
  Environment notes    4.8%      (2)
  Tool schemas        10.9%      (9)
  User messages        0.1%      (3)
  Assistant messages  22.2%     (12)
  Tool output         60.1%     (17)
~4 chars/token · esc back

标题拿总量和模型的窗口比;百分比是当前上下文内部的占比,所以加起来是 100%。如果某一行 大得意外,那就是该看的地方:一个你从不使用的工具 schema,或者一次读文件返回的长内容。页脚会 说明这些数字是谁算出来的 —— 能加载编码时是 tiktoken,否则是按每四个字符一个 token 估算。

两种百分比要分开理解:

显示位置计算方式例子
状态行的 ctx当前上下文 token ÷ 配置的窗口大小1,000,000 的窗口用了 100,000,显示 ctx 10.0%。
/context 的分类行这一类的 token ÷ 当前上下文总 token总共 100,000,其中工具输出 60,000,工具输出占 60.0%。

分类占比在显示舍入前加起来是 100%。Count 表示对应分类的消息、工具定义或指令条目个数, 不是对话轮数。恢复的会话也可以查看;当前进程尚未组装工具和环境说明时,页脚可能显示 notes and tools pending,说明这还是一份不完整的快照。

压缩 ​

当最新一次请求将要越过触发线时,对话会先被总结:较早的部分变成一条摘要消息,触发线的最后四分之一 原样保留,所以模型保住了眼前的上下文,只丢掉已经说过的内容。/compact 可以立刻做这件事。

摘要是作为一种独立的记录存下来的,而不是删除。这就是为什么对话里会以 Conversation checkpoint 收尾,为什么会话列表仍然准确,以及为什么昨天压缩过的会话今天还能 正确恢复。手动触发时只有最后一轮会原样保留,而自动压缩会留下触发线的四分之一。

压缩的代价

总结本身是一次模型调用,所以要花几秒钟 —— 期间对话里会显示 Compacting。早做比晚做好:不然 你就得在自己正忙着的时候面对接入点报错。如果摘要并不比原文更短,ZettCode 会直接说明并保留 原文。

对话进行了几轮,或者读过很大的文件之后,可以依次尝试:

text
/context
/compact
/context

每次用 Esc 关闭上下文面板,再输入下一条命令。/compact 立即开始生成摘要,期间显示带动画的 Compacting。对比前后报告:较早的内容由摘要替代,近期工作上下文仍然保留。 它不是 /clear:压缩会改变后续发给模型的内容,清屏只改变可见的对话。

如果最新的 checkpoint 已经覆盖当前对话,再手动压缩会被拒绝并提示。先继续对话,再考虑压缩。 摘要可能省略细节;需要准确原文时,让模型重新读取对应文件。

读懂那些数字 ​

↑18.4k ↓900 · 71.2% cached · 74 tok/s · ctx 12.3% —— 依次是:发出的 token 数、生成的 token 数、输入中命中 provider 缓存的比例、按模型耗时平均的生成速度,以及最新一次请求的窗口 占用。输入和输出总量在会话内累加;上下文占用是快照,不是不断累加的百分比。

字段应该怎么理解
↑ / ↓供应商上报的累计输入和输出 token。历史上下文重复发送时,每次都会算输入。
cached累计缓存命中输入 token ÷ 累计输入 token。100,000 输入里命中 60,000,就是 60.0%。
tok/s输出 token 除以测得的模型耗时,不是含工具、审批和阅读时间的整轮墙钟耗时。
ctx最近的上下文占用相对于所选模型配置窗口的比例。

接入点没有上报缓存命中数量时,这里无法得到有意义的命中率。这些统计不是账单,实际收费 应查看供应商控制台。

缓存这一项值得理解,因为时间和钱都花在这里。provider 缓存的是请求的前缀:如果一次请求的 开头和上一次逐字节相同,这一部分就更便宜、更快。这就是系统提示只写日期不写时间、项目指令按 固定顺序读取、以及可以在两轮之间随手打开 /context 的原因 —— 稳定的前缀有利于复用缓存。 不存在通用的“好命中率”:切换模型、压缩、工具定义变化和供应商缓存有效期都可能让比例下降。 新生成的输出,只有在之后的请求中作为输入发回去,才可能成为命中的输入缓存。

以 MIT 许可证发布。