跳到主要内容

639 篇博文 含有标签「llm」

查看所有标签

Prompt-Eligibility:数据分类中缺失的那一列

· 阅读需 13 分钟
Tian Pan
Software Engineer

调出你公司的数据分类政策。公开、内部、机密、受限——四个整齐的层级,每一个都映射到一组访问控制和一份批准的存储位置清单。现在问一个该政策从未准备回答的问题:这些层级中,哪些允许以发送给第三方模型 API 的 Token 序列的形式离开公司边界?

答案几乎总是沉默。这并非因为政策本身有误,而是因为它是不完整的。当今使用的每种分类方案都是为一种访问向量设计的,即询问“该员工是否被允许读取这一行?”Prompt 层引入了一个完全不同的向量:一个获得授权的服务读取了该行,将其转换为 Prompt,并将其跨网络传输给一个供应商,而该供应商可能会记录它、在其上进行训练,或将其以明文形式保存三十天。这些都不属于读取权限范畴。这些都不在覆盖范围内。

这就是缺失的一列。在你添加这一列之前,你的数据分类文档只是在自信地宣称一种你实际上并不具备的控制态势。

跨区域 Prompt 版本偏差:你的 CDN 误运行了六小时的 A/B 测试

· 阅读需 12 分钟
Tian Pan
Software Engineer

你在 09:14 发布了一个系统提示词(system-prompt)变更。发布仪表盘在 09:31 变绿。到 11:00 时,你的评估追踪器依然显示正常,成本仪表盘也无异常,但一位客户成功工程师联系了团队:仅在亚太地区,解析端的结构化输出错误上升了约 3%。北美无异常。欧洲无异常。

发布在覆盖 67% 的区域时自动暂停了,因为某个 POP 节点上的一个非核心健康检查在切换期间发生了抖动,而当时没人注意到。在六个小时里,us-easteu-west 运行着提示词 v47,而 ap-southap-northeast 仍停留在 v46。你正在运行一个按地理位置划分的实时 A/B 测试——只不过这个测试不是你设计的,你看不到测试过程,而且那个本应捕捉质量回退的评估套件正巧连接到其中一个区域的新版本,然后若无其事地忽略了问题。

这种失败模式并不是单个工具的 bug。它是将提示词通过为不同类型的工件构建的部署系统进行推送时,所产生的可预见的后果。

没人召集的索引策略委员会:超越一次性迁移的 RAG 语料库治理

· 阅读需 11 分钟
Tian Pan
Software Engineer

两年前,一个团队将他们的检索索引指向了 Wiki、Zendesk 导出文件以及公共文档的快照。上周,同一个索引返回了一个已弃用的运行手册(runbook),告诉 SRE 去重启一个已不存在的服务。该运行手册已经废弃了 18 个月。没人负责它的下线工作,所以没人把它删掉。Agent 自信地引用了它。模型没有错;错的是语料库(corpus)。

这是检索评估(retrieval evals)中不会出现的故障模式:语料库被视为一次性的工程决策,而实际上它是一个持续的治理问题。负责初始摄取(ingestion)的团队早已解散。本应标记出客户机密 PDF 的法律审查从未发生,因为没人告诉法务部门存在这个流水线(pipeline)。“新鲜度策略”(freshness strategy)只是一个在第三季度离职的人留下的 Slack 消息。检索索引变成了任何人抓取过的每一份文档的共享收件箱,而纳入标准已逐渐演变为“任何容易摄取的内容”。

推理力度预算编制:当思维 Token 成为财务账单的独立细目

· 阅读需 13 分钟
Tian Pan
Software Engineer

当你的财务团队第一次问,为什么单个用户在回答一个价值 0.1 美分的问题时产生了两美分的账单,那个电话讨论的不会是模型,而是发票上那行十二个月前还不存在的项目:推理 Token (reasoning tokens)。在账单上它们看起来像输出 Token,在大多数服务商那里也按输出 Token 的费率计费,而且它们没有天然的上限。一个在非推理模型上只需产生 400 个 Token 回复的查询,可能会悄无声息地消耗 8,000 个内部思考 Token 才能得出答案——唯一注意到这一点的人是核对支出的人。

在 API 时代的大部分时间里,“使用的 Token 数”是一个诚实的数字。你输入提示词,得到响应,账单是两者的清晰函数。推理模型打破了这种直觉。模型现在在发出调用者将阅读的答案之前,会生成一个隐藏的、可计费的、仅内部可见的思维链,而该链的大小取决于模型自身对问题难度的评估。用户可见的输出可能只有一句话,而账单可能长达十页。

重新规划而非重试:为什么大多数智能体错误并非瞬时性的

· 阅读需 12 分钟
Tian Pan
Software Engineer

一次日历写入返回了 409 Conflict。框架默认的错误处理器开始介入:退避 200ms,重试。同样的冲突。退避 400ms,重试。同样的冲突。退避 800ms,重试。等到智能体放弃并告诉用户“我无法预订会议”时,它已经浪费了三秒钟的延迟预算,去证明第一条响应就已经告诉它的事实:该时段已被占用。世界没有改变。它也不会在 800 毫秒内改变。重试永远不会奏效,因为这个错误中没有任何瞬时性的成分。

这是智能体系统中最为常见的错误处理 bug,而且它就隐藏在当今几乎每一个发布的框架之中。带有指数退避的重试模式是从无状态 HTTP 客户端中照搬过来的——在那里这种模式完全正确——但被引入到有状态的规划循环中时,它就完全错误了。对于智能体中的工具错误,正确的默认处理方式不是重试,而是重新规划。

采样参数继承:当 0.7 的温度从规划器泄露到验证器时

· 阅读需 12 分钟
Tian Pan
Software Engineer

一个在 8% 的情况下会推翻自己答案的验证器(verifier)并不是一个表现不稳定的模型。这是一个由于框架默认采用继承机制而进入生产环境的采样配置 Bug。规划器(planner)需要 temperature=0.7 来头脑风暴子任务的分解。而验证器 —— 其全部工作就是针对答案是否符合评分标准给出低方差的“是”或“否” —— 却是通过同一个 harness 调用实例化的,并默默地沿用了相同的温度设置。没有人故意这么设置。甚至根本没有人去设置它。

这是你的技术栈中最昂贵却无人认领的参数。它在调用树中不断累积:验证器上方的总结器、下方的结构化输出提取器,以及包裹整个流程的重试循环,都像使用全局变量一样沿用着规划器的“保持创意”旋钮。这笔账会同时体现在三个地方:评估的不稳定性、Token 支出,以及资深工程师花半天时间对一个结果发现根本不是退化的“性能退化”进行二分法排查。

AI 功能指标陷阱:为什么 DAU 和留存率在随机化表面 (Stochastic Surfaces) 上会产生误导

· 阅读需 13 分钟
Tian Pan
Software Engineer

一位产品经理(PM)带着一张幻灯片走进 AI 功能评审会,上面写着:“参与度 +12%,会话时长 +8%,留存率上升 3 个百分点。” 房间里的人纷纷点头。而在两个工位之外,客服主管正盯着另一张图表:涉及 AI 界面的工单增加了 22%,最常见的处理逻辑是“用户放弃,由人工客服协助”。这两个数字都是真实的,且都来自同一个产品。PM 的仪表盘建立在这样一个假设之上:AI 功能产生的事件形状与它所取代的按钮完全相同。事实并非如此。仪表盘统计的数据与用户实际体验之间的差距,正是 AI 功能在众目睽睽之下悄然失败的原因。

确定性功能的操作手册将交互视为点击流:用户触发一个事件,系统做出反应,用户继续操作。AI 功能具有不同的事件形状——一个包含阶段、重试、转向人工以及遥测数据永远无法看到的离线判断的“任务弧”(Task Arc)。将确定性仪表盘套用在这个任务弧上,就像是用 2018 年的面试流程来筛选 2026 年的工作职位。数字在上升,但这些数字本应预测的结果却在下降。

你的 stop_reason 在说谎:构建生产环境故障排查真正需要的停止分类法

· 阅读需 14 分钟
Tian Pan
Software Engineer

运维工程师调出一个 trace。模型已返回,span 正常关闭,API 调用显示 stop_reason: end_turn。从平台提供的各种信号来看,这是一次成功的生成。3 分钟后,客户报告说 Agent 煞有介事地写了半个配置文件,宣布操作完成,然后就继续下一步了。Trace 里没有任何预警信号,因为预警信号不在 API 协议里 —— 供应商提供的停止原因只有四到七类,而你的事故排查所需要的答案,恰恰隐藏在这些类别的缝隙之中。

停止原因(Stop reasons)是工程师在故障排查时最先查看的字段,也是最具误导性的字段。这些值是为运行时(runtime)设计的,旨在决定下一步该做什么:这一轮是否完成了?是否请求了工具?是否超出了预算?安全检查是否介入了?它们并不是为了让开发者重建答案出错的原因而设计的,而这两者之间的差异,正是生产团队耗费整个下午的时间所在。

流式 JSON 解析器:Token 与类型化对象之间的鸿沟

· 阅读需 13 分钟
Tian Pan
Software Engineer

模型正在逐个 Token 地输出 JSON。你的 UI 希望在字段出现的那一刻就进行渲染 —— 在冗长的回答正文之前显示置信度得分,或者在模型填充工具调用参数时实时显示它们。接着,有人尝试在每个数据块(chunk)上调用 JSON.parse,结果整个系统就崩溃了,因为 JSON.parse 是“全或无”的。它需要一个结构完整的文档才能返回任何结果。在模型输出闭合括号之前,你什么也显示不出来。

这不是一个可以通过 try/catch 解决的解析器问题。标准 JSON 解析器是针对内容长度已知的 HTTP 响应设计的。部分输入并不是它所建模的状态 —— 而是被视为“输入错误”。当你将 Token 流视为 HTTP 正文处理时,你继承了三十年来“文档要么完整,要么无效”的传统,而你的 UI 则为此付出了代价。

并行工具扇出的结构化并发:谁来负责部分失败?

· 阅读需 13 分钟
Tian Pan
Software Engineer

当你的智能体(Agent)扇出五个并行工具调用——跨三个索引进行搜索、查询两个数据库、调用一个外部 API——的那一刻,你已经跨越了一道无形的界限。你不再是在编写“提示-响应”(prompt-and-response)代码,而是在编写一个并发程序。大多数智能体框架都假装你没有在这样做,而账单会在凌晨 2 点准时送达。

这种假象是令人愉悦的。规划器(Planner)发出一个工具调用列表,运行时环境(Runtime)启动它们,收集返回的任何结果,最后由规划器消费这些汇总数据。从万英尺的高空俯瞰,这就像一个扇出 / 扇入(fan-out / fan-in)流水线,大多数团队在生产环境给他们上课之前,也确实是这样对待它的。问题在于,二十年的并发编程研究——部分失败语义(partial-failure semantics)、结构化取消(structured cancellation)、背压(backpressure)、确定性错误归因(deterministic error attribution)——已经解决了你即将重新发现的那些失败模式。而你的智能体框架在默认情况下,没有引入其中的任何一项。

系统提示词作为代码、配置或数据:影响全局的架构决策

· 阅读需 13 分钟
Tian Pan
Software Engineer

上个季度我交流过的一个团队发布了一个客户支持智能体,其系统提示词存储在 Postgres 的一行中,每个租户一行。这个方案听起来很合理:企业客户要求定制语气,“让提示词可编辑”是实现这一目标最廉价的方式。六个月后,发生了三件事。评估套件从 200 个案例膨胀到了 11,000 个,因为每个租户的提示词现在都需要自己的回归测试集。提示词更新工作流悄然变成了一个没有审核的写入路径,因为产品负责人被赋予了对表的直接访问权限。此外,由于部署流水线根本不知道提示词发生了变化,一个韩国租户提示词中损坏的 UTF-8 字符导致该租户的聊天机器人下线了两天,却没人察觉。

这些结果都不是需求强制导致的。它们是由一个无人刻意做出的架构决策所强制导致的:系统提示词存放在哪里?在代码中?在配置文件中?还是在数据库行中?团队选择了“数据库”,因为这是实现功能最快的路径,而后果在接下来的几个月里级联影响到了每一个相邻系统。

Tokenizer Churn:你的“兼容”模型升级中隐藏的破坏性变更

· 阅读需 13 分钟
Tian Pan
Software Engineer

供应商声称这次升级是无缝替换。API 契约保持不变。配置中的模型名称几乎没变。一周后,你的上下文窗口防御机制(context-window guard)开始在以前从未触发过的提示词(prompts)上报警,你的停止序列(stop-sequence)正则匹配在了错误的位置,而你的少量样本(few-shot)示例之一开始产生一个极其自信的错误答案,而你的评估套件恰好没有覆盖到这一点。没有人动过提示词。没有人动过温度参数(temperature)。有人悄悄重新训练了分词器(tokenizer)。

分词器更改是供应商不会称之为“破坏性”(breaking)的破坏性更改。API 层面保持了字节级稳定,SDK 没有升级主版本,发布说明中提到了“改进的指令遵循能力”——但从你的输入字符串到模型实际看到的整数序列的映射函数已经被替换了。你的代码关于文本如何转换为标记(token)的每一个假设现在都出现了微妙的偏差。这种隐形代价是,在有人重新通过 count_tokens 运行标准提示词并发现答案之前,你会经历两周“感觉模型不太一样”的困惑期。