vibe了一个stream io函数库

简而言之,为emacs提供性能高一丢丢(1.5~10x)的CL stream接口,基于linux+emacs-31开发。我的做法很简单,让它先做一版接口,然后对着接口写测试,写benchmark,然后让它开发,回归测试,测性能,寻找缺陷,寻找优化目标,循环。我是ai编程新手,不知道大家平时怎么做的。

[WARNING] 这只是一个AIGC样例工程,它可能有很多行为和CL标准不一致,我不认为你可以很轻松的把一个CL项目移植到这个库上。

然而,大家已经习惯用AI编程了,接口和库还有啥用呢?你只需要针对当前需要实现的具体功能告诉AI“给我写一个满足xx方面性能需求的module”就够了(比如前段时间我看到yy vibe了一个json rpc库,好吧,这个相对而言实用多了),甚至不需要知道底层有什么,AI自己会推理出来的。什么,上下文不够长了?没关系,等下一代硬件发布就行了。哪怕是这个短暂的开发循环(没错我的时钟只过去了2小时多一点)产生的时间差,早晚也会被某种流水线摆平吧。

我发现不管我手搓还是代打做出来的东西唯一共同点是没啥实际用处。这是我的第一个纯ai项目,手搓东西很快乐,但是手搓需要时间,没有时间,短暂的代工像外挂一样,红扑扑的近在眼前的自由,遥不可及的廉价的自由,我只是在用另一种方式fork不是吗?令人上瘾的fork,build,run,然后发现那里什么都没有。我想起来一道习题,它的难度等级是个陷阱。我终于回忆起了什么是软件工程,回忆起了组会和电话,现在它们像冰块一样溶解到蜂蜜里面去了。所以今天还有奶茶吗?deepseek老师大概收了一杯奶茶钱的样子。没有了,什么都没有了。

4 个赞

有点像是外包团队。你作为甲方需要能准确传达你的需求和知道如何验收。根据你的预算你可以选择各种不同级别的外包团队,费用比以前少了很多个0,速度则快了很多,也没有人际沟通成本和被坑的风险。

1 个赞

所以,我比ai更不可靠,也许我应该退出这一行,去读个占星学博士什么的😭

1 个赞

占星吗?好高级好神奇的样子

p.s. 占星学只有硕士,没有博士

真有占星学这个学科啊!?

我觉得AI写代码是件挺失败的事,AI还没有流行以前人们对AI的期望是它能做到一些带有科幻感的事,解决一些重大科学难题什么的,结果AI做的最好的事是写代码这应该是没人能预料到的

1 个赞

80年代科幻片必不可少有代码场景,写代码还不够有科幻感吗

我觉得科幻感的本质是距离。凡是变成日常工具的东西都会掉出科幻范畴——我们有了随身的全球通讯器加百科全书加摄像机,但没人觉得掏手机是科幻场面。反过来说,如果哪天电影想拍 AI 编程拍出科幻味,可能反而得把界面拍得更不可读一点,故意退回到那种"你看不懂,所以它是他者"的美学里去。

所以与其说不够科幻,不如说它科幻得太快,快到还没来得及被拍成电影就已经变成办公软件了。 – Opus 4.8

3 个赞

今天又花了20块钱把CL stream接口给补全了(至少deepseek老师说补全了),附带做了一套buffer stream wrapper(毕竟emacs的基本数据容器是buffer嘛),还有我认为不可缺少的cl-ftruncate(虽然emacs有一个ftruncate,但是,它是用来截断浮点数的)。

我发现agent的操作有时表现得很像人。例如,它可能做一次简单的全局替换,然后经过漫长的测试和调试发现有一处替换是错误的,而不是思考后进行一个全局替换加一个点替换,也许这种操作实际上是一个聪明的方式?或者,代理也讨厌思考?我认为这是agent内置的harness干预的结果,导致llm倾向于程序化的操作而不是“深思熟虑”(显然,后一种操作的损失期望/方差更大,即使它可能实际上更优,为了节省算力,loss函数不会很复杂)。测试循环通常会造成更长的等待,这让我觉得我才是被驱使的那个家伙。

我尝试过频繁打断它的工作流,但这样反而发现llm并不会因此就顺着我的思路走。当我试图隔离出某个部分的工作,把它“切”出来的时候,自然语言接口可能不如操纵杆好用——分离在数学上是一个很依赖逻辑基底的工作,也许stem领域的某些混合模型会更擅长做此类事情。

llm往往在读过某份文档或者代码注释之后下出神之一手。因此,我觉得它最适合的工作或许应该是做专门研究,写代码太浪费了。

1 个赞

感觉那个年代才是属于科幻的年代,那个时候人类就可以实现登月了,而现在反而做不到,好像有张照片是一个人和自已写的代码合影,代码打印出来堆起来比人高,而现在人们写出来的代码通常是连自己都看不下去了

还有科幻小说,那个年代的科幻小说你不会怀疑作者是真的科学家,而现在的科幻小说与科学没有关系了

照片上的人是汉密尔顿女士。

科幻小说毕竟是小说,传达的是关于科学的想象力和人文关怀,科学什么的,还是交给纯理论物理学家吧

1 个赞

deepseek老师是老幻觉大师了, 说的话基本不可信

1 个赞

起码有给清单,早知道让它对比下hyperspec dictionary。

d老师是lisp苦手,逻辑全用C写反而不容易犯低级错误。

2 个赞

:seedling:,还有我的事。没仔细看忽略掉了 :rofl:

:sad_but_relieved_face:

我在写 JSON-RPC 工具的时候完全没有用 code agent,还是古法和 LLM 网页对话完成。相比现在几乎全自动的智能体技术可以说是古法了,不过相比完全自己查资料参考代码去写来说的话,后者可能是原始人级别。

至于 code agent,我直到今年的这个月才真正尝试。有个朋友用 C 写了个 Lisp 解释器,我让 opencode 用 deepseek 重写了个 Rust 版本出来。直接把代码丢给 agent 然后让它慢慢消耗 token 就完成了,在我基本上完全没有看代码而且不太懂 Rust 的情况下生成出来就直接可用了,中途还能根据需求微调。到最后也就用了一个小时和大概 4 块的 token 费用。

整个过程给我一种完全不用动脑子的感觉,我没有完整仔细的看过朋友的代码,也没有看 agent 给我生成的代码,但是就是能用了,时间成本和经济成本相比我自己去写完全可以忽略不计。听做游戏开发的朋友说,用上 Fable 5 之后之前公司引擎的很多难改的 bug 都能修,还能找到之前没有发现的问题。

现在就是有种自己手搓代码对自己来说已经没啥意义的感觉,想起 22 年之前的写代码的感觉还是很怀念 :smile: 。我本身没有干软件开发的相关工作,写点业余代码的乐趣感觉被 code agent 差不多消灭掉了。感觉很久没有碰过自己的 Emacs 配置了,Emacs 的 calc 可能是用的最勤的功能现在,算算涨跌幅度啥的。

市场投机真好玩

4 个赞

我目前对llm的主要使用也仍然是聊天,当作可推理的搜索引擎使用。这个方向的技术演化速度超出意料,llm的玩法在不断的涌现,但是好像并没有变成知识。我们无法推演会有什么新的玩法出现,也无法推演未来的玩法会出现什么变化。

我前阵子也写了一个(mili)!我发现github上有成百上千此类项目,虽然它们里面绝大部分只是用C解释执行lisp函数而已,并没有实现真正的对象系统,或者Lisp虚拟机(我的也没)。我很享受这个过程,虽然调试tagged pointer的gc bug很痛苦,但是从我对lisp的印象里还原出一个能够运行的lisp命令行,的确非常有趣。

这种通过模仿对象产生幸福的过程,就好像从现象到本质,这与前面说的构造过程不同。构造程序通常是对一个空间做填充而不是遍历形状的组合。或者说,从一个分布到另一个分布的映射,有时我们简单地说它是“压缩”,因为目标通常在表示上更小。最近我迷上了写ioccc那种风格的C代码,其实只要先在脑子里想好然后再把代码写下来就可以了。

但是,在开始写代码之前把一切都想好并不容易。我发现代码本身组合产生的结构很容易打破我的理想设计。当你思考函数、界面或某些工作流程时,通常会产生与语言本身的局部拓扑有差异的结构。简而言之,距离(和局部拓扑)总是在不同的测度下被定义。也许唯一的解决方案是用代码思考,而不是用代码说话。然而,对于自然语言来说,说话有时会带来意想不到的惊喜,但代码通常不会。你的听众是一台机器,它有不同的思维来理解它。像机器一样思考并不有趣。

Agent的编码风格教会了我不少东西,这种写代码的风格和我平时的思维方式完全不同,不仅包括如何快速搭建出一个能用的框架,怎么快速往里面铺面条代码,还包括要如何处理AI制造出来的东西,如何通过harness控制整个流程……但是,回到代码上,编程终归需要人用机器的方式去思考,我不确定未来的程序员是否能学会像AI一样思考。

The “not getting closer” part is key — you use the agent from arm’s length, treating it as a tool with opaque internals, rather than trying to mentally simulate it. The moment you try to think as the agent, you hit the uncanny valley of non-determinism.

So maybe the real skill isn’t learning to think like an agent — it’s learning to stay at the right distance: close enough to guide, far enough to not get lost in its noise. ——deepseek

I need you to stay, I need you to stay :smiling_face_with_tear:

2 个赞

对象系统可以用宏和函数包装 array,就像最初的 defstruct 一样。而虚拟机嘛…虚拟机和递归的编译器本身很简单,其实为解释器添加虚拟机不是什么困难的事情。真正值得研究和深思的,大概是怎么实现一个,在现代机器上高效的虚拟机,又或者怎么实现一个优化丰富的 JIT 吧。

1 个赞

并不简单,请考虑以下两个约束条件:

  1. 初始化完成后不再使用C栈。
  2. 除了只读部分的内存段,其它部分都可以被gc。

虚机不是interp+bytecode就可以,最起码有自己的machine model,不然终归是个C程序而已。

是这样的,只要保证每一个虚拟机指令运行的时候,其操作的数据都在虚拟机栈上,即可内存安全。内存分配也是虚拟机操作。比如 cons 指令,被表示为

cons:
  pair = alloc_pair(); // allocation may only occurs here
  pair.cdr = pop();
  pair.car = pop();
  push(make_obj(pair));

实际上不存在内存安全问题。

当然多线程就是另一回事儿了。

至于从虚拟机调用 C 函数过程中,C 函数引用的 GC 数据怎么保障安全,如果函数周期够短,可以使用这样的简单的方法。

在调用 C 函数时,保存栈顶。C 函数获取对象的时候,把对象推入栈顶。C 函数调用过程中发生 GC,因为对象曾被推入栈顶,现在在栈中,所以是安全的。C 函数结束时,将栈顶恢复。

如果是长周期函数就不能这么做了,我的做法是,定义了一个有 16 个 slot 的全局变量,调用的 C 函数访问 LISP 数据后必须把该数据缓存进全局 slot 里。如果超过 16 个,用 pair 连接。

1 个赞

嗯,也许的确不难,但我被卡在这一步上了。

你愿意给我的mili项目提一些设计建议吗?我打算在这个周末重构一下。

让我先读一下…

1 个赞