庄晓立/LIIGO,20240520。
先看一段新闻报道(来源https://kxstock.hexun.com/2024-05-16/212868824.html):
q = input(">> ") // 读取用户输入的指令
ret = rag.query(q, ...) // 将用户指令输入给RAG服务并获取结果
ret.write("...") // 将RAG服务返回的图片数据存储到本地磁盘
主要流程:创建RAG服务对象rag(代码位于main函数上方,此图未体现),读取用户指令,请求服务,存储服务返回数据。input是Python系统函数,query和write均为RAG服务接口API。
由于Ctrl+C强制终止程序运行触发了Python程序内置的TRACEBACK功能,即输出函数调用栈。下文进一步分析调用栈将会解读出更多信息。
调用栈显示,main.py调用了ret.write(),ret.write()调用了time.sleep(6)。
也就是说,time.sleep(6)
代码是写在ret.write()
函数内部的。这一点我感觉很反常。
正常来说,流程应该是这样的:query, sleep, write。不知道处于何种考虑,演示者似乎不想让我们看到sleep,故意把sleep隐藏到write内部。事实上如果演示过程一切正常,我们根本不知道有sleep(6)的存在;只不过因为一个意外回车才导致sleep暴露在我们眼前。
说一下为什么我感觉不正常。
这里涉及两个角色,一个是模块的实现者(生产者),一个是模块的使用者(消费者)。也就是说一个提供API、一个调用API,双方各行其责。
rag.query()
是API,使用者负责调用API,实现者负责实现API内部代码,也就是说query()函数里面的代码是实现者写的。
ret是query()的返回值,因而ret.write()
也是API,write()函数里面的代码是实现者写的。
可是sleep()应该是调用者的工作呀,应该写在API函数外面,不应该写在API函数里面。
而且看ret.write()
的命名,其功能很简单很明确,就是写出文件,按常理不应该有sleep功能。
以上讨论的是API未提供等待机制的情况。按说成熟的API设计应该提供等待机制,可行方案是:或1,把rag.query()设计为异步函数(调用方异步等待),或2,新增ret.waitForComplete()类似接口(在ret.write()之前调用)。
考虑到他们演示的模块还不是正式版,还没有发布,API不成熟没有等待机制也可以理解。
让使用者等待调用完成是很尴尬的,因为使用者不能预知要等多久。作为演示代码也无所谓,根据经验就暂定等6秒吧,可以的。
但是使用者等待的时机,应该是在query之后write之前呀。write函数里面,那不是你的领地;把sleep(6)写在write里面,是很反常的。因为你API尚未完善需要调用方等待呀,DEMO代码应该明确体现出sleep调用呀。
此演示主要面向开发者,我认为其目的大抵有二:1、展示模块功能,体现自身技术实力,2、展示调用接口,体现API友好易用。
前述两个演示目的都未达成,毫无疑问是“翻车”了。原本想展示技术实力,结果让人怀疑演示造假。原本想展示API友好易用,结果竟然需要sleep(6)等待。
虽然华为昇腾社区官方及时出面,否认了演示造假,但是该回应缺乏细节和逻辑,可信度不够。
我建议华为昇腾社区还要尽快多做一些工作,才能及时消除大面积负面影响: