跳到主要内容

720 篇博文 含有标签「llm」

查看所有标签

那位通过反复试验摸清你 Prompt 的高级用户

· 阅读需 10 分钟
Tian Pan
Software Engineer

此刻,你的产品里有一位用户,体验远好于中位数用户。不是因为他付得更多,不是因为他在不同的订阅层,也不是因为他被分到了某个特殊的实验组。他通过耐心地试探,发现这个 AI 功能只要换种方式提问,就会给出漂亮的回答。他知道哪些动词能触发结构化输出。他知道一个词的追问会得到精简版本,一整句话则会得到展开版本。他知道某些话题如果不包装成假设性问题,助手就会戒备起来。这一切,你的网站上没有一处写过。他是逆向工程出来的。

有意思的不是这种用户存在,而是这种用户现在成了你的产品文档。你的 AI 功能跟用户之间签了一份契约——一份没公开的契约,完全编码在系统 prompt 里——而了解这份契约的唯一方式就是反复试验。只有一小部分用户有耐心去做这些试验。其余人拿到的是一个更糟糕的产品。

你的 Agent 读不懂的生产日志

· 阅读需 10 分钟
Tian Pan
Software Engineer

你把事故响应 agent 接入了 Splunk。你在系统提示里给了它查询语法,给了它执行 SPL 的工具,还有一个新鲜的 API token。第一次真正处理告警时,它拉了错的日志,总结了错的服务,信誓旦旦地报了错的客户。集成做得完美无缺,agent 却一文不值。

你忘了什么。十五年的日志惯例、没文档的字段名、跨越三次重组从 ERR 漂移到 error 再到 ERROR 的告警级别字符串、把 customer_id 在认证服务里变成 cust_id_v2_actual、在计费服务里变成 tenant.user.id 的团队特定后缀——这些东西没有一条出现在 prompt 里。你给了 agent 对 API 的访问权,但你没有给它访问那些让 API 变得有用的机构知识的权力。

这种失败的形状比 Splunk 大得多。任何把查询语言暴露给 agent、而底层语料是团队手工塑造了十年的工具,都会撞上这堵墙。Agent 拿到了动词,没拿到名词。

当评估指标全看“感觉”时,你的 A/B 测试无法区分两个模型

· 阅读需 9 分钟
Tian Pan
Software Engineer

你在实验中上线了一个模型替换。两周过去了,控制面板只变动了 0.1%,读数显示“无显著差异”。你得出结论,新模型与旧模型基本相同,然后继续进行其他工作。

它们并不相同。你的指标从未敏感到足以区分它们。

提示词 Diff 隐藏了自身的爆炸半径

· 阅读需 10 分钟
Tian Pan
Software Engineer

一个 PR(合并请求)进入了你的评审队列。Diff 显示系统提示词(system prompt)中修改了三个词:Output strictly valid JSON 变成了 Always respond using clean, parseable JSON。这看起来就像是一次文案润色。你快速浏览了一下,CI 检查勾标是绿色的,于是你点击了批准。总耗时:90 秒。

六个小时后,下游解析器开始拒绝带有尾随逗号和缺失字段的响应。结构化输出的错误率从接近零飙升至两位数,一个创收工作流陷入停滞。Diff 中没有任何迹象预示到这一点。Diff 中也不 可能 预示到这一点,因为 Diff 衡量的是错误的东西。

这就是评审提示词变更的核心问题:提示词 Diff 的大小完全无法说明其影响范围的大小。三五个词的修改与三段话的重写都只是文本,而文本 Diff 以相同的视觉权重呈现它们,就像对待任何其他编辑一样。但提示词并不是 描述 行为的文本 —— 它是 导致 行为的文本,而一次编辑所产生的因果爆炸半径在你评审的产物中是不可见的。

用户终将学会忽略的置信度评分

· 阅读需 12 分钟
Tian Pan
Software Engineer

你想要表现得诚实。你在智能体给出的每个答案旁边都标上了一个小小的 92%。当智能体第三次以 92% 的置信度给出错误答案后,你的用户就不再看那个数字了。他们并没有因此生气。他们只是学会了——就像人类在面对失灵信号时总会学到的那样——仪表盘上的指针并没有连接到引擎。数字还在那里。生成它需要消耗你的 token。但它不再能为任何人的决策提供参考。

这种失败模式是置信度校准(calibration)UX 研究不断重现的:呈现概率是一种信任承诺,而且这种承诺是单向的。一旦数字在用户的使用体验中被证明与正确性无关,这个分数就失去了意义——你为了展示它而投入的信任也随之崩塌。你无法在事后通过修正数字来挽回局面。这个数字现在只是个装饰品。

填充式工具调用:当智能体在表演勤奋而不是真正干活

· 阅读需 11 分钟
Tian Pan
Software Engineer

打开任何一个生产环境智能体的 trace,看一看在用户提问和第一个真正有用的动作之间到底跑了哪些工具调用。你会看到一个 get_user_profile 返回了一个根本没人用的名字、一个 check_status 返回绿色然后再也没被引用、一个 list_recent_orders 的结果被总结成"ok"然后直接丢掉。这些调用没有一个改变了最终答案。但每一个都花了真金白银的钱、真实的延迟,以及在 trace 里真实占一行。你的智能体已经学会了表演勤奋——而表演勤奋如今是你最大的单一浪费来源。

这就是填充式工具调用:智能体发出一个动作,不是因为它需要那个结果,而是因为"先想一想,再行动"的整体模式在训练时被反复奖励,多到模型现在会把"显得周全"当作回答任何问题的副作用来执行。这是一个 LLM 版本的初级分析师,故意打开五个根本不会读的标签页,好让坐在对面的高级同事看到自己很忙。区别只在于:初级分析师会累。智能体永远不会。

无人书写的工具调用授权层

· 阅读需 10 分钟
Tian Pan
Software Engineer

你的 API 网关验证了用户身份。你的工具端点会检查用户是否有权删除该行。在这两次检查之间,存在一个并不存在的层:即决定模型在此次对话中是否被允许以这些特定参数请求 delete_user 的那一层。

在大多数智能体(agent)技术栈中,那一层就是系统提示词(system prompt)。它会说“小心执行破坏性操作”和“只删除用户明确要求你删除的记录”之类的话。这句话并不是访问控制。它只是对一个非确定性过程的礼貌请求,而评估该请求的组件,恰恰是攻击者试图操纵的那个。

你的 Agent 端点是一个伪装成函数调用的分布式系统

· 阅读需 10 分钟
Tian Pan
Software Engineer

现代 AI 应用中最危险的一行代码看起来完全无害:

result = await agent.run(user_query)

它读起来就像一个函数调用。它有名称,接受参数,返回数值。你的 IDE 会自动补全它。你的类型检查器也觉得没问题。然而,就在这个单一的 await 背后,隐藏着一个远程的、多跳的、部分失效的分布式系统,而它却套着本地过程的语法外壳。代码看起来的样子与它实际表现出的行为之间的鸿沟,正是大多数生产环境 Agent 事故发生的地方。

那些由于模型选择了不同的 Token 而无法复现的 Bug

· 阅读需 11 分钟
Tian Pan
Software Engineer

用户提交了一个 bug。你的智能体生成的摘要掉了一段关键内容,或者 JSON 返回格式错误,或者回答一本正经地胡说八道。你打开工单,复制请求,然后重放(replay)。结果正常。你又重放了一次。依然正常。于是你把工单标记为“无法复现”并继续处理其他事情。

Bug 依然在那儿。真实用户依然在遇到它。你之所以关闭工单,是因为你的调试工具链默认了固定的输入会产生固定的输出——而你正在调试的组件实际上是从概率分布中进行采样的。

对于你的 AI 功能,“自研还是购买” 是个错误的问题

· 阅读需 10 分钟
Tian Pan
Software Engineer

每场关于 AI 功能的规划会议最终都会陷入同样的二元对立。一方想“直接套个 API”并在下个冲刺阶段发布。另一方则想“掌握模型”,以便公司掌控自己的命运。这种争论听起来很有战略意义,但实际上是一个分类错误。

“自研还是购买”将你的 AI 功能视为一个不可分割的整体,要么自研,要么购买。但 AI 功能并不是单一的事物。它是一个由至少五个不同层级组成的堆栈,每一层都有其自身的答案。如果团队将决策简化为一次掷硬币,几乎总是会掌握错误的层级并租用错误的层级,因为他们提出的问题无法区分这些层级之间的差异。

更好的问题不是“我们能做出来吗?”大多数东西你都能做出来。真正的问题是:如果竞争对手明天购买了完全相同的东西,哪一层会破坏我们的差异化? 这个问题会为你梳理出堆栈的优先级。

Token 预算是产品决策,而非配置值

· 阅读需 12 分钟
Tian Pan
Software Engineer

在你的代码库某处,有一行代码看起来像 retriever.search(query, top_k=8)。某位工程师在某个下午写下了那个 8。它从未被团队以外的任何人评审过,从未出现在规范文档中,也从未被重新审视。这一个整数决定了你的上下文窗口中有多少配额分配给了检索到的文档而非对话历史,决定了每次请求的成本,决定了响应速度的感官体验,并且——由于语言模型在长文本下的实际表现——还决定了答案的准确性。

这是一个产品决策。它却被硬编码在一个 f-string 里。

你的语音智能体将每一个转录错误都视为事实

· 阅读需 11 分钟
Tian Pan
Software Engineer

一名用户拨打你的保险语音代理,询问关于其免赔额(deductible)的问题。语音识别器听到了 "the duck tibble"。你的语言模型接收到了字符串 "the duck tibble",发现它逻辑不通,于是要么提出了一个令人生疑的后续问题,要么——更糟糕的是——胡编乱造了一个关于并不存在的产品答案。用户挂断了电话。你的日志显示了一次成功的交互:音频输入,生成转录,产生回应,没有抛出错误。

这就是几乎每个生产环境中的语音代理都存在的隐蔽失败。语音转文本系统完成了它的工作——它产生了一个最优的猜测。语言模型完成了它的工作——它对收到的文本进行了推理。而 Bug 就存在于它们之间的鸿沟中,存在于一个将概率猜测重新标记为事实的交接过程中。