在 bytesized32 的开源代码里面看到了一个玄学内容。
while True:
try:
stream = call_gpt(stream=True, model=model, messages=messages, **kwargs)
pbar = tqdm(stream, unit="token", total=kwargs.get("max_tokens", 8*1024), leave=False)
for chunk in pbar:
time.sleep(0.01) # Should help with Errno 104: Connection reset by peer https://stackoverflow.com/questions/383738/104-connection-reset-by-peer-socket-error-or-when-does-closing-a-socket-resu
chunk_content = chunk.choices[0].delta.content
if chunk_content:
response += chunk_content
pbar.set_postfix_str(f"...{response[-70:]!r}")
nb_tokens = count_tokens(chunk_content)
pbar.update(nb_tokens)
else:
pbar.close()
break
except (openai.APITimeoutError, openai.APIError, ChunkedEncodingError, ReadError, RemoteProtocolError) as e:
if isinstance(e, openai.APIError):
print("*****", e.type)
if "An error occurred during streaming" not in e.message:
raise e
# Append the response we received so far to messages.
if len(messages) == 1:
messages.append({"role": "assistant", "content": response})
messages[-1] = {"role": "assistant", "content": response}
print(e)
仔细看看 try except 的 try 最后面 else 和上面的 for 缩进一致,真的很玄学!
ChatGPT 给的解释是
在 Python 中,
for
循环后面的else
子句只有在循环没有被break
语句中断的情况下才会执行。也就是说,如果for
循环正常完成迭代而没有提前退出,else
子句就会执行。
所以说如果 for 循环中的内容因为 API 寄了,就不会进行 pbar.close(),然后在 except 里面把之前生成的内容作为 assistant 的回复 append 到 message 最后面。因为最外层是一个 while True,所以这样的实现可以有效避免 api 失效对整个 pipeline 的影响。
太酷啦!
emm 其实我自己玩这个的时候也遇到了其它问题,比如 api 调用被 chunk 掉了,生成一个文字交互游戏代码,最后主函数写到 if __nam
就不写了。这个问题我觉得把 while True 改改就能解决,你怎么看!