@@ -231,25 +231,84 @@ def test_non_streaming_request(self):
231231
232232 def test_stop_behavior_in_reasoning (self ):
233233 """
234- [Row 7] stop 在 reasoning content 阶段生效
235- 验证:设置 stop word 为思考过程中必然出现的词(如 'step' 或 'thinking'),
236- 确认模型是否异常截断或按预期行为处理(取决于预期是忽略还是截断) 。
234+ [Updated] 验证 Stop 参数在 Reasoning 模型中的行为:
235+ 1. 确认 reasoning_content 能够正常返回 (不被误截断)。
236+ 2. 确认 stop 参数作用于正文 (content),并正确截断 。
237237 """
238+ # 设置一个具体的 Stop 词,诱导模型在正文中输出它
239+ target_stop_word = "Banana"
238240 payload = {
239- "model" : "pre-siliconflow/deepseek-r1" , # 必须是思考模型
240- "input" : {"messages" : [{"role" : "user" , "content" : "Count from 1 to 5 step by step" }]},
241+ "model" : "pre-siliconflow/deepseek-r1" ,
242+ "input" : {
243+ "messages" : [{
244+ "role" : "user" ,
245+ "content" : f"Please think about the color of the sun, and then simply output the phrase: 'The sun is like a { target_stop_word } '"
246+ }]
247+ },
241248 "parameters" : {
242- "stop" : ["step" ], # 这是一个在思考过程中很容易出现的词
243- "enable_thinking" : True
249+ "stop" : [target_stop_word ],
250+ # R1 自动开启思考,但也可能需要显式参数,视具体后端实现而定,这里保持默认或按需添加
244251 }
245252 }
246- response = make_request (payload )
247253
248- # 这里的断言取决于你们的预期:
249- # 如果预期是不支持(即不会截断),则 status_code 200 且内容完整。
250- # 如果预期是会截断导致格式错误,则捕获错误。
254+ response = make_request (payload )
251255 assert response .status_code == 200
252- # 进一步可以检查 response.text 中是否包含 reasoning_content
256+
257+ # --- SSE 解析逻辑 ---
258+ collected_reasoning = ""
259+ collected_content = ""
260+ final_finish_reason = None
261+
262+ for line in response .iter_lines ():
263+ if not line :
264+ continue
265+
266+ # 解码 line
267+ line_text = line .decode ('utf-8' )
268+
269+ if line_text .startswith ("data:" ):
270+ json_str = line_text [5 :].strip ()
271+ if json_str == "[DONE]" :
272+ break
273+
274+ try :
275+ chunk = json .loads (json_str )
276+ choices = chunk .get ("choices" , [])
277+ if not choices :
278+ continue
279+
280+ delta = choices [0 ].get ("delta" , {})
281+
282+ # 1. 收集 reasoning_content
283+ # 注意:有些实现可能叫 reasoning_text,视具体 API 定义,这里假设是 reasoning_content
284+ if "reasoning_content" in delta :
285+ collected_reasoning += delta ["reasoning_content" ]
286+
287+ # 2. 收集正文 content
288+ if "content" in delta :
289+ collected_content += delta ["content" ]
290+
291+ # 3. 捕捉 finish_reason
292+ if choices [0 ].get ("finish_reason" ):
293+ final_finish_reason = choices [0 ].get ("finish_reason" )
294+
295+ except json .JSONDecodeError :
296+ continue
297+
298+ # --- 断言验证 ---
299+ print (f"\n [DEBUG] Collected Reasoning Length: { len (collected_reasoning )} " )
300+ print (f"[DEBUG] Collected Content: '{ collected_content } '" )
301+ print (f"[DEBUG] Finish Reason: { final_finish_reason } " )
302+
303+ # 1. 验证 reasoning 内容回来了 (Think 过程不应为空)
304+ assert len (collected_reasoning ) > 10 , "Expected significant reasoning content from R1 model."
305+
306+ # 2. 验证 Stop 生效 (Content 应该包含 'The sun is like a ' 但不包含 'Banana')
307+ assert "The sun" in collected_content
308+ assert target_stop_word not in collected_content , f"Content should stop before '{ target_stop_word } '"
309+
310+ # 3. 验证 finish_reason 是 stop
311+ assert final_finish_reason == "stop" , f"Expected finish_reason to be 'stop', but got '{ final_finish_reason } '"
253312
254313 def test_thinking_budget_behavior (self ):
255314 payload = {
0 commit comments