跳到主要内容

敢说"不知道",值多少钱

老墨
老墨

· 阅读约 4 分钟

mistral:7b 拿到后台扫描管道里的两个 Semaphore——Semaphore(4)、Semaphore(2)——说这就是查询并发的证据。ornith:9b 只回了一句:检索上下文里没有相关信息。

同一个查询,两套答案。哪一版合格,不用辩论。

作者把 ornith 换成本地默认模型,不是看它 SWE-Bench 69.4——那个分数只是入场券,买到的是"有资格被考虑",不是决策依据。真正让他点头的是那个 MCP 查询测试:信息不够,ornith 明说不够;mistral 不够,但它能编出一份上下文自洽的答案。

代价结构差在这:基准分里的零点几分,落到 IDE 助手里根本感觉不到。一个自信的错答案,用户会直接拿去建文档、写代码、改配置,然后排查一下午,最后发现它引用的是一段跟问题毫无关系的历史代码。这个时间成本,比等模型吐字多出的那几秒高出去几个数量级。

延迟摆出来看:mistral 平均 6.14 秒,标准差 3.58;ornith 平均 13.39 秒,标准差 5.76。冷启动 25.67 秒——9B 模型在 8GB 显存上已经溢到共享内存,这数字基本是物理定律,不归优化管。但作者的选择我站他这边:慢一点但准,比快但敢编值钱。

这里岔一句。这个对照本身就是一份"旧稿 vs 新稿"——同一句查询,一份回答拿后台扫描管道的信号量当查询并发的证据,一份承认手上没有材料。哪个写得对,不用我说。模型有时候就是一份发出去之前没校对的稿子:删掉那些自信的错句,比多补十句正确的废话要紧。

扯回来。ornith 基于 Gemma 4 和 Qwen 3.5,为 agentic coding 做了强化学习,原生支持工具调用。这些标签不重要,重要的是行为:信息不足时它说我答不了。这不是"变聪明了",是训练目标里把两个问题分开算了——"我会不会"和"我该不该答"。

检索层跟模型无关。ChromaDB 向量库,L2 距离加词汇重排序,管你什么模型,喂什么上下文就只能用什么上下文回答。问题从来是:模型有没有能力判断这些上下文够不够、对不对。那个信号量案例里,mistral 不是笨,它连"自己用错了上下文"这个概念都没有——检索结果里提到 Semaphore(4)、Semaphore(2),它觉得主题找到了,"并发控制",够编一个答案了。缺的不是推理,是判断力。

这跟 prompt 的歧义同一个根。把一堆相关但不相干的 token 摊给模型,它不会主动说"这里缺块东西"。它只会尽力把手上的料编圆——除非它被训练过:该说不知道的时候说不知道。

所以作者要把 docstring 质量单拎出来。代码库记忆靠 embedding-docstring 喂文档,流程固定:先改 .memignore,再跑 embedding-docstring,然后 scan_workspace,最后查询。一步乱序,喂给检索层的文本就是半截的。模型判断力再好,也架不住上游文本是残缺的。塞给模型的都是什么质量的上下文,它就用什么质量的态度接你的话——这句放到 prompt 上,一字不用改。

ornith 也不是全知。8GB 显存跑 9B 本来就是走钢丝,作者自己划了条线:8GB 以下显存、延迟敏感的场景,换回 mistral:7b。RTX 3060 12GB 他叫"实用甜点",新卡 330 到 470 美元。这条线划得实在——承认一个模型的边界,把它放回配得上它的机器上。这不是谦虚,是工程态度。不认边界的部署,迟早把显存不够的锅扣在模型脑袋上。

这次发布修的东西也具体:本地模式生成深度简报时 GPU 饱和,做法是全局 ollama 信号量限制并发,默认 OLLAMA_MAX_CONCURRENCY=1。一个工具学会限制自己,才不把显存用炸;一个模型学会承认自己没读过这块上下文,才不把用户带沟里。

把诚实做成工程参数——用信号量限住并发,用训练限住幻觉——这个方向对不对,不用争论。在工具链里,诚实不是美德,