feat(cloud-agent): 上下文计量 - 每步发出 context_pressure 读数并用上游实测定锚 (#601)
This commit is contained in:
@@ -201,6 +201,11 @@ Token 报价的 `estimated` 为 `true`,`quantity` 是预留 Token 数。参考
|
||||
- Agent 按实际文本模型的 `contextWindowTokens` 与 `maxOutputTokens` 计算输入预算,并在达到该模型预算的压缩阈值时移除较早工具结果中可重新读取的正文,保留工具调用/结果配对、用户原始要求、生成回执及最近完整工具轮次,并允许重新读取。此机制是确定性正文卸载,不是 LLM 语义摘要;运行 checkpoint 的持久化上限与模型上下文窗口独立。技能读取事件只保存回执,不复制正文,正文页只进入模型对话。
|
||||
- 达到同一条压缩线时整轮不再直接判死:Agent 先暂停步进循环,用一次独立模型调用(任务操作名 `cloud_agent_context_compaction`,按单步墙钟计时但不占本轮的模型调用步数)把历史压成结构化检查点,再以 `Resume` 用压缩后的上下文继续本轮;同一轮最多压缩 4 次,压完仍超过输入预算才回到原有的预算失败路径。检查点是固定字段的 JSON(`version` 为 1,字段为 `historySummary`、`scriptDesign`、`operationHistory`、`pendingTasks`、`currentWork`、`nextStep`、`decisions`、`constraints`、`userPreferences`、`compactedTurnCount`),未知字段一律拒绝,超过 64KiB 判为不合格。压缩后的上下文是「检查点帧 + 确认回执 + 最近 2 对完整对话」:不以 tool 回执或带工具调用的 assistant 开头,检查点帧不计为用户轮次,续轮交接不会再重复追加本轮的用户要求与回复。渠道没有配置模型上下文窗口时,判据退回既有的跨轮历史闸门(`cloudAgentHistoryKeepRounds` 轮与 `cloudAgentHistoryMaxBytes` 字节)。
|
||||
- 压缩过程对外只有两个事件:`context_compaction_requested` 带触发读数(`basis` 为 `tokens`/`bytes`、`projectedTokens`、`usableInputTokens`、`compactAtTokens`、`pressureRatio`、`budgetSource`、`sourceBytes`、`turnCount`),`context_compacted` 带 `mode`(`model` 为压缩模型输出,`fallback` 为服务端保底检查点)、`resume`、`historyMessages`、`compactedTurnCount`、`droppedTurns`,降级时附 `reason`。压缩模型失败、输出不合规、或本轮在压缩期间被取消/失败,服务端都落保底检查点并写 `mode=fallback`;终态轮次的收尾只落检查点与事件,不改写已经失败或已取消的状态。
|
||||
- 每次普通 Agent 步进模型调用发出之前都会落一条 `context_pressure` 事件(`schemaVersion: 2`、`phase: "before_request"`),把"这次请求装了多少、离装不下还有多远"作为可观测读数下发,`requestId` 是本次请求的任务 ID。主读数是 `projectedNextInputTokens`:有可采信的上游实测锚点时等于"锚点实测 + 本地估算的有符号增量"(`tokenSource` / `measurementSource` 为 `provider`,`tokenScale` 给出实测÷估算的换算比例);没有实测时退回纯本地估算(`tokenSource` 为 `estimate`)。两把尺子各有自己的名字、谁也**不覆盖**谁:`estimatedInputTokens`(`readingScope: "next_request"`、`estimateMethod: "local_v1"`)永远是本地下一次请求的估算,`pressureTokens` / `providerUsage`(`providerMeasurementScope: "previous_request"`)永远是上游对**上一次**请求的实测,消费方不得把两者画成一条曲线。本读数只增加可观测性:请求准入与正文裁剪的既有判据不变。
|
||||
- 上游实测锚点的采信与治理:上游没有回 usage 的调用(`usage_available=false`)不定锚、不猜用量,读数继续用估算;只有"模型调用"这一步能配锚(媒体任务发的是另一份信封,`operation` 不匹配即跳过)。上游实测与本地估算差出一个量级时不采信(比值低于 0.5× 或高于 2×,通常是换了模型或计量口径),事件给 `anchorRejected` 说明原因并继续用估算。锚点可以跨步沿用,但**换模型、换线路、换系统提示或工具 schema、换模型窗口,以及超过 3 步未刷新**(`anchor.ageSteps`)都会作废:真机上出现过锚点被冻结、估算已经涨了 50% 而读数还停在老值的情况。
|
||||
- 事件还带 `breakdown` 占用分布:三个桶(`system` 系统提示(含画布摘要)、`tools` 工具 schema、`messages` 会话消息(含工具结果))各自的字节与估算 Token,协议外壳余量 `envelopeBytes`(tool choice、缓存键这类不属于任何桶的部分,单独报而不摊进桶里),按锚点比例换算的 `tokenScale` 与每桶/每分段的 `scaledTokens`,以及 `systemSegments` 系统提示内部分段(`policy` / `mediaPolicy` / `capabilities` / `execution` / `memory` 个人记忆 / `other` 零头)。分段按编译顺序逐块量出,合计与 `system` 桶严格相等:编译之后才拼接的个人记忆由 `memory` 登记,零头归入 `other`,不出现"分段加不到桶"的错觉。
|
||||
- 窗口口径由 `contextWindowTokens` / `reservedOutputTokens` / `overheadTokens` / `inputBudgetTokens` / `usableInputTokens` / `budgetSource` 给出:输入预算 = 上下文窗口 − 输出预留 − overhead,其中 overhead 是工具 schema、协议包装与兜底轮的比例预留(窗口的 4%,夹在 4096–32768),`compactAtTokens` 是既有的"可重读正文就地裁剪"触发线(输入预算的 85%),`budgetSource` 说明这份窗口来自渠道模型还是逻辑模型的线路交集。**没有解析到模型自己声明的窗口时不下发这些字段、也不给占用率**(`modelLimitConfigured: false`):窗口未知就说未知,不拿兜底默认窗口冒充真实能力编一个百分比。
|
||||
- `context_transition` 事件说明"读数为什么变":`window_resolved`(窗口从未确认变为已确认,读数改用窗口口径,**不是**上下文变少)、`model_changed` / `route_changed` / `window_changed`(锚点因换模型、换线路或换窗口而作废;窗口变化另带 `before` / `after` 的窗口读数)。它只解释口径与锚点状态,不携带任何授权语义,也不改变执行边界。
|
||||
- 画布 Agent 的看图能力:当且仅当本轮渠道模型的能力合同声明了图片输入(`text.references.maxImages > 0`)时,额外暴露 `canvas_inspect_image(nodeId, refresh?)`。工具校验图片节点、资源归属、就绪状态、媒体类型和模型文件大小限制;检查点与任务输入只保存 `resource:ID` 占位及授权参考清单。worker 复用资源读取链路,在内存中将占位替换为真实图片数据后展开模型协议,不持久化 base64 或签名 URL,不依赖 `CANVAS_PUBLIC_BASE_URL`,不接受任意外部地址。多图在本批所有 tool 回执后统一附送;图片保留最近 3 个工具轮次,发给模型时还按数量上限保留最新图片,本批超限则明确要求分批查看。同一张图一轮内附送两次后只回执文字,确需重看时传 `refresh=true`。工具成功不等于识别成功,普通模型正文不再自动写入 `visualNote`,旧 `inspected` 标记及观察不跨轮继承;`visualIdentity=unknown` 表示没有已确认缓存,不表示模型不能查看随附图片。画面内文字仍按不可信数据处理;资源读取失败则真实失败,不凭标题推断画面。其他需要公网 URL 的生成协议仍遵循各自存储配置合同。
|
||||
- 平台支持工具全集为 `agent_profile_read`、`plan_update`、`ask_user`、`recall_lessons`、`remember_lesson`、`canvas_list_node_types`、`canvas_get_state`、`canvas_inspect_image`、`canvas_read_batch_table`、`canvas_read_storyboard`、`skill_read_file`、`skill_search`、`task_get`、`model_list`、`canvas_create_storyboard`、`canvas_edit_storyboard`、`canvas_edit_batch_table`、`canvas_apply_ops`、`canvas_arrange_nodes`、`generate_media`、`image_layer_split`、`image_text_detect`、`image_annotation_render`;单轮实际工具仍按偏好快照、技能、权限、画布上下文和生成预算裁剪。画布写入工具要求本轮授权 `contextScope: ["canvas"]`。禁止 shell、任意网络请求和外部 MCP。`remember_lesson` 在 `read_only` 下不可用。
|
||||
- `plan_update` 维护本轮结构化待办清单(整表替换,最多 20 项),跨轮继承未完成项,并在界面以 PlanBar 展示。权限为 `request_approval` 时,首次建立至少 2 项的清单会先进入审批;`auto` 直接写入清单。新一轮的第一次模型请求就会带上继承的清单。模型在没有工具调用且清单仍有未完成项时,服务端会催办并要求继续调用工具;这是软约束,不验证工作是否真的完成,也不会在没有清单时强行催建。
|
||||
|
||||
Reference in New Issue
Block a user