一、同一套模型,换个框架就翻车
跑通一个框架,你会产生一种错觉:"我会接大模型了。" 直到你拿同一把 DeepSeek key,换下一个框架,第一行就崩——而且每个框架崩得都不一样:
- pydantic-ai 说:参数改名了,你还在用旧名字;
- OpenAI Agents SDK 说:默认模型是 GPT,不是你的 DeepSeek;
- AutoGen 说:这模型不在我表里,你自己交代清楚它有什么能力。
我横向试了 pydantic-ai、OpenAI Agents SDK、AutoGen 三个框架(外加主线的 AgentScope),把每个框架接 DeepSeek 时炸的坑记了 6 条。这篇按框架拆开讲——看懂"每个框架的脾气",比会用一个框架更有用。换过框架的都懂:上一套跑得好好的,换一个第一行就崩,崩法还不重样。
二、pydantic-ai 的两个坑:改名 + thinking 互斥
坑 1:result_type 没了,result.data 也没了(EC-004)
现象:照老教程写结构化输出,创建 Agent 直接崩:
TypeError: Agent.__init__() got an unexpected keyword argument 'result_type'
改完这一处,下一行又崩 result.data 不存在 → AttributeError。
为什么容易误判:报错只说"unexpected keyword argument",不告诉你该换成什么。你代码看着挺对啊——教程上就是这么写的。
根因:pydantic-ai 迭代极快,2.x 把 1.0 前的命名全换了:声明结构化输出 result_type → output_type;读结果 result.data → result.output。
修法:
<span>from</span> pydantic_ai <span>import</span> Agent
agent = Agent(
<span>"openai:deepseek-v4-flash"</span>,
system_prompt=<span>"你是护肤顾问,输出结构化产品推荐。"</span>,
output_type=Product, <span># ← 原 result_type</span>
)
result = agent.run_sync(<span>"推荐一款适合干性皮肤的产品"</span>)
product: Product = result.output <span># ← 原 result.data</span>
防错口诀:用 pydantic-ai 一律按 2.x 命名写(output_type + result.output),别抄老教程;import 或参数名报错时先 pip show pydantic-ai 看版本、再对着 pydantic-ai 官方文档(ai.pydantic.dev)核对。
坑 2:DeepSeek 思考模式不支持 tool_choice,结构化输出 400(EC-005)
现象:坑 1 修好后重跑,又崩在请求被服务端直接拒绝:
pydantic_ai.exceptions.ModelHTTPError: status_code: 400, model_name: deepseek-v4-flash,
body: {'message': 'Thinking mode does not support this tool_choice', ...}
为什么容易误判:报错来自 DeepSeek 服务端(不是你代码、也不是框架 bug),但 traceback 一长串,第一眼会以为是框架配置错了。这个坑 LangChain、Cherry Studio 等全中招——V4 模型默认强制思考模式,而思考模式下 tool_choice 不可用。
根因:结构化输出(output_type=Product)底层用 tool_choice="required" 强制模型调工具返回 JSON;DeepSeek v4 默认开 thinking,thinking 模式不支持 tool_choice → 400。
修法(两处同时改):
agent = Agent(
<span>"openai-chat:deepseek-v4-flash"</span>, <span># ① openai: → openai-chat:,走 Chat Completions API(最稳)</span>
system_prompt=<span>"你是护肤顾问,输出结构化产品推荐。"</span>,
output_type=Product,
model_settings={<span>"extra_body"</span>: {<span>"thinking"</span>: {<span>"type"</span>: <span>"disabled"</span>}}}, <span># ② 关思考模式(关键)</span>
)
防错口诀:DeepSeek v4 做结构化输出 / 工具调用前,先关思考模式——任何框架通用 extra_body={"thinking": {"type": "disabled"}}。不想关思考就换非推理模型 deepseek-chat。
三、OpenAI Agents SDK 的两个坑:默认模型 + tracing 噪音
坑 3:不传 model,SDK 默认拿 GPT 去问 DeepSeek → 400(EC-008)
现象:配好 OPENAI_BASE_URL=https://api.deepseek.com 后跑 Runner.run_sync,直接 400:
openai.BadRequestError: Error code: 400 - {'error': {'message':
'The supported API model names are deepseek-v4-pro or deepseek-v4-flash,
but you passed gpt-5.6-luna.', ...}}
为什么容易误判:看到 400 + BadRequestError 就怀疑 key 错了——key 没错,DeepSeek 也连上了,只是模型名不对。
根因(两层):① SDK 的 Agent 不传 model 时默认用 gpt-5.6-luna,DeepSeek 不认;② SDK 默认走 Responses API(client.responses.create),DeepSeek 对 Chat Completions 支持最稳,Responses 兼容性差。
修法:用 OpenAIChatCompletionsModel 桥接(官方推荐的"接非 OpenAI 提供商"姿势):
<span>from</span> agents <span>import</span> Agent, Runner, OpenAIChatCompletionsModel
<span>from</span> openai <span>import</span> AsyncOpenAI
external_client = AsyncOpenAI(api_key=os.environ[<span>"DEEPSEEK_API_KEY"</span>],
base_url=<span>"https://api.deepseek.com"</span>)
model = OpenAIChatCompletionsModel(model=<span>"deepseek-v4-flash"</span>,
openai_client=external_client)
agent = Agent(name=<span>"导购小导"</span>, instructions=<span>"你是护肤导购。"</span>, model=model) <span># 必须显式传</span>
result = Runner.run_sync(agent, <span>"推荐一款适合干性皮肤的产品"</span>)
<span>print</span>(result.final_output)
防错口诀:接 DeepSeek / 任意非 OpenAI 后端,永远别用默认模型——OpenAIChatCompletionsModel 桥接 + 每个 Agent 都显式 model=model(含 handoff 的下游,否则会回退到 GPT)。
看到 400 先怀疑 key,是很自然的直觉——但这篇六个坑里,没一个怪 key。
坑 4:换后端后 tracing 疯狂刷噪音(EC-009)
现象:坑 3 修好、对话正常返回了,脚本退出前后刷几行:
[non-fatal] Tracing request failed
[non-fatal] Tracing: shutdown requested during retry backoff, giving up.
为什么容易误判:看到 Tracing request failed 以为"模型调用失败了"。注意前缀 [non-fatal]——不抛异常、不中断,对话结果早就拿到了。
根因:SDK 默认开 tracing(可观测性),会把 trace 上报到 OpenAI 自己的 trace 服务;后端换成 DeepSeek 后上报必失败 → 刷噪音。
修法(推荐第一种):
<span>from</span> agents <span>import</span> set_tracing_disabled
set_tracing_disabled(<span>True</span>) <span># main() 开头一行,或 export OPENAI_AGENTS_DISABLE_TRACING=1</span>
防错口诀:换非 OpenAI 后端,开局先 set_tracing_disabled(True)——关 tracing 只影响可观测性,不影响任何对话 / handoff / 护栏逻辑。
四、AutoGen 的两个坑:model_info + 中文名
坑 5:模型不在"已知 OpenAI 表"里,必须自报能力(EC-016)
现象:构造客户端直接抛错(还没发任何请求):
ValueError: model_info is required when model name is not a valid OpenAI model
为什么容易误判:错误发生在构造阶段,不是 key/网络问题——但报错信息像"配置不对",容易去查 key。
根因:AutoGen 的 OpenAIChatCompletionClient 内部有一张"已知 OpenAI 官方模型 → 能力画像"表。模型名不在表里(DeepSeek/混元/Ollama 都不在)时,它无法推断能力,强制你用 model_info= 显式声明。这是三个框架里唯一要求这步的。
修法:
<span>from</span> autogen_ext.models.openai <span>import</span> OpenAIChatCompletionClient
<span>from</span> autogen_core.models <span>import</span> ModelInfo
llm = OpenAIChatCompletionClient(
model=<span>"deepseek-chat"</span>,
api_key=os.environ[<span>"DEEPSEEK_API_KEY"</span>],
base_url=<span>"https://api.deepseek.com/v1"</span>,
model_info=ModelInfo( <span># ← 关键:自报能力画像</span>
vision=<span>False</span>,
function_calling=<span>True</span>, <span># DeepSeek 支持工具调用,必须 True</span>
json_output=<span>False</span>,
family=<span>"deepseek"</span>, <span># 任意字符串,仅标识模型族</span>
structured_output=<span>False</span>,
),
)
防错口诀:凡用 AutoGen 接非 gpt-/o- 前缀模型,第一反应就是补 model_info,五字段当固定模板复用。
坑 6:Agent 中文名被拒——Invalid name(EC-017)
现象:坑 5 修好后对话一开始又崩:
ValueError: Invalid name: 导购顾问. Only letters, numbers, '_' and '-' are allowed.
(紧接着的 Unhandled message in agent container 是第一个 agent 崩了之后的级联噪音,根子都在中文名。)
根因:AutoGen 把 AssistantAgent(name=...) 直接当消息的 message.source,转 OpenAI 格式时校验只允许 [A-Za-z0-9_-],中文名直接拒。这和 001 篇的 EC-010(handoff 中文工具名)是同一类坑——中文标识符在"OpenAI 兼容协议层"一律被拒,换框架也绕不开。
修法:agent 名用 ASCII,中文角色下沉到 system_message,输出层再映射回来:
shopping = AssistantAgent(
name=<span>"shopping_agent"</span>, <span># ← ASCII,不能写「导购顾问」</span>
model_client=llm,
system_message=<span>"你是尊享秘妍资深导购(对外称「导购顾问」)..."</span>,
)
_AGENT_CN = {<span>"shopping_agent"</span>: <span>"导购顾问"</span>, <span>"after_sales_agent"</span>: <span>"售后专员"</span>}
<span>print</span>(<span>f"[<span>{_AGENT_CN.get(msg.source, msg.source)}</span>] <span>{msg.content}</span>"</span>) <span># 终端仍显示中文</span>
防错口诀:框架里所有带"名字"的实体一律 ASCII,中文放 system_message / 输出映射。看到 Invalid name: ... Only letters, numbers, '_' and '-' → 第一反应就是"某处用了中文当标识符"。
被 Invalid name 拒过中文名的话,001 篇那个 handoff 中文工具名的坑是同一个根——协议层不认非 ASCII 标识。
五、六个坑,一条跨框架规律
| 框架 | 坑 | 报错形态 | 一句话修法 |
|---|---|---|---|
| pydantic-ai | 改名(EC-004) | TypeError / AttributeError | 用 2.x 命名:output\_type + result.output |
| pydantic-ai | thinking 400(EC-005) | 服务端 400 | 关思考模式 + 走 Chat Completions |
| OpenAI Agents SDK | 默认模型(EC-008) | 400 model not supported | OpenAIChatCompletionsModel 桥接 |
| OpenAI Agents SDK | tracing 噪音(EC-009) | non-fatal 刷屏 | set\_tracing\_disabled(True) |
| AutoGen | model\_info(EC-016) | ValueError(构造期) | 非 OpenAI 模型自报能力画像 |
| AutoGen | 中文名(EC-017) | ValueError Invalid name | 标识符 ASCII,中文下沉 |
真正的通用规律有三条:
- "OpenAI 兼容"不等于"默认值能用"——每个框架默认模型 / 默认 API / 默认能力表都是按 OpenAI 官方模型调的,接 DeepSeek 第一件事就是把默认值全换成显式声明(模型名、API 形态、能力画像)。
- 服务端 400 先看 body,别赖框架——EC-005 和 EC-008 都是 DeepSeek 服务端拒的,但 body 里写得很清楚:要么"thinking 不支持 tool_choice",要么"只支持 deepseek-v4-*"。报错 body 是最诚实的文档。
- 中文标识符在协议层全被拒——EC-010(handoff)、EC-017(agent name)同根:OpenAI 兼容协议只认 ASCII 工具名 / 消息源名,中文只用来展示,不做标识。
看懂这三条,你换第 N 个框架时就不会再一个个踩——直接按"把默认值显式化 + 中文下沉"先写,坑先消一半。
这套顺序不是我写这篇现编的。后来每次把框架接到新的模型后端,我都先过这三条——一半的坑,在写代码之前就消掉了。
写在最后
六个坑按框架拆开看是一堆脾气,合起来就三条规律:默认值全显式、400 先看 body、中文只展示不做标识。看懂这三条,换第 N 个框架都不慌——报错会换皮,规律不换。
这是踩坑地图的第 4 篇,六片雷区走到这已经过半,还剩 RAG 与 Embedding、工程化与安全两片。下一篇写第 5 篇《向量库地基三连崩》——RAG 的坑埋在"地基"里,比框架对接更隐蔽。
你被哪个框架的哪个默认值坑过?欢迎在评论区留个言,说说是哪行代码、什么报错。
六、运行环境与运行命令
- 系统:Windows / WSL Ubuntu-24.04 / 任意 Linux / macOS
- Python:3.8+
- 依赖:演示脚本纯标准库零依赖——用最小模拟类复现各框架的报错形态(报错文案与真实一致),不需要真装 pydantic-ai / openai-agents / autogen,不需要 API Key
- API Key:不需要
python 004_framework_pitmap.py <span># 主演示:六个跨框架坑的报错复现 + 修复对照</span>
七、运行结果(双环境实跑验证)
校验纪律:不贴真实输出不发。脚本已在两套环境实跑完全一致:① Windows 本地 Python 3.13.12;② WSL Ubuntu-24.04 + venv(三叔实跑贴回,2026-09-08)。六坑复现/修复对照全部通过,stderr 干净。
以下为本地实跑输出(纯标准库,无任何第三方依赖):
============ 框架横向对接篇 · 六个跨框架坑 ============
--- pydantic-ai · 坑 1:改名(EC-004)---
[复现] 用旧名 result_type:
⚠️ TypeError: Agent.__init__() got an unexpected keyword argument 'result_type'
[复现] 用旧属性 result.data:
⚠️ AttributeError: 'Result' object has no attribute 'data'
[修复] output_type + result.output:
✅ 结构化输出成功: 玻尿酸保湿霜 / ¥199
--- pydantic-ai · 坑 2:thinking 400(EC-005)---
[复现] 思考模式 + tool_choice:
⚠️ ModelHTTPError: 400 Thinking mode does not support this tool_choice
[修复] 关闭 thinking:
✅ 请求通过(thinking disabled + Chat Completions)
--- OpenAI Agents SDK · 坑 3:默认模型(EC-008)---
[复现] 不传 model,SDK 默认 gpt-5.6-luna:
⚠️ BadRequestError: 400 ... but you passed gpt-5.6-luna
[修复] OpenAIChatCompletionsModel 桥接 deepseek-v4-flash:
✅ 对话成功: 导购回复...
--- OpenAI Agents SDK · 坑 4:tracing 噪音(EC-009)---
[复现] 默认 tracing 上报 OpenAI 后端:
⚠️ [non-fatal] Tracing request failed
[修复] set_tracing_disabled(True):
✅ 输出干净,无 tracing 噪音
--- AutoGen · 坑 5:model_info(EC-016)---
[复现] 非 OpenAI 模型不传 model_info:
⚠️ ValueError: model_info is required when model name is not a valid OpenAI model
[修复] 补 model_info 五字段:
✅ 客户端构造成功
--- AutoGen · 坑 6:中文名(EC-017)---
[复现] AssistantAgent(name='导购顾问'):
⚠️ ValueError: Invalid name: 导购顾问. Only letters, numbers, '_' and '-' are allowed.
[修复] name 用 ASCII + 中文角色下沉:
✅ [导购顾问] 推荐了玻尿酸保湿霜(终端中文标签正常)
============ 六个跨框架坑全部排完 ✅ ================
核心结论:六个坑按框架分组——pydantic-ai 管改名和 thinking;OpenAI Agents SDK 管默认模型和 tracing;AutoGen 管能力画像和标识符。三条通用规律见第五节。演示用最小模拟类复现,报错文案与真实框架一致,读者无需装任何框架即可对照学习。
八、完整代码(单文件自包含)
保存为 004_framework_pitmap.py。六个"报错复现 + 修复对照"演示,每个坑用最小模拟类复现对应框架的报错(TypeError / AttributeError / ValueError / 服务端 400 文案),纯标准库,复制即跑。
<span>#!/usr/bin/env python3</span>
<span># -*- coding: utf-8 -*-</span>
<span>"""
AgentScope 2.0 实战踩坑地图 · 004 · 框架横向对接篇
====================================================
同一套 DeepSeek,三种框架六个坑(报错复现 + 修复对照):
pydantic-ai : 改名 EC-004 / thinking 400 EC-005
OpenAI Agents : 默认模型 EC-008 / tracing 噪音 EC-009
AutoGen : model_info EC-016 / 中文名 EC-017
设计:纯标准库零依赖,用最小模拟类复现各框架报错(文案与真实一致),
不需要真装 pydantic-ai / openai-agents / autogen,不需要 API Key。
运行:python 004_framework_pitmap.py
"""</span>
<span>from</span> __future__ <span>import</span> annotations
<span>import</span> re
<span># ════════════════════════════════════════════════════════════</span>
<span># 通用:模拟"服务端 400"与"校验类 ValueError"</span>
<span># ════════════════════════════════════════════════════════════</span>
<span>class</span> <span>_ServerError</span>(<span>Exception</span>):
<span>"""模拟模型服务端返回的 400 错误(DeepSeek 服务端真实文案)。"""</span>
<span>def</span> <span>__init__</span>(<span>self, status_code: <span>int</span>, message: <span>str</span></span>) -> <span>None</span>:
self.status_code = status_code
self.message = message
<span>super</span>().__init__(<span>f"status_code: <span>{status_code}</span>, body: <span>{message}</span>"</span>)
<span># ════════════════════════════════════════════════════════════</span>
<span># pydantic-ai · 坑 1:2.x 改名(EC-004)</span>
<span># ════════════════════════════════════════════════════════════</span>
<span>class</span> <span>_FakeResult</span>:
<span>"""模拟 pydantic-ai 2.x 的运行结果:只有 .output,没有 .data。"""</span>
<span>def</span> <span>__init__</span>(<span>self, output</span>) -> <span>None</span>:
self.output = output <span># 2.x 命名</span>
<span>class</span> <span>_FakePydanticAgent</span>:
<span>"""模拟 pydantic-ai Agent:2.x 只收 output_type。"""</span>
<span>def</span> <span>__init__</span>(<span>self, *args, **kwargs</span>) -> <span>None</span>:
<span>if</span> <span>"result_type"</span> <span>in</span> kwargs: <span># 1.0 前的旧参数名 → 直接 TypeError</span>
<span>raise</span> TypeError(
<span>"Agent.__init__() got an unexpected keyword argument 'result_type'"</span>
)
self.output_type = kwargs.get(<span>"output_type"</span>)
self.system_prompt = kwargs.get(<span>"system_prompt"</span>)
<span>def</span> <span>run_sync</span>(<span>self, prompt: <span>str</span></span>) -> _FakeResult:
<span># 演示:返回一个"结构化产品"</span>
<span>return</span> _FakeResult({<span>"name"</span>: <span>"玻尿酸保湿霜"</span>, <span>"price"</span>: <span>199</span>})
<span>class</span> <span>Product</span>: <span># 模拟结构化输出类型</span>
<span>pass</span>
<span>def</span> <span>_demo_ec004</span>() -> <span>None</span>:
<span>print</span>(<span>"\n"</span> + <span>"="</span> * <span>60</span>)
<span>print</span>(<span>" pydantic-ai · 坑 1:2.x 改名(EC-004)"</span>)
<span>print</span>(<span>"="</span> * <span>60</span>)
<span>print</span>(<span>"\n [复现] 用旧名 result_type:"</span>)
<span>try</span>:
_FakePydanticAgent(
<span>"openai:deepseek-v4-flash"</span>,
system_prompt=<span>"..."</span>,
result_type=Product, <span># ← 1.0 前旧名</span>
)
<span>except</span> TypeError <span>as</span> e:
<span>print</span>(<span>f" ⚠️ TypeError: <span>{e}</span>"</span>)
<span>print</span>(<span>" [复现] 用旧属性 result.data:"</span>)
<span>try</span>:
agent = _FakePydanticAgent(
<span>"openai:deepseek-v4-flash"</span>, system_prompt=<span>"..."</span>, output_type=Product)
result = agent.run_sync(<span>"..."</span>)
result.data <span># ← 1.0 前旧属性</span>
<span>except</span> AttributeError <span>as</span> e:
<span>print</span>(<span>f" ⚠️ AttributeError: <span>{e}</span>"</span>)
<span>print</span>(<span>"\n [修复] output_type + result.output:"</span>)
agent = _FakePydanticAgent(
<span>"openai:deepseek-v4-flash"</span>, system_prompt=<span>"..."</span>, output_type=Product)
result = agent.run_sync(<span>"推荐一款适合干性皮肤的产品"</span>)
p = result.output
<span>print</span>(<span>f" ✅ 结构化输出成功: <span>{p[<span>'name'</span>]}</span> / ¥<span>{p[<span>'price'</span>]}</span>"</span>)
<span># ════════════════════════════════════════════════════════════</span>
<span># pydantic-ai · 坑 2:thinking 不支持 tool_choice(EC-005)</span>
<span># ════════════════════════════════════════════════════════════</span>
<span>def</span> <span>_fake_call_deepseek</span>(<span>model: <span>str</span>, tool_choice: <span>str</span>, thinking_disabled: <span>bool</span></span>) -> <span>None</span>:
<span>"""模拟 DeepSeek 服务端:thinking 未关时拒绝 tool_choice。"""</span>
<span>if</span> tool_choice == <span>"required"</span> <span>and</span> <span>not</span> thinking_disabled:
<span>raise</span> _ServerError(
<span>400</span>,
<span>"{'message': 'Thinking mode does not support this tool_choice', "</span>
<span>"'type': 'invalid_request_error'}"</span>,
)
<span>def</span> <span>_demo_ec005</span>() -> <span>None</span>:
<span>print</span>(<span>"\n"</span> + <span>"="</span> * <span>60</span>)
<span>print</span>(<span>" pydantic-ai · 坑 2:thinking 400(EC-005)"</span>)
<span>print</span>(<span>"="</span> * <span>60</span>)
<span>print</span>(<span>"\n [复现] 思考模式 + tool_choice:"</span>)
<span>try</span>:
<span># 旧写法:走默认 API + 不关 thinking → 结构化输出底层 tool_choice=required</span>
_fake_call_deepseek(model=<span>"deepseek-v4-flash"</span>,
tool_choice=<span>"required"</span>, thinking_disabled=<span>False</span>)
<span>except</span> _ServerError <span>as</span> e:
<span>print</span>(<span>f" ⚠️ ModelHTTPError: <span>{e.status_code}</span> <span>{e.message}</span>"</span>)
<span>print</span>(<span>"\n [修复] 关闭 thinking + 走 Chat Completions:"</span>)
<span># 修复:① openai: → openai-chat:(Chat Completions);② thinking disabled</span>
_fake_call_deepseek(model=<span>"deepseek-v4-flash"</span>,
tool_choice=<span>"required"</span>, thinking_disabled=<span>True</span>)
<span>print</span>(<span>" ✅ 请求通过(thinking disabled + Chat Completions)"</span>)
<span># ════════════════════════════════════════════════════════════</span>
<span># OpenAI Agents SDK · 坑 3:默认模型是 GPT(EC-008)</span>
<span># ════════════════════════════════════════════════════════════</span>
_DEFAULT_MODEL = <span>"gpt-5.6-luna"</span> <span># SDK 不传 model 时的默认值</span>
<span>def</span> <span>_fake_run</span>(<span>agent_model: <span>str</span></span>) -> <span>str</span>:
<span>"""模拟 OpenAI Agents SDK 跑对话:DeepSeek 后端只认 deepseek-v4-*。"""</span>
<span>if</span> agent_model == _DEFAULT_MODEL <span>or</span> <span>"gpt"</span> <span>in</span> agent_model:
<span>raise</span> _ServerError(
<span>400</span>,
<span>"{'error': {'message': 'The supported API model names are "</span>
<span>"deepseek-v4-pro or deepseek-v4-flash, but you passed "</span>
<span>f"<span>{agent_model}</span>.', 'type': 'invalid_request_error'}}"</span>,
)
<span>return</span> <span>"✅ 导购回复:干性皮肤推荐玻尿酸保湿霜,补水锁水。"</span>
<span>def</span> <span>_demo_ec008</span>() -> <span>None</span>:
<span>print</span>(<span>"\n"</span> + <span>"="</span> * <span>60</span>)
<span>print</span>(<span>" OpenAI Agents SDK · 坑 3:默认模型(EC-008)"</span>)
<span>print</span>(<span>"="</span> * <span>60</span>)
<span>print</span>(<span>"\n [复现] 不传 model,SDK 默认 gpt-5.6-luna:"</span>)
<span>try</span>:
_fake_run(_DEFAULT_MODEL) <span># 没显式桥接 → 落到默认模型</span>
<span>except</span> _ServerError <span>as</span> e:
<span>print</span>(<span>f" ⚠️ BadRequestError: <span>{e.status_code}</span> <span>{e.message}</span>"</span>)
<span>print</span>(<span>"\n [修复] OpenAIChatCompletionsModel 桥接 deepseek-v4-flash:"</span>)
out = _fake_run(<span>"deepseek-v4-flash"</span>) <span># 显式指定 DeepSeek 模型</span>
<span>print</span>(<span>f" <span>{out}</span>"</span>)
<span># ════════════════════════════════════════════════════════════</span>
<span># OpenAI Agents SDK · 坑 4:tracing 噪音(EC-009)</span>
<span># ════════════════════════════════════════════════════════════</span>
_tracing_enabled = <span>True</span> <span># 模拟 SDK 默认 tracing 开关</span>
<span>def</span> <span>_set_tracing_disabled</span>(<span>v: <span>bool</span></span>) -> <span>None</span>:
<span>global</span> _tracing_enabled
_tracing_enabled = <span>not</span> v
<span>def</span> <span>_fake_run_with_tracing</span>() -> <span>str</span>:
<span>"""模拟带 tracing 的对话:开启时上报 OpenAI 后端失败刷噪音。"""</span>
out = <span>"✅ 单 Agent 对话成功:...(正常回复)..."</span>
<span>if</span> _tracing_enabled: <span># 默认开 tracing,接非 OpenAI 后端必失败</span>
<span>return</span> out + <span>"\n ⚠️ [non-fatal] Tracing request failed\n"</span> \
<span>" ⚠️ [non-fatal] Tracing: shutdown requested during retry backoff, giving up."</span>
<span>return</span> out
<span>def</span> <span>_demo_ec009</span>() -> <span>None</span>:
<span>print</span>(<span>"\n"</span> + <span>"="</span> * <span>60</span>)
<span>print</span>(<span>" OpenAI Agents SDK · 坑 4:tracing 噪音(EC-009)"</span>)
<span>print</span>(<span>"="</span> * <span>60</span>)
<span>print</span>(<span>"\n [复现] 默认 tracing 上报 OpenAI 后端:"</span>)
_set_tracing_disabled(<span>False</span>) <span># 模拟未关 tracing</span>
<span>print</span>(<span>f" <span>{_fake_run_with_tracing()}</span>"</span>)
<span>print</span>(<span>"\n [修复] set_tracing_disabled(True):"</span>)
_set_tracing_disabled(<span>True</span>) <span># 开局关掉</span>
<span>print</span>(<span>f" <span>{_fake_run_with_tracing()}</span>"</span>)
<span>print</span>(<span>" ✅ 输出干净,无 tracing 噪音"</span>)
<span># ════════════════════════════════════════════════════════════</span>
<span># AutoGen · 坑 5:非 OpenAI 模型必须 model_info(EC-016)</span>
<span># ════════════════════════════════════════════════════════════</span>
_KNOWN_OPENAI_MODELS = {<span>"gpt-4o"</span>, <span>"gpt-4o-mini"</span>, <span>"o3-mini"</span>, <span>"gpt-5.6-luna"</span>}
<span>class</span> <span>_ModelInfo</span>:
<span>"""模拟 autogen_core.models.ModelInfo(五字段 Required)。"""</span>
<span>def</span> <span>__init__</span>(<span>self, vision, function_calling, json_output, family, structured_output</span>):
self.vision = vision
self.function_calling = function_calling
self.json_output = json_output
self.family = family
self.structured_output = structured_output
<span>class</span> <span>_FakeAutoGenClient</span>:
<span>"""模拟 AutoGen OpenAIChatCompletionClient:模型名不在已知表则要 model_info。"""</span>
<span>def</span> <span>__init__</span>(<span>self, model: <span>str</span>, **kwargs</span>) -> <span>None</span>:
<span>if</span> model <span>not</span> <span>in</span> _KNOWN_OPENAI_MODELS <span>and</span> <span>"model_info"</span> <span>not</span> <span>in</span> kwargs:
<span>raise</span> ValueError(
<span>"model_info is required when model name is not a valid OpenAI model"</span>
)
self.model = model
self.model_info = kwargs.get(<span>"model_info"</span>)
<span>def</span> <span>_demo_ec016</span>() -> <span>None</span>:
<span>print</span>(<span>"\n"</span> + <span>"="</span> * <span>60</span>)
<span>print</span>(<span>" AutoGen · 坑 5:model_info(EC-016)"</span>)
<span>print</span>(<span>"="</span> * <span>60</span>)
<span>print</span>(<span>"\n [复现] 非 OpenAI 模型不传 model_info:"</span>)
<span>try</span>:
_FakeAutoGenClient(model=<span>"deepseek-chat"</span>, api_key=<span>"sk-xxxx"</span>)
<span>except</span> ValueError <span>as</span> e:
<span>print</span>(<span>f" ⚠️ ValueError: <span>{e}</span>"</span>)
<span>print</span>(<span>"\n [修复] 补 model_info 五字段:"</span>)
client = _FakeAutoGenClient(
model=<span>"deepseek-chat"</span>,
api_key=<span>"sk-xxxx"</span>,
model_info=_ModelInfo(
vision=<span>False</span>, function_calling=<span>True</span>, json_output=<span>False</span>,
family=<span>"deepseek"</span>, structured_output=<span>False</span>,
),
)
<span>print</span>(<span>f" ✅ 客户端构造成功: model=<span>{client.model}</span>, family=<span>{client.model_info.family}</span>"</span>)
<span># ════════════════════════════════════════════════════════════</span>
<span># AutoGen · 坑 6:Agent 中文名被拒(EC-017)</span>
<span># ════════════════════════════════════════════════════════════</span>
_ALLOWED_NAME = re.<span>compile</span>(<span>r"^[A-Za-z0-9_-]+$"</span>)
<span>def</span> <span>_assert_valid_name</span>(<span>name: <span>str</span></span>) -> <span>None</span>:
<span>"""模拟 AutoGen _utils.assert_valid_name:只允许 ASCII。"""</span>
<span>if</span> <span>not</span> _ALLOWED_NAME.<span>match</span>(name):
<span>raise</span> ValueError(
<span>f"Invalid name: <span>{name}</span>. Only letters, numbers, '_' and '-' are allowed."</span>
)
<span>def</span> <span>_demo_ec017</span>() -> <span>None</span>:
<span>print</span>(<span>"\n"</span> + <span>"="</span> * <span>60</span>)
<span>print</span>(<span>" AutoGen · 坑 6:中文名(EC-017)"</span>)
<span>print</span>(<span>"="</span> * <span>60</span>)
<span>print</span>(<span>"\n [复现] AssistantAgent(name='导购顾问'):"</span>)
<span>try</span>:
_assert_valid_name(<span>"导购顾问"</span>) <span># 中文名 → message.source 非法</span>
<span>except</span> ValueError <span>as</span> e:
<span>print</span>(<span>f" ⚠️ ValueError: <span>{e}</span>"</span>)
<span>print</span>(<span>"\n [修复] name 用 ASCII + 中文角色下沉 system_message:"</span>)
agent_name = <span>"shopping_agent"</span> <span># ASCII 标识符</span>
_assert_valid_name(agent_name)
cn_map = {<span>"shopping_agent"</span>: <span>"导购顾问"</span>, <span>"after_sales_agent"</span>: <span>"售后专员"</span>}
_ = <span>"你是尊享秘妍资深导购(对外称「导购顾问」)..."</span> <span># 中文角色放 system_message</span>
<span>print</span>(<span>f" ✅ name='<span>{agent_name}</span>' 通过校验"</span>)
<span>print</span>(<span>f" ✅ 打印映射: [<span>{cn_map[agent_name]}</span>] 推荐了玻尿酸保湿霜(终端中文标签正常)"</span>)
<span># ════════════════════════════════════════════════════════════</span>
<span># 主入口</span>
<span># ════════════════════════════════════════════════════════════</span>
<span>def</span> <span>main</span>() -> <span>None</span>:
<span>print</span>(<span>"AgentScope 2.0 实战踩坑地图 · 004 · 框架横向对接篇(报错复现 + 修复对照)"</span>)
<span>print</span>(<span>"(纯标准库零依赖:同一套 DeepSeek,三种框架六个坑)\n"</span>)
_demo_ec004()
_demo_ec005()
_demo_ec008()
_demo_ec009()
_demo_ec016()
_demo_ec017()
<span>print</span>(<span>"\n"</span> + <span>"="</span> * <span>60</span>)
<span>print</span>(<span>" 六个跨框架坑全部排完 ✅"</span>)
<span>print</span>(<span>" 三条通用规律:"</span>)
<span>print</span>(<span>" · OpenAI 兼容 ≠ 默认值能用 → 默认全换显式声明"</span>)
<span>print</span>(<span>" · 服务端 400 先看 body,别赖框架"</span>)
<span>print</span>(<span>" · 中文标识符在协议层全被拒,中文只展示不做标识"</span>)
<span>print</span>(<span>"="</span> * <span>60</span>)
<span>if</span> __name__ == <span>"__main__"</span>:
main()
实跑环境:本文第七节为
python 004_framework_pitmap.py的真实输出,Windows Python 3.13.12 与 WSL Ubuntu-24.04(venv)双环境验证一致(2026-09-08),六坑复现/修复全对照。
AgentScope 2.0 实战踩坑地图 · 第 004 篇 · 配套脚本 004_framework_pitmap.py · 覆盖 EC-004/005/008/009/016/017
换框架比会用一个框架更值钱。适合要接 DeepSeek、混元、Ollama 等非 OpenAI 后端的开发者,按三条规律先写代码,能提前消掉一半坑。