统一三协议工具调用归一,禁止静默丢弃
非流式 DTO 为兼容流式分片改成可选字段后,filter_map 会把缺 id / name / function 的工具调用逐个丢掉;响应同时带解说文本时整个响应被当作普通文本 回复成功返回,带 tool_choice=required 的请求随后退化为格式修复循环,审计 里看不出成因在解析层。Responses 与 Anthropic 的提取有同类缺陷。 把策略收进单一入口 normalize_tool_calls:协议层只做字段映射,识别为工具 调用后字段不全一律返回 Deserialize;arguments 缺省或空白归一为空对象, 非空则必须是完整 JSON。流式收尾改为委派同一入口,行为不变。 顺带修正两处口径不一致:Chat 缺 arguments 从空串改为空对象,Responses 缺 arguments 从整条丢弃改为空对象(零参函数合法)。非流式 arguments 半截 JSON 由此改为显式失败,上游 max_tokens 截断会命中。 补 9 个非流式用例,含缺 id 且有正文不得退化成纯文本回复的回归锁,以及三 协议同一缺失形状必须同类报错的一致性用例。
This commit is contained in:
@@ -257,7 +257,9 @@ npm run check:server-rs-ddd
|
||||
|
||||
流式 `on_delta` 只发送文本增量、累计文本和完成原因,工具调用不进入回调。平台层按协议 slot 聚合并行工具片段:Chat 使用 `delta.tool_calls[].index`,Responses 使用 `output_index`,Anthropic 使用 content block `index`。Responses 的 `function_call_arguments.done` 和 `response.completed` 中的完整 arguments 覆盖此前分片;completed-only 恢复以 `response.output[]` 数组下标作为 slot。该聚合只负责解析,不表示工具执行并发。
|
||||
|
||||
流式收尾时,缺少工具 id / name、或非空 arguments 不是完整 JSON,均返回 `Deserialize`;空 arguments 默认归一为 `{}`。这只是 JSON 语法完整性检查,不是按工具 `parameters` 执行 JSON Schema 校验。非流式 Anthropic 缺失 `tool_use.input` 时也归一为 `{}`;其它协议的非流式 arguments 仍按上游字段解析。
|
||||
工具调用归一只有一份策略,流式与非流式、三种协议共用:协议层只把各自 DTO 映射成统一中间形态,接受与否全部由归一层判定。**被识别为工具调用(Chat 的 `tool_calls[]` 成员、Responses 的 `type=function_call`、Anthropic 的 `type=tool_use`)后,字段不全一律返回 `Deserialize`,不得静默丢弃。** 缺少 id 或函数名报错;arguments 缺省或空白归一为 `{}`(零参函数合法);arguments 非空则必须是完整 JSON,否则报错。这只是 JSON 语法完整性检查,不是按工具 `parameters` 执行 JSON Schema 校验。
|
||||
|
||||
静默丢弃是明确禁止的实现方式:它会把“上游给了工具调用但我们没解出来”伪装成“上游只回了正文”——响应同时带解说文本时更会被当作普通回复成功返回,而带 `tool_choice=required` 的请求随后退化为格式修复循环,审计里只能看到“模型没按协议调用工具”,看不出真正成因在解析层。非流式 DTO 为兼容流式分片把字段改成可选后尤其要注意:可选字段解除了 serde 的强制校验,缺失必须在归一层重新拦截。
|
||||
|
||||
流式工具调用必须来自已收尾的流:只要聚合出过工具 slot,收尾时就必须已观察到本协议的完成信号,否则按截断返回 `Deserialize`。完成信号按协议判定——Chat 为非空 `choices[].finish_reason` 或 `data: [DONE]`,Responses 为 `response.completed`,Anthropic 为带 `stop_reason` 的 `message_delta` 或 `message_stop`。不能用 `data: [DONE]` 作为统一判据:MiniMax 兼容层不发该标记,只发 `finish_reason`。也不能只用 “参数是合法 JSON” 当完成证明——顶层花括号闭合只说明单个参数对象字节完整,说明不了模型是否还要发下一个工具块,更说明不了上游随后会不会报 `max_tokens` 或 error;代理超时、网关自行掐断和 HTTP/2 提前 `END_STREAM` 都表现为干净 EOF,与正常收尾在字节层无法区分。该门禁当前只覆盖工具路径;纯文本响应缺完成信号仍按成功返回并打 warn,改动前必须先确认所有在用网关的文本收尾行为。流在任何工具分片到达前就断掉时槽位为空,门禁无从触发,这是已知残留缺口。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user