feat(llm): 模型配置新增输出上限,支持 max_completion_tokens 字段名

llm_profiles 加两列:max_tokens(单次回复输出上限,0=不发送该字段,由服务端
默认值决定)与 max_tokens_field(上限发哪个键)。后者仅对 format=openai 生效:
空(默认)= max_tokens;'max_completion_tokens' = 新键。OpenAI 推理模型
(o 系列/GPT-5)拒收 max_tokens、只认新键,而多数兼容网关反过来只认旧键,
故做成显式开关而非自动推断。anthropic 与 openai-responses 自带字段名,
存下来只会误导,保存时一并清空。

顺带补上一处从未接通的链路:planner/worker/chat/mainagent/goals 五个
agentcore.Options 都没设过 MaxTokens,恒为 0——openai 系因 omitempty 压根
不发上限,anthropic 走 norma 的 8192 兜底。光加配置项而不接这条线,用户在
后台填了数字也不会生效,故本次一并接通,取值与 streaming 一样按 profile
每轮解析,故障转移切换后下一轮即生效。

task_llm.go 里 nonStreaming() 的来源优先级(agent 绑定 → 任务链激活 profile
→ 全局)抽成共用的 activeCfg(),避免 maxTokens() 再抄一份同样的三级回退。

norma 升到 v0.3.3(该版本提供 Config.MaxTokensField)。go.mod 只动 norma 这
一行:仓库此前未 tidy 过,跑 go mod tidy 会顺带升 x/crypto、x/net 等一批无关
依赖,不混进本次改动。

迁移:新列走 ADD COLUMN IF NOT EXISTS + 默认 0/'',旧库升级后行为完全不变;
CHECK 约束限定取值,每次启动先删后建保持幂等。
This commit is contained in:
Autumn-27 committed 2026-08-31 12:20:31 -04:00
1 parent 338e77c064
commit 7cc467c159
20 files changed
+364 -33

No files matched your search

+2
View File
@@ -721,6 +721,8 @@ export const api = {
priority?: number; // 轮询顺位,越大越先用
pool_exclude?: boolean; // true=不作为故障转移目标
streaming?: boolean; // true(默认)=流式 | false=非流式
max_tokens?: number; // 单次回复输出上限;0=不发送,由服务端默认值决定
max_tokens_field?: string; // ""=max_tokens(默认) | "max_completion_tokens"(仅 openai 格式)
}) => post<{ id: number }>("/llm/profiles", p),
deleteLLMProfile: (id: string) => del<{ deleted: number }>(`/llm/profiles/${id}`),
activateLLMProfile: (id: string) => post<{ ok: boolean }>("/llm/profiles/active", { id: Number(id) }),
+6
View File
@@ -3017,6 +3017,9 @@ export const llmProfiles: LLMProfile[] = [
is_default: true,
priority: 0,
pool_exclude: false,
// anthropic 的字段名固定,故 max_tokens_field 恒为空。
max_tokens: 0,
max_tokens_field: "",
},
{
id: "2",
@@ -3033,6 +3036,9 @@ export const llmProfiles: LLMProfile[] = [
is_default: false,
priority: 10,
pool_exclude: false,
// openai 格式 + 推理模型:上限走 max_completion_tokens。
max_tokens: 8192,
max_tokens_field: "max_completion_tokens",
},
];
+6
View File
@@ -904,6 +904,12 @@ export interface LLMProfile {
pool_exclude?: boolean;
// true(默认)= 流式(SSE) | false = 真·非流式(stream:false,一次性返回)。
streaming?: boolean;
// 单次回复的输出上限(token)。0 = 不发送该字段,由服务端默认值决定。
// 注意与 context_window_k 区分:后者是模型总容量,只在本地用于压缩阈值。
max_tokens?: number;
// 上限用哪个请求字段名,仅 format="openai" 有意义:
// ""=max_tokens(默认) | "max_completion_tokens"(OpenAI 推理模型只认它)
max_tokens_field?: string;
}
// ---- LLM 轮询(故障转移)----