关于帮AI程序员解决一个蛋疼bug小事

444 阅读5分钟

因为AI工具的兴起和繁荣,市面上涌现出了一大批AI“程序员”,可能他们对代码的机制甚至语法都一窍不通(是你吗?是你吗?Emmmmmmm);

但是他们通过cursor等集成AI的工具能成功生成所需要的程序工具,比如下面的主人公:

image.png

因为是我亲爱的客户M,奔着客户就是上帝,给钱就是义父的原则;我给必须给他打上马赛克...

故事的起因是这样的,M通过claude生成了一个python交易小程序,代码大概800行左右,然后咧:

image.png

它运行一段时间就崩溃了....

image.png

而且是偶发的....

image.png

这给亲爱的M急的直抓头皮,并且请教了 a bounch of 某宝客服.

But...

没解决

好!这下通过邻居小老弟老W的引荐,成功和我这个自吹“没什么bug解决不了”的15年开发经验的不秃中登,相遇了

image.png

并粘贴了下面的日志:

image.png

我一看,damn!!这能有任何关系?

Sppsvc.exe我就不介绍了。

日志他是来源于windows的事件日志系统:

image.png

这里有个小tip:

对于应用程序的崩溃你或许可以在这里看到崩溃日志,但是如果是带代码的程序开发,我们首先一定首先要锁定的程序本身。

所以在本案例中,首先要做的无非两件事:
1.程序的运行被外部环境干扰,比如安全软件的hook插件(因为他们是在你程序运行时跑到你的程序内部的),可能会在极端条件下诱发程序的崩溃,譬如360...

2.Python程序本身存在问题:

A.导入的库有问题。

B.写的代码有问题。

首先排除第一个点,我首先使用procexp.exe进行导入库的查找,看有没有可疑的dll,但事实证明他的电脑干净得不像话,(据说他为了解决这个问题把电脑都重装了.....

image.png

那么就只能去看第二个点,程序崩溃,那么首先我们要借助有效的IDE,首先对于python,我们运行pycharm进行调试肯定能抓到python层面的bug:

Debug模式跑起来!!!!!!

image.png

卒。。。

看来这个问题要解决起来绝非那么简单:
首先我们注意到一个熟悉的东西:

(0xC0000005)

这是个什么东西?

Windows 的异常代码 0xC0000005 就是 STATUS_ACCESS_VIOLATION,也就是“访问冲突”/“内存访问违规”

一般是编译型语言编译成二进制文件后,里面的一些操作,涉及到内存的违规访问,如果你是C/C++开发选手,这些应该很熟悉;如果不是,你只需要知道这种错误在python中是不存在的,既然在python中不存在,那么错误只会存在导入库中:

那么我们首先去看他的导入库有哪些:

image.png

Damn!!!!!这么多?那有没有快速的方法定位?

答案是:

有的

  
import faulthandler

faulthandler.enable(all_threads=True)

在你代码的顶部加入这两行代码,就可以在崩溃的时候在日志底部锁定出错的方法:

在本文中通过堆栈导致退出的函数最终锁定在:

image.png

通过函数的字面意思

convert_kline_to_image_tensor

可以知道这哥们M大概率是想把获取的K线图转化成一个CNN的Tensor

然后在这个函数里面崩了,这个函数主要涉及到下面的绘图库:

Matplotlib,

Okay我们一言不合先升级matplotlib到最近版本3.10.5

运行。。

image.png

Okay!看来是要从代码层面去解决(绕过)这个问题了。。

我们来问GPT。。用魔法打败魔法。。

GPT给我提供了N个解决方案。。但是都是去调整代码,试过了以后发现根本不行。。

那么我们只能另辟蹊径:

如果这个bug在现在的库中根本没解决,那么我就可以把这个函数作为一个单独的进程运行(你就算崩溃了,我重启你就行了,根本不会影响主交易程序),然后主交易程序作为一个单独的程序运行。。然后两个进程通信不就搞定了吗:

okay。。就这么干。。示例代码如下(看不懂也没关系反正就明白这么解决的就对了。。):

executor = ProcessPoolExecutor(max_workers=1)

def _render_kline_bytes(df_values, dates_values):

"""

子进程中运行的“渲染”函数示例:

接收纯数值和日期,返回 (1,1,64,64) 大小的 float32 tensor bytes

"""

# 这里省略实际绘图逻辑,直接返回一块空白张量的 bytes

arr = np.zeros((1, 1, 64, 64), dtype=np.float32)

return arr.tobytes()

def convert_kline_to_image_tensor(df_segment: pd.DataFrame) -> torch.Tensor:

"""

示例版:把 K 线数据打包给子进程,

超时或子进程崩溃时返回全零张量

"""

# 简单边界检查

if df_segment is None or len(df_segment) < 2:

return torch.zeros(1, 1, 64, 64)

# 准备纯数值和日期

df_vals    = df_segment[['Open','High','Low','Close']].to_numpy()

dates_vals = df_segment.index.to_list()

global _executor

try:

fut = _executor.submit(_render_kline_bytes, df_vals, dates_vals)

raw = fut.result(timeout=2)    # 最多等 2 秒

arr = np.frombuffer(raw, dtype=np.float32).copy()

return torch.from_numpy(arr).view(1, 1, 64, 64)

except TimeoutError:

fut.cancel()

return torch.zeros(1, 1, 64, 64)

except BrokenProcessPool:

# 子进程崩溃,重建池

try: _executor.shutdown(wait=False)

except: pass

_executor = ProcessPoolExecutor(max_workers=1)

return torch.zeros(1, 1, 64, 64)

except Exception:

return torch.zeros(1, 1, 64, 64)

最后:

image.png

感恩老板!

我的文章同步发表在我的公众号“夜读tech”,如果你感兴趣麻烦点一手关注谢谢