跳到主要内容

861 篇博文 含有标签「insider」

查看所有标签

隐藏的 SDK 重试机制:为什么你付了两倍的钱却浑然不知

· 阅读需 12 分钟
Tian Pan
Software Engineer

打开 OpenAI Python SDK 的源代码,你会发现一行安静的代码:DEFAULT_MAX_RETRIES = 2。Anthropic SDK 也采用了同样的默认设置。大多数 TypeScript SDK 也是如此。两次重试,指数级退避(exponential backoff),在连接错误、408、409、429 以及任何 5xx 错误时自动触发——这些都在你的代码看到失败之前就执行了。你没有配置它。你没有选择加入。你通常甚至不知道它的发生,因为你的应用记录的指标是 request_count(请求数),而不是 attempt_count(尝试数),并且你的追踪器(tracer)唯一能看到的 span 是 SDK 在最后一次尝试后关闭的最外层 span。

这在大多数情况下都没问题,直到出问题为止。如果在该 SDK 调用之上再添加一个应用级的重试装饰器——那种每个团队在遇到第一个 429 错误后都会写的代码——你就构建了一个 3x3 的风暴:SDK 尝试三次,你的包装层围绕 SDK 又尝试三次,在服务商降级期间,一个单一的用户请求会扇出为九次推理调用。服务商的账单会计算每一次尝试。而你的仪表盘只记录了一次。当最终有人进行账实对账时,那将是一场谁都不会喜欢的季度末谈话。

内部工具代理:当你杠杆率最高的 AI 功能却零客户时

· 阅读需 12 分钟
Tian Pan
Software Engineer

你公司最具战略意义的 AI 投资,可能是一位工程师在某个周五下午编写的一个 Slack 机器人。它回答“如何获取分级环境凭据”、“哪个值班人员负责认证服务”或“部署卡住时的运行手册是什么”,它节省的工程小时数比整个面向客户的 AI 路线图还要多——而后者占据了你四分之三的模型开销、安全审查队列以及发布沟通带宽。

组织架构图并未反映出这一点。OKR 文档也没有反映这一点。没有人是它的产品经理(PM),也没有人是它的工程经理(EM)。这个机器人之所以能生存下来,是因为构建它的工程师仍在回复 GitHub 上的 issue,在每一个面向客户的功能因六周的安全审查和发布就绪检查清单(之所以存在是因为客户可能会流失)而推迟发布时,它的价值正在悄然复合增长。

负面提示词是代码异味:为什么系统提示词中的每个 “不要” 都是技术债

· 阅读需 11 分钟
Tian Pan
Software Engineer

打开任何已经上线超过三个月的生产环境 AI 功能的系统提示词(system prompt)。数一数其中的负向条款——“不要”、“绝不说”、“避免”、“在任何情况下都不”、“你绝不能”。如果计数达到了两位数,你看到的就不是一个系统提示词。你看到的是一个坟场。每一块墓碑都标志着一个特定的用户投诉、一个特定的事故报告,或者一条来自利益相关者的 Slack 消息,因为他们看到模型做出了一些令人尴尬的事情。团队在表面打了补丁后就继续前进了,现在这个提示词读起来就像一份被强行嫁接了人格的法律免责声明。

负向提示词是代码异味(code smells)。并非隐喻意义上的,而是字面意义上的。它们在提示词工程中相当于吞掉异常的 try/except 块、没有文档的配置标志,或者是 2022 年留下的 // TODO: refactor this。它们在某种程度上有效,直到它们失效。而且它们所掩盖的失败模式,几乎总是比它们被添加用来压制的那个失败更有趣。

MCP 中的 OAuth:在工具服务器中传递用户身份

· 阅读需 11 分钟
Tian Pan
Software Engineer

当你第一次将 MCP 服务器接入真实的生产系统时,你会发现教程中轻描淡写的一点:该协议赋予了智能体(Agent)能力,但并没有给工具服务器一个每个审计日志都要求的答案——这是代表哪个人执行的操作? 你可以在不解决这个问题的情况下交付一个可运行的演示 demo,但如果不解决它,你无法向受监管的企业交付产品。而这两种状态之间的鸿沟,几乎完全是一个伪装成 OAuth 问题的分布式系统问题。

团队在这个鸿沟中寻求的解决方案,大致按尝试顺序排列,就像是把 OAuth 工作组十五年来一直警告的每一种反模式都游览了一遍。在 MCP 服务器环境中共享服务账号;将长期有效的个人令牌粘贴到配置中;或是乐观地认为“我们只需转发用户的会话 Cookie,让下游服务去处理就好”。每种方案在预发环境中都有效。但在安全审查第一次真正介入时,每种方案都会以不同的方式崩盘。

策略文件:为什么你不应该把拒绝规则写在系统提示词里

· 阅读需 13 分钟
Tian Pan
Software Engineer

上个季度,一家金融科技初创公司的安全审核员在系统提示词(system prompt)中添加了四行内容。这次修改包含一条拒绝规则,旨在防止助手为公司未获得运营许可的司法管辖区提供具体的税务建议。这听起来很合理、范围明确且符合审计要求。该规则在周二上线。到周五时,评估套件显示在与税务完全无关的客户入职流程中出现了 7 个点的下降——模型开始对任何提及国家的提问都模棱两可,甚至包括“这个账户持有哪种货币”。产品团队撤回了修改。安全团队在下周以略有不同的措辞重新发布了它。三周后,同样的退化以不同的形式再次出现,而接下来的安全修改又破坏了另一个无关的流程。

这里的 bug 不在于措辞,而在于拒绝规则放错了位置。它被挤进了一个 2,400 token 的构件中,该构件还包含助手的对话语气、格式契约、任务指令以及其他六项策略条款——对其中任何一项的修改都是对所有内容的行为修改,因为模型无法分辨哪句话是策略,哪句话是风格。生产环境中的系统提示词之所以变成了一坨乱麻的单体,是因为三个正交的关注点伪装成了一个整体。没有将它们解耦的团队在每次修改时都在支付“集成税”。

Prompt 修改不只是措辞变动:将 Prompt 视为软件的代码审查规范

· 阅读需 13 分钟
Tian Pan
Software Engineer

周二下午,一个只有六行代码的系统提示词(system prompt)编辑出现在了一个 Pull Request (PR) 中。Diff 只是普通的英文。两位评审者扫了一眼新的措辞,觉得读起来更自然,于是点击了批准。PR 在不到一分钟内合并。到了周五,客服开始收到关于智能体的工单:它突然拒绝总结超过一定长度的文档,不再引用来源,并莫名其妙地在每句回复开头都加上 “Certainly!” —— 这种行为没人要求过,Diff 中也无法预见。

当一个花了十年时间学习如何评审代码的团队,在面对提示词这一产物时,竟然退化到了第一周的水平,结果就是这样。Diff 看起来 毫无害处,因为它读起来像英语,而人类正是用眼睛来审阅英语的。让代码评审发挥作用的规范 —— 运行测试、检查影响范围、对 “小改动” 保持适当的怀疑 —— 并没有悄然转化。措辞变好了,但行为变差了,直到用户发现之前,没人注意到。

会话边界问题:计费、评估和记忆的对话终点在哪里

· 阅读需 12 分钟
Tian Pan
Software Engineer

三个团队正在查看同一个事件流,每个团队都有一个名为 session_id 的列,但每个团队对什么是“会话”都有不同的定义。计费(Billing)继承了来自认证库的 30 分钟空闲窗口。评估(Eval)从聊天机器人框架中继承了“直到用户说‘再见’或停止打字 10 分钟为止”的定义。记忆(Memory)则使用 UI 在用户点击“开启新聊天”时生成的线程 ID —— 而大多数用户从不点击这个按钮。三列数据,三种语义,一个汇总仪表盘,以及三个共用一个根因但互不相关的 Bug。

这就是会话边界问题(session boundary problem)。它看起来像是一个埋点琐事,但实际上是一个披着基础设施外衣的产品问题:一段对话在哪里结束?坦诚的回答是没有单一的标准答案 —— 计费会话、评估会话和记忆会话并不是同一种对象 —— 如果一个团队选择了一个默认定义并让另外两个团队继承它,那么他们交付的就是具有相同根因的计费纠纷、评估偏见和内存泄漏。

“展示过程”的 UX 陷阱:当推理链只是披着产品外壳的调试输出

· 阅读需 11 分钟
Tian Pan
Software Engineer

推理模型会输出思维链(chain-of-thought)轨迹,因为这是它的计算方式。产品团队在 UI 中渲染该轨迹,是因为隐藏它感觉像是丢掉了用户付费购买的 token。这是两个不同的决定,而产品端几乎没有人意识到他们做了第二个决定。于是,轨迹变成了面板,面板变成了功能,功能有了文档页面。六个月后,有人在季度回顾中问,为什么支持队列里全是用户在反驳推理过程,而不是针对答案本身。

推理轨迹本质上是调试输出。它的存在是为了让工程师了解模型为什么选择某个工具、在日期上含糊其辞,或者在段落中间悄悄切换了角色。在没有经过设计审查的情况下将其推给终端用户,等同于在生产环境中留下 console.log 调用并称之为“透明度”。它看起来像个功能,渲染成本几乎为零,但它会以团队构建的任何仪表盘都无法显示的方式悄悄削弱信任。

总结税:当压缩消耗的 Token 超过了它节省的量

· 阅读需 12 分钟
Tian Pan
Software Engineer

一个长时间运行的 Agent 每 12 轮就会达到其压缩阈值。每一次压缩的成本都相当于一次规模等同于当前运行窗口的 LLM 调用——首先是 8K tokens,然后是 14K,接着是 22K——因为被总结的内容跨度随着每次触发而增长。到了第 60 轮,用户在观察 Agent 自我总结上花费的 token,已经超过了在实际推理上花费的 token。成本仪表盘将“用户推理成本”显示为一个单一数字,完全没有意识到其中一半是为用户永远不会再看的上下文压缩而付费的。

这就是“总结税”:一类随着对话长度增加而增长的开销,在用户回合之间悄然触发,并作为一个单一项目出现,将用户付费的工作与系统为自我管理而进行的内务处理混为一谈。这是现代 Agent 架构中最接近“垃圾回收停顿时间(garbage-collection pause time)”的东西——而大多数团队在生产环境中运行时都关闭了 -verbose:gc

我们已经有了:当 AI 功能在重新造你已有的代码轮子

· 阅读需 13 分钟
Tian Pan
Software Engineer

我合作过的一个团队在上季度发布了一个“智能”日期提取器。该模型可以解析像“下周二”和“14 号之后的两周”这样的自然语言短语,在生产环境中通过功能标志 (feature flag) 运行,在选定的层级上每次请求的成本约为 3 美分。六周后,一位后端工程师偶然参加了一场设计评审,随口提到公司其实早就有了一个日期解析器。它编写于 2019 年,存在于一个 AI 团队中没人读过的工具模块里,能以不到 1 毫秒的延迟处理 99.4% 的相同输入,而且运行成本几乎为零。那个 AI 功能并没有被撤下,而是被合理解释了——“模型可以处理长尾情况”——于是团队继续前进,发布了一个比公司已有方案更贵、更慢、准确度更低的版本。

这并非个案。对于那些比 AI 团队成立时间更久的公司来说,这是 AI 功能最主要的失败模式。这种模式不断重复:一个智能分类器复制了多年前编写的正则表达式流水线;一个检索系统获取了一个内部服务一直作为类型化表维护的供应商列表;一个智能体 (agent) 学习提取那些解析器已经可以确定性提取的实体。AI 功能发布的质量标准甚至低于它并不知道其存在的确定性系统,而构建确定性系统的团队往往在跨团队会议上才发现这一点。

80% 陷阱:聚合 RAG 指标如何掩盖系统性长尾失效

· 阅读需 11 分钟
Tian Pan
Software Engineer

你的 RAG 管道在评估集上达到了 80% 的检索准确率。团队将其发布。三周后,一位客户抱怨说,系统在回答关于产品遗留集成的某些问题时,给出的答案完全错误,表现得却非常有信心。你进行了调查,将该查询输入你的管道,它检索到了完全相关的文档——但只是针对一般主题。而那三个涵盖了遗留集成边缘情况的特定文档就躺在你的语料库里,却从未被检索出来。

那 80% 的数字是真实的。但作为刚才所发生情况的信号,它几乎毫无用处。

稀疏信号问题:当无法进行 A/B 测试时如何衡量 AI 功能质量

· 阅读需 11 分钟
Tian Pan
Software Engineer

你向企业客户上线了一个 AI 写作助手。每天使用它的人只有二十三个。产品经理在问:新的摘要模型是否真的比旧的更好?距离下一个迭代周期只剩两周,你需要给出一个决定。

于是你想到了 A/B 测试——然后立刻发现数学跑不通。要在 20% 的任务完成率基准上检测出 10% 的相对提升,在 80% 统计功效下,每个实验组大约需要 1,570 名用户。按每天 23 个用户算,你需要 136 天才能积累足够的数据。功能早就被弃用了,实验还没结束。

这就是稀疏信号问题。它并非 B2B 初创公司的特有困境。大多数 AI 功能——即便在成熟产品中——也只有一小部分用户在使用,而且都是执行特定高价值任务的用户。适用于大规模消费者推荐引擎的评估方法,在这种环境下完全失效。接下来,本文将介绍如何构建一套在无法进行 A/B 测试时依然有效的评估体系。