Atoms多模型同时调用返回格式统一处理
为避免业务代码中充斥着大量的if-else解析逻辑,需要统一Atoms多模型的返回格式。这可以通过Atoms Adapter基类来实现,具体包括定义统一的响应结构、强制实现parse_response()方法、标准化流式SSE解析、归一化错误码以及设置Token统计字段。如此一来,就能实现模型切换时无需对业务代码进行任何修改。

为什么需要统一Atoms多模型返回格式
当你在同一服务中同时调用DeepSeek、通义千问和GLM这三个模型进行结果比对时,会惊讶地发现,每个模型返回的JSON结构竟然完全不同。DeepSeek使用的是choices[0].message.content,通义千问用的是output.text,而GLM呢,居然把答案藏在了result.choices[0].message.content里。这可就麻烦了,业务代码里到处都是if-else判断,要是再添加个新模型,连解析逻辑都得改三处!
用Atoms Adapter基类统一响应结构
第一步:定义统一响应数据类,强制所有适配器返回相同字段
第二步:在AtomsAdapter抽象基类中声明parse_response()为抽象方法,要求子类必须实现解析逻辑
第三步:各厂商适配器继承该基类,各自覆盖parse_response(),把原始响应映射到统一字段content、usage.input_tokens、usage.output_tokens、model
这一步不能跳过——
【未实现parse_response会导致调用直接抛AttributeError】
response.content这个字段。
处理流式响应的SSE字段名差异
方法一:DeepSeek兼容模式下,SSE data行是{"choices":[{"delta":{"content":"a"}}]}
方法二:通义千问返回{"output":{"text":"a"},"request_id":"xxx"},且不带data:前缀,需手动补全
方法三:GLM的流式响应是{"result":{"choices":[{"delta":{"content":"a"}}]}},嵌套两层
统一做法:在适配器的stream_parse()方法中,先用正则提取原始data行,再根据self.vendor字段分支解析,最后统一封装成{"content": "a", "finished": false}格式输出
错误码归一化处理
1. 拦截原始HTTP响应状态码与body
2. 将OpenAI的429 {"error": {"type": "rate_limit_exceeded"}} → 转为{"code": "RATE_LIMIT", "message": "请求超频"}
3. 将通义千问的400 {"code": "InvalidParameter", "message": "model not found"} → 同样转为{"code": "MODEL_NOT_FOUND", "message": "模型不存在"}
4. 所有厂商的鉴权失败(401/403)统一映射为{"code": "AUTH_FAILED", "message": "API密钥无效"}
前端只需监听code字段做toast提示,不用再维护五套错误文案。
Token统计字段标准化
DeepSeek返回usage.total_tokens,通义千问只有usage.input_tokens和usage.output_tokens,GLM干脆不返回usage字段
解决方案:在适配器parse_response()末尾插入token估算逻辑——当原始响应无usage时,用len(tokenizer.encode(content))反向估算输入+输出token数
注意:通义千问的input_tokens字段名是snake_case,而DeepSeek用camelCase,统一转为input_tokens和output_tokens小写下划线命名
-
- 元宵节猜灯谜的祝福短信
- 角色扮演 |
-
- 关于柯南的沙雕网名有哪些
- 角色扮演 | 1
- 网名
-
- 最新中性名字男女通用网名有哪些
- 角色扮演 | 1
- 网名
-
- 关于蓝色说唱的网名有哪些
- 角色扮演 | 1
- 网名
-
- 我好喜欢你是什么梗?
- 角色扮演 |