Skip to content

refactor(harness): unify context token accounting and charge provider default output schemas - #3570

Open
dargoner wants to merge 17 commits into
agentscope-ai:mainfrom
dargoner:refactor/unify-context-token-accounting
Open

dargoner wants to merge 17 commits into
agentscope-ai:mainfrom
dargoner:refactor/unify-context-token-accounting

Conversation

@dargoner

Copy link
Copy Markdown
Contributor

AgentScope-Java Version

2.1.0-SNAPSHOT (based on main @ 5f7f8e6)

Description

Background

Context-budget accounting was spread across several call sites with different conventions: the final-request budget ignored provider-level default output schemas (Ollama format, OpenAI/OpenAI-Responses response_format, and the Anthropic/DashScope/Gemini equivalents) that the adapters actually send on the wire; media charging was duplicated between estimators; and the pruning pass accumulated token counts in int, which can overflow on very large histories.

Changes

  • Unified accounting service (TokenAccountingService, MediaTokenEstimator): a single place that prices a request (text + tools + media + output reservation + response-format schemas), reused by budget checks, compaction and tests.
  • Effective model options (Model, SessionModels, ReActAgent, HarnessContextBuilder): models expose getDefaultOptions() / resolveOptions(); the context builder budgets what the provider will actually send (explicit options merged over provider defaults). Default response schemas are now charged for OpenAI, OpenAI official (Responses), DashScope, Anthropic, Gemini and Ollama, with format semantics aligned to the provider's effective wire format (including JSON-representation detection for Ollama object schemas).
  • Prune accounting hardening (ConversationCompactor, TokenCounterUtil): accumulation widened to long and per-result accounting aligned with the retained/pruned split.
  • Regression tests that exercise the real adapter classes so default-schema pricing cannot silently drift.

Tests

  • New: ContextBudgetRegressionTest (9), ProviderDefaultSchemaBudgetTest (21), TokenAccountingServiceTest (10).
  • Updated: HarnessContextBuilderTest 8 → 12, ConversationCompactorTest extended.
  • Full 13-module reactor build after rebase onto main: 6433 tests, 0 failures / 0 errors (43 environment skips).
  • mvn spotless:check passes.

Checklist

  • Code has been formatted with mvn spotless:apply
  • All tests are passing (mvn test)
  • Javadoc comments are complete and follow project conventions
  • Related documentation has been updated (e.g. links, examples, etc.) — N/A for this change (internal accounting; Javadoc covers the new APIs)
  • Code is ready for review

TokenAccountingService 收敛 estimator、固定开销与最终预算调用点;
新增 MediaTokenEstimator 与 TokenCounterUtil 适配层,ContextTokenEstimator
的近似实现改由其驱动。
TokenAccountingService 新增 countBlocks/messageOverhead,TokenCounterUtil
暴露 calculateBlockToken/calculateMessageOverhead;prune 的 minimumTokens
只累计入选块的 token 成本并计一次消息开销,避免同消息内 excluded 大块
借出配额越过阈值;累计变量改为 long 避免超大输入整数回绕。
TokenSurface 增加 responseFormat 维度、TokenEstimate 增加独立计费桶,
默认 estimator 从 GenerateOptions 读取;fixed estimate 按其扣除一次会话
预算,final estimate 计入一次,trigger/keep 算法不变。补充计费桶单次
计入、大 schema 触发预算拒绝、schema 压缩会话预算三处回归。
新增 responseFormat 计费桶后保持无结构化输出 schema 场景的构造兼容。
core:Model 新增 getDefaultOptions()(默认 null),SessionModels.Recorded
包装与 ReActAgent 故障转移匿名模型透传,DashScope/OpenAI/Anthropic/Gemini
返回各自默认配置;harness:ContextTokenEstimator 按
GenerateOptions.mergeOptions(请求, 默认) 计价生效 schema,请求级优先。
补充默认 schema 等值计价、请求级覆盖与预算拒绝回归。
…ex r4)

OpenAIResponsesChatModel 的 getDefaultOptions() 返回 configuredOptions;
OllamaChatModel 将 schema format 反向映射为 ResponseFormat.jsonSchema 后
返回。harness 增加 ollama/openai-official test 依赖,新增
ProviderDefaultSchemaBudgetTest 走真实适配器验证默认 schema 等值计价、
请求级覆盖与超预算拒绝。
Model 新增 resolveOptions(requestOptions) 钩子(默认 getDefaultOptions
合并),ReActAgent 故障转移模型与 SessionModels.Recorded 透传;Ollama
覆写以镜像发送路径的 format 语义,修正 text 覆盖漏计与 body param
覆盖误计;estimator 改经钩子解析有效选项。补充真实适配器回归。
withSchemaProjection 保留转换后的全部映射字段,仅将对象形 format 投影为
计价的 response format;对象识别改为按发送侧 JSON 表示(Map 直用,其余经
codec 尝试绑定),非对象值不投影。补充 ObjectNode 计价与发送 JSON 回归。
HarnessContextBuilder.inputLimit 经 resolveOptions 并入模型有效默认
maxTokens/maxCompletionTokens;CompactionConfig 文档对齐边界准备器
(allowance 触发)与 standalone onReasoning 两条路径的预算口径。
四类媒体与嵌套工具媒体的触发估值和最终预算精确一致,媒体桶按块计一次。
anthropic/dashscope/gemini/openai 断言默认 response schema 与显式同价、
请求级覆盖默认,OpenAI 非流式线级验证默认 schema 到达 wire;输出预留与
窗口回退改为手算精确临界值。pom 增加四个 model extension test 依赖。
@dargoner
dargoner force-pushed the refactor/unify-context-token-accounting branch from b248f4f to f1ee22c Compare October 18, 2026 13:13

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants