拒绝 Token 焦虑:OpenCode 上下文超限的终极指南

你是否遇到过 "Input length xx exceed" 的报错?或者发现 AI 好像"忘记"了之前的对话?

如果在 OpenCode 中遇到这类问题,往往是因为触发了模型的上下文限制。本文说明如何核对模型额度与配置。修改本地数值不会增加提供商实际允许的上下文,也不会改变订阅权益。

# 为什么会报错?#

首先要澄清一个误区:Input 不等于你输入的这段话。

当你按下回车时,OpenCode 实际发送给大模型的内容包含:

  1. System Prompt:OpenCode 的核心指令(定义了它是谁,能做什么)。
  2. Conversation History:之前的对话记录(为了保持上下文连贯)。
  3. Tool Outputs:工具调用的返回结果(比如读取的文件内容、终端输出)。
  4. User Input:你刚刚输入的这段话。

如果这些内容的总和超过了模型允许的 input limit,接口可能拒绝请求;OpenCode 的压缩机制会尝试减少后续请求的历史占用,但不能保证所有超限请求都能恢复。

# 核心策略:先核对模型额度,再按需覆盖#

核验日期:2026-10-12。 以下配置结构适用于 OpenCode 1.x,结合官方 自定义提供商示例↗ 与 v1.19.0 源码核验;不要直接套用到 OpenCode 2 的配置。

标准提供商的模型额度通常由 OpenCode 从 models.dev 自动读取,不需要为每个模型手填 limit。只有接入自定义模型,或确认模型元数据与服务端实际限制不一致时,才需要按提供商文档补充或覆盖。

## 配置位置与字段#

在项目的 opencode.jsonc 或全局 ~/.config/opencode/opencode.jsonc 中,模型额度的完整路径是 provider.<提供商 ID>.models.<模型 ID>.limit。limit 不是顶层字段;顶层 model 使用 提供商 ID/模型 ID。更多位置规则见 配置文档。

字段含义填写依据
context模型上下文窗口上限,单位为 token提供商对应模型与接口的文档
output模型最大输出 token 数提供商的输出限制
input可选的独立输入上限仅在提供商明确给出输入上限时填写

定义 limit 时需要包含 context 和 output。不要为了“留空间”凭空填写 input,也不要通过调大数字尝试突破服务端限制。

## 完整 JSONC 结构示例#

下面是采用 OpenAI Chat Completions 兼容接口的自定义提供商结构示例。域名、模型 ID 和额度均为占位示例,使用前需替换为真实服务的参数,并设置对应环境变量;此示例不代表任何具体模型的额度。

jsonc
1{
2  "$schema": "https://opencode.ai/config.json",
3  "model": "myprovider/my-model",
4  "provider": {
5    "myprovider": {
6      "npm": "@ai-sdk/openai-compatible",
7      "name": "My Provider",
8      "options": {
9        "baseURL": "https://api.example.com/v1",
10        "apiKey": "{env:MY_PROVIDER_API_KEY}"
11      },
12      "models": {
13        "my-model": {
14          "name": "My Model",
15          "limit": {
16            // 示例值:必须按实际服务端限制替换
17            "context": 200000,
18            "output": 65536
19          }
20        }
21      }
22    }
23  }
24}

配置后使用 /models 核对模型名称。对于已内置的提供商,应使用其真实 ID,并仅覆盖需要调整的模型字段,不必照搬上面的自定义接口配置。

## 与压缩阈值的关系#

在 v1.19.0 的阈值实现↗ 中,有独立 input 上限时会再预留缓冲;没有时则根据 context 和有效最大输出量计算可用额度。因此,省略 input 不等于不能压缩,也不能据此断言模型会退回 4096 或 8192 的小窗口。

# OpenCode 如何减少上下文占用#

即使配置了正确的 Limit,长对话还是容易超限。OpenCode 内置了三套机制来对抗这个问题,而不是简单粗暴地报错。

OpenCode 对 Input 超过 Limit 的处理方式不是切分(Split),而是通过 压缩(Compaction)、修剪(Pruning) 和 截断(Truncation) 来减少上下文的大小。

## 1. 压缩 (Compaction) —— 让 AI 帮你做笔记#

启用自动压缩时,OpenCode 会依据模型额度与 token 使用量判断是否需要压缩任务。阈值和保留策略随版本变化,以下为机制概述。

  • 原理:通过压缩 Agent 将较早的对话整理为摘要。
  • 效果:后续请求使用摘要及保留的近期内容,减少历史占用;摘要可能遗漏细节,不能保证固定的压缩比例。
  • 代码位置: packages/opencode/src/session/compaction.ts

## 2. 修剪 (Pruning) —— 遗忘不重要的细节#

在编程过程中,工具调用的输出往往非常长(比如 ls -R 的结果,或者大文件的内容)。

  • 原理:OpenCode 会修剪较早的工具输出,减少后续请求携带的详细内容,并保留近期结果;这不等于删除磁盘上的原始文件。
  • 效果:防止历史中的工具调用(Tool Calls)像滚雪球一样占满上下文。
  • 代码位置: packages/opencode/src/session/compaction.ts 中的 prune 函数

## 3. 截断 (Truncation) —— 最后的安全防线#

这是针对单次工具调用的硬性安全限制。

  • 场景:比如你让 AI 读取一个 10MB 的日志文件。
  • 处理:工具可限制单次返回的内容,向模型提供部分输出,并在支持时附上完整输出的存储路径。具体阈值和保存方式取决于工具及 OpenCode 版本。
  • 注意:工具输出限制与模型额度是不同层次的控制;调高 provider.<id>.models.<id>.limit.input 不会自动扩大每个工具的输出。

# 总结#

如果你的输入(包括历史记录)超过了 Limit,OpenCode 会尝试通过总结历史来腾出空间。它不会将你的单次长输入切分成多个块分批发送给模型(这通常需要 RAG 或其他复杂架构支持)。

因此,如果经过压缩后,单次请求的内容仍然超过模型的上下文限制,请求通常会直接被 Provider 拒绝(报错)。

先确认选中的模型与服务端额度一致,再按需修正 provider.<id>.models.<id>.limit。请求仍然超限时,应缩小单次输入或工具输出,而不是继续调高本地额度。