ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

【Bug已解决】Fireworks forwards unsupported file content blocks

【Bug已解决】Fireworks forwards unsupported file content blocks 【Bug已解决】Fireworks forwards unsupported file content blocks一、现象长什么样ChatFireworkslangchain-fireworks 对接 Fireworks AI 的聊天模型在收到多模态内容时会把里面所有 content block 原样转发给 Fireworks API。但 Fireworks 的聊天接口不支持file类型的 content block它支持文本、图片 URL但不支持文件块如 PDF/文档作为{type: file, ...}。于是当你传一条含file块的消息比如从多模态 pipeline 过来的、或用户上传了文档ChatFireworks直接把它塞进请求体Fireworks 服务端返回400: unsupported content block type file整个请求失败。更隐蔽的是有时消息里混着文本 文件文本本身是合法可答的但就因为那个不支持的file块被一起转发整条消息被拒连文本部分也答不了。二、背景不同模型提供商的多模态能力边界不同Anthropic支持文本、图片、部分文件。OpenAI支持文本、图片、文件某些模型。Fireworks主要支持文本 图片 URL不支持file块。LangChain 的BaseMessage.content可以是list[dict]混合块文本、图片、文件。ChatFireworks的转换逻辑应当按 Fireworks 支持的白名单过滤/转换content blocks把不支持的file剥离或转成支持的形态如把文件内容抽成文本再附上。但它直接透传导致服务端拒绝。三、根因根因两点未做能力白名单过滤转换不检查 Fireworks 支持的 block 类型把file等不支持块原样转发。无优雅降级遇到不支持块要么全拒要么应将其转换为支持的形态如读取文件文本但都没有。本质把通用多模态 content当成Fireworks 一定支持直接转发忽略了提供商能力边界。四、最小可运行复现下面缩略逻辑复现转发被拒def bad_convert(content): # 直接透传所有 block return [b for b in content] # file 块也原样留下 msg [ {type: text, text: 总结这份文档}, {type: file, file: {file_id: x}}, # Fireworks 不支持 ] fireworks_request {messages: [{content: bad_convert(msg)}]} # Fireworks 返回 400: unsupported content block type file修复按支持白名单过滤把file转成文本或剥离。SUPPORTED {text, image_url} def good_convert(content): out [] for b in content: if b[type] in SUPPORTED: out.append(b) elif b[type] file: # 降级把文件内容抽成文本附上示意 out.append({type: text, text: f[文件内容] {extract_text(b)}}) return out五、解决方案第一层最小直接修复最小修法在ChatFireworks转换时维护一个支持块类型白名单剥离/转换不支持的file块转文本或丢弃并告警。class ChatFireworksPatch: SUPPORTED_BLOCKS {text, image_url} def _to_api_content(self, content): if isinstance(content, str): return content out [] for block in content: t block.get(type) if t in self.SUPPORTED_BLOCKS: out.append(block) elif t file: # 降级为文本避免整条被拒 out.append({type: text, text: f[file] {block.get(file, {}).get(file_id, )}}) else: # 其他不支持块记录并跳过 logger.warning(dropping unsupported block type: %s, t) return out or content这一层让含file块的消息不再被服务端拒。六、解决方案第二层结构化改进把Fireworks 内容块能力策略固化成策略对象作为单一事实来源明确支持白名单与降级方式。from dataclasses import dataclass, field from typing import Dict, List dataclass(frozenTrue) class LangChainFireworksFilePolicy: ChatFireworks 内容块能力策略的单一事实来源。 supported_blocks: List[str] field(default_factorylambda: [text, image_url]) file_block_action: str convert_to_text # convert_to_text | drop | error warn_on_drop: bool True def convert(self, content: list) - list: out [] for b in content: t b.get(type) if t in self.supported_blocks: out.append(b) elif t file: if self.file_block_action convert_to_text: out.append({type: text, text: f[file] {b.get(file, {})}}}) elif self.file_block_action drop: if self.warn_on_drop: logger.warning(dropped file block) else: raise ValueError(funsupported file block, no action) else: if self.file_block_action ! error: if self.warn_on_drop: logger.warning(unsupported block %s, t) return out def validate(self) - None: if file in self.supported_blocks: raise AssertionError(Fireworks does not support file blocks)转换逻辑用policy.convert能力边界集中、可测。七、解决方案第三层断言 / CI 守护用 pytest 锁死过滤import pytest from policy import LangChainFireworksFilePolicy as P def test_file_converted_to_text(): p P() content [{type: text, text: hi}, {type: file, file: {file_id: x}}] out p.convert(content) assert all(b[type] in p.supported_blocks for b in out) assert any(b[type] text for b in out) def test_unsupported_not_forwarded(): p P() content [{type: file, file: {}}] out p.convert(content) assert not any(b.get(type) file for b in out) def test_file_not_in_supported(): with pytest.raises(AssertionError): P(supported_blocks[text, file]).validate() def test_drop_action(): p P(file_block_actiondrop) out p.convert([{type: file, file: {}}]) assert out []CI 加一条ChatFireworks单测必须构造含file块的消息断言转换后请求体不含file类型。八、排查清单Fireworks 回400 unsupported content block type file→ 转换透传了不支持的 file 块。是否按提供商能力白名单过滤→ Fireworks 只支持 text/image_url。file 块能否降级为文本→ 转成文本附上避免整条被拒。其他不支持块是否也透传→ 统一走 policy.convert。是否静默丢块→ 应 logger.warning。是否有不含 file 类型测试→ 必须有。九、小结ChatFireworks把不支持的file类型 content block 原样转发给 Fireworks API导致服务端 400、整条消息被拒。根因是转换未做提供商能力白名单过滤与降级。第一层按支持块白名单剥离/转换file块第二层用LangChainFireworksFilePolicy把能力边界固化成单一事实来源第三层用 pytest 守护请求体不含 file 类型。多模态转换的通用原则转发内容块前必须按目标提供商支持的白名单过滤/降级绝不平铺透传。
返回列表