最近和各大AI大语言模型一起合作写了个小项目,让大家看看AI离取代人类还差多远。

先上代码 slirp-go
里面包含了 slirp.go 程序代码,并在 README.md 里标注了每个小版本prompt

开发大家都在一个共享环境下,连docker都不能运行,rootless也没有。不过好在linux环境,弄个proot能apt或者yum install自由,但是诸如podman这样的程序还是没法运行。一阵恼火,于是下载了linux kernel直接ARCH=um编译出user mode linux,我自己运行自己的内核总可以了吧。

喜滋滋编译完,好了,这个kernel没有网络。挖坟找找自己以前写的文章看看当时怎么配置user mode linux的,结果是要tun/tap设备,这个需要管理员先开一些权限,在rootless下可以用,但是这个权限没开啊…

于是开始到处找不用tun/tap的方法。发现了user mode linux的网络可以支持daemonslirp模式,这不是很好么。于是兴冲冲跑去github搜索一下,有些好些年前的项目,编译出来,怎么都不能运行?daemon模式有点复杂的,相当于需要从二层网络开始处理…而slirp是三层网络,只处理ip packet。

那我只要有个程序处理这些ip packet连上internet,我的user mode linux不就可以联网了么。于是喊上LLM,这还不简单。

首先登场的当然是写代码目前最强的Claude4,让它用c写一个简单的slirp程序,结果程序是能一次性编译通过,但是好像用user mode linux加载没什么反应。然后尝试了下gemini2.5pro,gpt4o,qwen3,都不能一次性编译通过了都…

这下遇到瓶颈了,很烦躁。继续手动搜索,突然找到了libslirp,眼前一亮。于是让claude4用c和libslirp写一个简单的slirp程序,程序有一处错误改正下就能正常编译了,但是运行以后还是什么都没有。于是手动从libslirp的gitlab上扒下来一个ping的example,发现编译不过,原来是libslirp最新已经4.9了,一般linux源里的都还是4.4,版本号改变不大但是内部api有一些大动静…加上文档写得很差,AI都写得不太对了。(所以知道了吧,要想不被AI取代,请把项目文档写差一点…目前为止我让AI写调用公司产品API的代码复杂的就没有对过的,发现它被文档毒害得不浅,或者说产品文档实在质量太差,连参数都能列错…而开发k8s operator代码刚刚的,因为人家文档不错,正确案例也多…)

写了半天,发现这个libslirp好像只是一个网络packet封装啊,看完文档发现它还是要靠一些手段诸如tun/tap连到外面…我要是能这么做,早就iptables配置好了啊…然后还试用了下slirp4netns(unshare -> no permission),同样的问题…

然后继续搜索引擎,突然找到了个pySLiRP,它是需要一个/dev/usbXXX设备作中介,通过PPP协议传输packet数据的。于是我又仔细看了下slirp的说明,据说是通过stdin和stdout交换数据。于是拿到这个pySLiRP以后,看了下它是通过打开usb设备设定baud rate通信的,我让AI写点代码把它替换掉不就好了?于是让claude4和gemini2.5pro比赛写代码,因为pySLiRP用的是asyncio,它通过第三方库打开usb设备得到async的readerwriter,这下目标明确,让俩模型写一段python代码将stdin和stdout转化为async的readerwriter。哔哔哔,代码写得很快,claude4响应比gemini快不少,质量也好很多,但是有些时候claude4没处理好的细节可能gemini可以补上一些,所以基本我还是喜欢让2个模型一起写代码,增加成功率(qwen3的代码能力确实还是有待提高的,大部分时候不能满足开发要求,所以这里暂时选了claude4+gemini2.5pro)。这次AI的代码直接放到原有代码里,把接口换成调用AI的代码,一次性成功。我还让AI给加了dump hex数据到stderr的代码。运行user mode linux,配置网络,ping一下某个ip,然后终于有数据打印到stderr了。

因为网络知识奇差无比,这些hex是啥意思?直接问AI好了,解释下这坨binary是什么意思。哦,很给力,两个AI都解析出了这坨binary是一个ip packet,并且是一个icmp ping的packet,只是两头多了0xc0。这里claude说不知道这是啥意思,但是gemini给出了猜测,根据这个0xc0,很像是slip的protocol。

然后再去查slip protocol,原来就是一些encode/decode的约定。这时候再读pySLiRP的代码,用了一套PPP protocol,牛头不对马嘴啊…但是有了最基础的输入输出数据样本,我又试了一下libslirp,完全不知道怎么控制它啊…算了,用raw的形式先把ping搞定,至少要先让ping有unreachable host输出。

于是先让AI写了俩函数去encode和decode slip,这样我们从stdin拿到数据,然后decode以后就是一个纯ip packet了。然后让AI写一个函数,如果我有一个ping的ip packet,解析之后生成一个unreachable host的ping response。对于这种特别明确的任务,claude4可怕的地方就来了,一次性写对,直接使用。于是我们有了第一个slirp的python版本——slirp.py。放到user mode linux里,配置好网络,ping一下,稳定得到unreachable host了!甚至其他curl或者网络请求都会得到“无响应”的响应。最初版本成功!

写到这里突然意识到目前这个项目实际上是写一个程序,这个程序要求是一边处理ip packet,另一边处理和外界的联系,有点像NAT,或者更像proxy,但是不同的地方是两边处理的粒度不一样。比如ping,我们得到ip packet,然后我们要把icmp的payload拿到,然后使用user mode下的socket发送这些payload,再得到response payload,并且构造ip packet去响应user mode linux的网络请求。

所以刚才的unreachable host版本写完以后,我让AI写一个程序,可以rootless得发送icmp payload,并且得到icmp response,并生成一个可用得response ip packet…把这次的代码和最初版本接起来,得到一个可以ping外部ip的slirp版本。当然,如果是ping内部同虚拟网段的机器,我们还可以让AI写个程序一直response ok就好了。至此ping的部分就做好了。

这给了我一部分和AI继续合作的信心。因为考虑到后续python的运行速度可能会比较慢,所以又让AI把之前的代码用golang写了一遍。很不错,各个部分都是一次性编译通过并且运行无误。

之后就进入udp处理的部分了。这个部分主要是先支持ping www.csdn.net,因为上面的最初版本,里面会判断如果是icmp ping,再判断是内部网络还是外部网络ip,就能走通ping,其他的ip packet还是unreachable host,所以ping www.csdn.net会告诉我domain name暂时不可用,打出的ip packet第一个也是一个dns query的udp packet。relay吧,udp packet发送过来,然后slirp维护一个map,并和对应net.UDPConn通信就好了。从udp packet里拿到payload,拿到服务器的ip和port,发送payload,拿到response,拼接一个合适的ip packet发送回去,通路成功!这下ping一个域名也可以了。我出要求,AI写代码,我负责integration整合并且debug…还算顺利。

之后有一个难题就是udp是无状态的,那我在map里的connection什么时候释放呢?之后想了个简单策略,如果30s没有通信,直接timeout释放掉,之后它发送数据再创建连接好了。至于udp server如何处理,暂时不慌,以后再说吧。

接下来就是处理tcp了。这个时候也是gpt5刚出来的时候,让它写了点代码,真的是牛头不对马嘴,算了,还是继续claude4+gemini吧…这个时候代码已经有个600多行了,在免费的高级模型里,已经不能读代码然后改了。没关系,我们直接让它写一个处理tcp的ip packet,然后再写一个程序处理tcp payload的读写,把两个程序代码拼一起就完成了最基本的。

这个时候把claude4的代码贴进去,运行,然后curl http://bing.com,看到log已经显示连接到bing的ip,并且发送了http request,只是curl一直报错 http/0.9 not allow之类,傻眼了。把代码片段贴给俩AI模型,然后告诉我了几个错误的bug…这下抓瞎了…只能看看curl的源代码哪里报这个错,但是看代码还是要花不少时间…

这个时候正好是gpt5出了gpt5-high和gpt5-chat不同版本的时候,那就试试gpt5-high吧,把处理tcp的部分直接贴给它,它直接指出了错误,给口碑崩塌的gpt5挽回了一些颜面…原来是处理SYN SYN-ACK ACK的时候SeqNum忘了加一!不错,AI对有效context内代码的理解已经很给力了。

写到这里,slirp.go已经在没有第三方库的情况下1000多行能够处理简单curl http://some-index-server了,比如准备好一个写了world的hello文件放nginx上,curl一下会返回world。

之后接着就要考虑如何给超过MTU的tcp分片传输了…开始的时候让AI直接把读到的大的数据分片直接全部发送给user mode linux,发现并不能传输数据,得你一拳数据我一拳ACK…这个好像其实并不复杂,一个List[]byte变成一个队列,然后如果读到了数据,就往队列里塞数据,之后触发一下写一个分片,并按照拿到ACK之后继续按照存储得offset发送下一个分片,一来一往,这个让AI写的话需要描述很复杂,还要给它一部分代码,怕context窗口不够(当然,这是目前模型最大的限制,上下文窗口超出以后会有问题,别看宣称多长的上下文窗口,理论上是无限的,但是vector就那么长总有上限的…),所以让AI写了一个fill(out *[][]byte, data []byte, isEOF bool)函数,然后让它把out改成队列的形式…所有需要的代码都好了,直接集成到现有代码里,把之前的handleTcpResponse直接发送读到内容的部分更新成一个goroutine去发送分片数据,再更新下ACK的部分也触发下分片发送!好了,完成,一个简单的slirp.go就写好了。试了下curl一个完成index.html或者xxx.css文件,都可以完整输出了。

1100+行。我大概写了200行的integration,IP写了900行左右。

先休息下,之后是要进行大量测试确保基本的操作没有错误…等测试全面完成了放代码出来…然后就是实现server的功能,比如ssh连接,需要实现listen在一个unix socket,然后把网络流量导到这个socket里就好了…

之后我们就来看看商业版的agent如何写代码吧…
本来比较嫌弃claude 4 sonnet参数量太小,但是发现cursor真的在这个模型上下了不少功夫。先试了下gemini pro 2.5和cursor配合,写代码写得很奇怪…然后再试claude 4和cursor配合,确实AI发展已经相当精彩了。

期间,我手动把代码拆成了多个文件。
我们把剩下没有怎么实现的功能都交给AI吧,让它实现从外面访问user mode linux内部的服务,诸如ssh;让它照猫画虎实现ipv6的部分…因为模型小,所以一次性搞不定,虽然一次性把需求都扔给了它,一次使用了1.1M的token;之后看完它的代码,发现它在外部方位内部服务上就写了个buffer,没有做具体可用的事情,只能再次提出具体需求,让它实现把tcp/udp payload转成packet内外打通,主要补齐server端需要处理的SYN-ACK部分。这部分它第一也没有处理好,直接处理完SYN-ACK就建立访问了,但实际上还缺失了模拟客户端ACK的部分。3次直接操作repo,1800行代码全交由AI去写。

所以基本上,商业产品诸如cursor,你只要发挥指挥作用,剩下的就让AI自动完成就好了。如果担心安全问题,就直接创建一个诸如container或者UML这样的sandbox,然后让它发挥,或者你看着它,每次危险操作都确认一下。整个流程上比较繁琐的部分就是对接大模型然后cache各种资源,用小模型去省大模型tokens。

不过我个人的兴趣是,使用尽量小或者没有模型实现一个语言系统。目前查阅的资料,其实之前的rules方法也没有尝试billion级别的,所以到底谁好用还说不定。所以除了用AI,继续探索AI的方向,继续牛马…

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐