资深 LLM 用户为何少用生成式模型
经验用户分享 LLM 实际使用限制与现实困境。有助于理性看待 AI 工具,但属观点讨论。
经验用户分享 LLM 实际使用限制与现实困境。有助于理性看待 AI 工具,但属观点讨论。
最近,我一直在尝试将自己对生成式 AI 的立场整理成一份个人伦理声明,因为尽管我对现代生成式 AI 的多个方面持强烈批评态度,却也参与其中。在撰写这份声明的过程中,我开始反思自己如何利用大语言模型:既用于我在 BuzzFeed 担任高级数据科学家的专业工作,也用于撰写个人博客和开发开源软件。大约十年来,我一直在研究和开发文本生成相关工具,从 char-rnns,到让 GPT-2 支持微调,再到 GPT-3 实验,以及更多围绕 ChatGPT 和其他 LLM API 的实验。虽然我不敢自称是最擅长使用现代 LLM 的人,但我在应对下一词元预测模型的缺点方面积累了丰富经验,也非常善于发掘它们的优点。
令我意外的是,我使用它们的频率远没有人们想象中工程师使用得那么高,但这并不意味着 LLM 对我毫无用处。这个问题需要根据具体情况细致讨论。
多年来,为了从 LLM 中获得最佳结果,我用过各种技巧。其中最著名的技巧是提示词工程,也就是以特定方式组织提示词,引导模型生成满足特定约束的输出。在提示词中加入诸如向 LLM 提供金钱奖励,或者只是要求 LLM 把输出写得更好之类的内容,确实能够带来可量化的积极影响,既能提高模型对原始提示词的遵循程度,也能提升输出文本的质量。每当同事问我为什么 LLM 的输出不符合预期时,我都会建议他们多做一些提示词工程,而这几乎总能解决他们的问题。
AI 领域没有人喜欢提示词工程,尤其是我。人们曾尝试通过更稳健的 RLHF 范式消除对提示词工程的需求,但结果反而让提示词工程变得更有价值,因为 LLM 开发者由此能够更好地利用模型增强后的提示词遵循能力。诚然,“提示词工程师”作为一个职位名称最终成了梗,但这主要是因为,对于任何认真使用 LLM 的人来说,提示词工程如今已经成了一项必备技能。提示词工程确实有效,而专业工作的一部分,就是使用真正有效的方法,即使它看起来很荒唐。
因此,我从不使用 ChatGPT.com 或其他面向普通用户的前端来访问 LLM,因为它们更难控制。相反,我通常使用各家 LLM 服务提供的后端 UI。这些 UI 是对 API 功能的一层轻量封装,必要时也很容易将操作迁移到代码中。直接访问 ChatGPT API 等 LLM API,可以设置系统提示词,以非常细致的方式控制生成过程的“规则”。对生成文本指定具体约束,例如“不要超过 30 个单词”或“绝不使用 ‘delve’ 一词”,写在系统提示词中往往比像使用 ChatGPT.com 那样写在用户提示词里更有效。任何不允许你显式设置系统提示词的现代 LLM 界面,很可能都在使用一套你无法控制的自有系统提示词。例如,当 ChatGPT.com 曾出现对用户过度谄媚的问题时,OpenAI 修改了系统提示词,要求 ChatGPT “avoid ungrounded or sycophantic flattery.”。与任何 ChatGPT 变体相比,我更常使用 Anthropic Claude 的 API,尤其是 Claude Sonnet,因为根据我的个人体验,Claude 没那么“机械”,处理编程问题时也准确得多。
此外,使用 API 时还可以控制生成的“温度”,它大体上决定了生成内容的创造性。默认情况下,LLM 并不会始终选择概率最高的下一个词元,以便每次生成都能给出不同的输出。因此,我更喜欢将温度设置为 0.0,使输出基本保持确定性;如果需要少量变化,则设置为 0.2–0.3。现代 LLM 现在的默认温度通常是 1.0,而我的推测是,这个较高的数值会加剧 LLM 的幻觉问题:输出文本内部逻辑一致,事实却是错误的。
交代完这些背景,我现在可以谈谈过去几年里我是如何在 BuzzFeed 使用生成式 LLM 的。以下是我参与过的一些项目的概要——只是众多项目中的一部分——这些项目都使用 LLM 快速、成功地解决了问题:
BuzzFeed 的网站内容策划人员开发了一套新的分层分类体系,用于将数千篇文章归入指定的类别和子类别。由于我们没有已经标注好的文章可用于训练传统的多类别分类模型来预测这些新标签,我编写了一个脚本来调用 Claude Sonnet API,并在系统提示词中写入 The following is a taxonomy: return the category and subcategory that best matches the article the user provides.,同时附上 JSON 格式的分层分类体系;然后,我将文章元数据作为用户提示词传入,并将温度设为 0.0,以获得最精确的结果。循环处理所有文章后,得到了合适的标签。
在使用一些数据科学花招识别出数百个彼此不同的 BuzzFeed 文章语义聚类后,我们发现并没有一种简单的方法能为每个聚类赋予唯一标签。我又编写了一个脚本调用 Claude Sonnet API,在系统提示词中写入 Return a JSON-formatted title and description that applies to all the articles the user provides.,用户提示词则包含该聚类中的五篇文章。同样,循环运行脚本处理所有聚类后,获得了非常出色的结果。
一位 BuzzFeed 作者问,是否可以使用 LLM,依据 BuzzFeed 风格指南对“这里应该使用破折号吗?”之类的语法问题做合理性检查。我再次调用了 Claude Sonnet API,这次将完整的风格指南复制粘贴到系统提示词中,并加入命令 Reference the provided style guide to answer the user's question, and cite the exact rules used to answer the question.。测试表明,引用内容准确无误,确实存在于源输入中,推理也保持一致。
这些项目最初都只是有人在早间站会上随口提出的想法,或是通过 Slack 私信发来的点子,但每个项目都只花了一两个小时就完成了概念验证(包括测试),并移交给相关利益相关者进行评估。对于分层标签这类项目,如果没有 LLM,我就需要开展更复杂的研发工作,还可能得通过人工标注来构建训练数据集,整个过程很可能要花费数天,而且在智力上并没有什么成就感。在这里,LLM 确实遵循了帕累托法则,帮我完成了可用解决方案的 80%,但剩下 20% 的迭代、测试和收集反馈工作反而耗时更长。即使模型输出后来变得更加可靠,LLM 幻觉仍然值得担忧,因此我也建议同事谨慎使用:如果 LLM 的输出看起来古怪,就应该让人类再次核对。
还有一种不涉及文本生成的 LLM 用例,在我的专业工作中同样非常有用:文本嵌入。从技术上讲,现代文本嵌入模型也是 LLM,只不过它的头部不会输出下一个词元的 logits,而是输出一个数字向量,用于在高维空间中唯一标识输入文本。ChatGPT 革命所推动的所有 LLM 改进,例如更长的上下文窗口和质量更高的训练方案,也同样适用于这些文本嵌入模型,并促使它们随着时间推移取得了巨大进步,例如 nomic-embed-text 和 gte-modernbert-base。文本嵌入在 BuzzFeed 发挥了许多作用,从识别相似文章到构建推荐模型,但这篇博客文章讨论的是生成式 LLM,因此这些用例就留待以后再讲。
不,我不会使用 LLM 来撰写这个博客上的文章。如今,人们读到一篇由资深 LLM 用户撰写的文章时,我怀疑这已经成了一种默认假设。我的博客风格实在太古怪,LLM 无法准确模仿。我的写作风格直白、不恭,偶尔还令人尴尬:即使运用提示词工程和少样本提示,向模型提供我现有博客文章的示例,并要求它精确遵循相同的文学风格,LLM 最终生成的内容还是更接近 Marvel 电影的对白。但即使 LLM 能用我的口吻撰写文章,我仍然不会使用它,因为如果文章大部分内容并非出自我自己的文字,却将其呈现为我的作品,在作者身份上会构成不道德的虚假表达。此外,我通常撰写的是科技和编程领域刚刚发生的事件,这些内容即便存在于 LLM 的训练数据中,也不会得到充分体现,从而增加产生幻觉的可能性。
我发现了一个有点滑稽的技巧,可以让 LLM 改进我的文章,却不让它代替我写作:把基本完成的博客文章交给它,让 LLM 假装成一名尖刻的 Hacker News 评论者,根据文章写出五条各不相同的评论。这样不仅能找出论证中可能遭到批评的薄弱之处,而且它也不会告诉我该在文章里写些什么来提前回应这些负面反馈,因此我必须自然地想办法解决它们。我通过 Claude API 运行了这篇博客文章的初稿和 Hacker News 系统提示词(聊天记录),它指出,我在 BuzzFeed 使用 LLM 的例子过于简单,并不比传统的自然语言处理技术更具创新性,因此我补充说明了为什么 NLP 的效率或效果不会那么好。
不,我也不会把 LLM 当作友好的聊天机器人。character.ai 和 Replika 等 LLM 个人陪伴类初创公司的巨大成功,本身就足以证明 LLM 确实有用,即使这种用途只是娱乐或心理疏导,而不是更具实用性的用途。
我承认自己是个异类,因为把 LLM 当作朋友是最常见的使用场景。先不谈我是个内向的人,很难和这样一个实体成为朋友:它被训练得尽可能友善,却又会因为幻觉而习惯性地撒谎。我可以通过提示词工程,让 LLM 指出我在胡说八道,而不是只给我积极肯定,但撒谎的问题没有办法解决。
没错,我会使用 LLM 编程,但只会在我有合理把握认为它们能够提高生产力时使用。早在最初的 ChatGPT 问世时,我就开始让 LLM 帮我编写正则表达式,因为单凭这一点就能为我节省数小时——虽然承认这件事有点尴尬。不过,如今 LLM 在编程中的作用已经远远超出了这一点,而如何以最佳方式利用 LLM 辅助编程,也变得更加微妙、更具争议。
和大多数程序员一样,我以前会用 Google 搜索编程问题,然后点击第一个看起来相关的 Stack Overflow 结果,直到我决定开始向 Claude Sonnet 提出同样的问题,并获得详细得多、也更符合具体需求的答案。对于那些包含特定功能约束和软件框架的问题,这一点尤为明显,因为这些条件的组合很可能不会出现在 Stack Overflow 的答案中。我最近在撰写另一篇博客文章时向 Claude Sonnet 提过这样一个问题,转述如下:使用 Pillow 库编写 Python 代码,将五张图片合成为一张图片:左半部分由一张图片构成,右半部分由其余四张图片构成。(聊天记录)。使用 Pillow 合成多张图片并不算太难,Stack Overflow 上也有足够多的相关问题和解决方案,但这种特定的合成方式很独特,需要进行一些棘手的位置计算,而我很可能会在第一次尝试时搞错。不过,Claude Sonnet 生成的代码基本正确,而且很容易测试,替我省下了枯燥的调试时间。
然而,对于更加复杂的代码问题,尤其是涉及冷门库的问题,我对 LLM 的输出会更加谨慎,因为从 Stack Overflow 和 GitHub 抓取到的相关代码示例更少。我遇到过一个真实问题:我需要在训练模型时将详细指标记录到数据库中——我使用的是 Hugging Face transformers 中的 Trainer 类——以便稍后进行可视化和分析。我要求 Claude Sonnet:在 Python 中为 Hugging Face transformers Python 库的 Trainer 类编写一个 Callback 类,使其能够在每个步骤中将模型训练元数据记录到本地 SQLite 数据库,例如当前 epoch、该步骤耗时、步骤损失等。(聊天记录)。我对这个问题没那么乐观,因为创建自定义回调的相关代码并不多。不过,Claude 生成的代码实现了一些很有帮助的思路,而这些并不是我提问时立刻想到的,例如使用缓冲区来减少阻塞 I/O、通过 SQLite 配置提升速度、批量插入以及连接管理。让 Claude 两次“把代码做得更好”(为什么不呢?)之后,它又提出了一些出乎意料的思路,例如缓存 SQLite 连接,以及使用一个 JSON 列类型的单独字段来存储任意数量的指标,同时还让代码更加符合 Python 风格。这段代码依然很多,如果不在实际训练循环的完整上下文中测试,不太可能开箱即用。然而,即使代码存在缺陷,其中的思路本身也极其有用;在这种情况下,以生成的代码为基础进行修改,比从头编写自己的 SQLite 日志记录器快得多,而且最终代码的整体质量可能也更高。
对于我日常工作中占用时间最多的实际数据科学任务,我发现 LLM 的代码生成并没有那么有用。LLM 无法可靠地输出数学运算的文本结果,一些 API 会通过提供代码解释器来执行数据 ETL 和分析,从而绕过这个问题,但考虑到我通常处理的数据规模,这类工作流在成本上并不可行。虽然 pandas 是 Python 中处理表格数据的标准工具,而且早在 2008 年就已出现,但我现在只使用相对较新的 polars 库。我注意到,LLM 往往会像编写 pandas 函数一样凭空编造 polars 函数,迫使我深入查阅文档来确认,时间一长便令人厌烦。至于数据可视化,我完全不用 Python,而是使用 R 和 ggplot2,因此我一直没有想过要咨询 LLM;此外,我也怀疑 LLM 是否同样熟悉这两个框架。自 2017 年以来,我使用的数据可视化技术就没有发生过变化,而制作图表时最耗时的问题,是判断数据点对人类读者来说究竟太大还是太小,这并不是 LLM 能够帮忙解决的问题。
向 LLM 询问编程问题,只是编程辅助的一个方面。另一个主要方面,是使用 GitHub Copilot 这类能够提供行内代码建议的编程助手。尽管我在使用 LLM 解决一次性编程问题时取得了不错的效果,但实际上,我出于一个意想不到的原因并不喜欢使用编程助手:它会让人分心。每当看到 Copilot 弹出代码建议时,我都必须在思维上从编写代码切换到审查代码,然后再切换回来,这会破坏我的专注状态。总体而言,它对生产力的净提升为零,成本方面则是净损失,因为 Copilot 的费用远高于仅仅通过 Web UI 临时向 LLM 提问。
现在,我们可以谈谈房间里的几头大象了——AI 智能体、MCP 和凭感觉编程——而我的观点会比较辛辣。从高层次来看,AI 智能体和 MCP 是对工具范式的重新包装;这种范式由 2022 年的 ReAct 论文推广,其中 LLM 可以判断回答用户输入是否需要某个工具,提取相关元数据并传给工具执行,然后返回结果。此后,LLM 在上下文窗口大小和提示词遵循能力方面迅速进步,使 AI 智能体工作流变得更加可靠,而 MCP 的标准化相较于普通工具而言是一项客观改进,我对此表示支持。然而,它们并没有带来任何在几年前 LangChain 首次登场时还无法实现的新用例,而且现在 MCP 工作流的简单实现,甚至比当时更加复杂和令人困惑。无论过去还是现在,我个人都没能为 AI 智能体找到任何新颖的用例。
对于使用 Claude Code 或 Cursor 等编程 AI 智能体进行凭感觉编程,我甚至几乎没有尝试的欲望。理论上,编程 AI 智能体应该能够解决我对 LLM 生成代码可靠性的担忧,因为它本身会进行复核,并且能够纳入整个代码项目的上下文。然而,我也听说过一些骇人听闻的故事:有人意外花掉数百美元,却没有得到任何能够解决其编程问题的成果。试验代码生成与拿代码生成赌博之间,只有一线之隔。凭感觉编程可以帮我完成 80% 的工作,我也认同这一点对于快速构建个人应用具有价值——这些应用要么永远不会公开发布,要么在发布时明确声明“按现状提供”。但在严肃项目中,用凭感觉编程为明知质量不达标却仍然交付的代码辩护,是不专业的;我唯一能够负责的代码,是我对其实现完全有信心的代码。
当然,编程领域始终在变化,上面所说的一切只是我目前使用 LLM 的方式。我完全有可能在 Hacker News 上看到一篇文章,从而彻底改变自己对凭感觉编程或其他 AI 编程工作流的看法。不过,我对当前的编程生产力很满意,也能够快速、正确地完成所有编程任务。
围绕 LLM 及其社会角色的讨论已经变得足够两极分化,以至于仅仅发表一句极其中立的陈述——LLM 确实有一些用途——就足以招致铺天盖地的骚扰。我强烈反对 AI 批评者 Ed Zitron 的论断:他认为 LLM 行业注定失败,是因为 LLM 在现实世界中毫无用处,导致 OpenAI 和其他 LLM 提供商无法赚取足够的收入来抵消其巨额成本。以下两点完全可以同时成立:(a) LLM 提供商的成本经济性过差,无法为投资者带来正向投资回报;(b) LLM 能够解决有意义且影响重大的问题,确实很有用,只是还达不到足以证明 (a) 合理的 AGI 炒作所宣称的程度。这种特殊的组合造成了一个令人沮丧的灰色地带,需要以细致入微的方式来讨论,而意识形态分裂的社交媒体已经无法从容容纳这种讨论。假设 OpenAI 和其他所有 LLM 提供商突然倒闭,并且以后再也不会有更好的 LLM 模型得到训练和发布,那么 Qwen3 和 DeepSeek R1 等开源且采用宽松许可证的模型仍然是有效的替代品,它们的性能与 ChatGPT 相当,并且可以托管在 Cerebras 和 Groq 这类专用 LLM 托管服务商上——这些服务商实际上能够从每一次用户推理查询中获利。OpenAI 的倒闭并不会导致 LLM 消亡,因为 LLM 如今确实有用,市场对它们的需求永远不会归零:这口钟一旦敲响,就再也无法让它恢复沉寂。
作为一名软件工程师——尤其是数据科学家——这些年来我学到的一件事是:在合适的场景中使用合适的工具始终是最佳选择,而 LLM 只不过是这个工具箱里的又一件工具。LLM 究竟能提高生产力还是适得其反,取决于你在何时、何地使用它们,但它们绝对不是毫无用处。使用 LLM 更像是强行把方榫塞进圆孔里(过程中可能会损坏榫头或孔洞),而不借助 LLM 做事,则相当于仔细设计一个圆榫,让它顺利穿过圆孔,不出任何意外。但面对某些圆孔,当你需要快速迭代时,有时先把方榫硬塞进去、之后再考虑问题是合理的;而另一些时候,你必须更精确地处理榫头和孔洞,确保两者都不会受损,否则之后就得花费额外的时间和金钱去修复榫头和/或孔洞。
……也许以后让 LLM 帮我写比喻,也没什么不好。