跳到主要内容

861 篇博文 含有标签「insider」

查看所有标签

影子 MCP:你的安全团队从未听说过的工具服务器已经在工程师的笔记本电脑上运行了

· 阅读需 14 分钟
Tian Pan
Software Engineer

你的安全团队拥有公司信用卡上每一项 SaaS 订阅的完整清单、每一个获得管理员授权的 OAuth 应用,以及连接到公司 Wi-Fi 的每一台设备。然而,对于你的高级工程师笔记本电脑上当前绑定到 127.0.0.1 的七个进程,他们却完全视而不见——一个带有长期 Staging API 令牌的“部署助手”,一个订阅了包含客户数据的 Slack 频道的“工单分类器”,以及一个拥有生产分析数据仓库读取权限的“发布说明生成器”。这些都不在供应商名单上。它们不会出现在 SSO 日志中。所有这些都在利用工程师现有的凭据运行,执行着从未经过审批的操作。

这就是影子 MCP(Shadow MCP),它是企业中增长最快的未管理授权面。模型上下文协议(Model Context Protocol)使得将任何工具接入任何 LLM 的成本变得极低,而工程师们——天性使然——首先接入了那些最显而易见的工具。Saviynt 的 CISO AI 风险报告指出,75% 的 CISO 已经发现其生产环境中运行着未经授权的 AI 工具。GitHub MCP 服务器在 2026 年初的周安装量突破了 200 万次。Postgres MCP 服务器允许 LLM 对开发者能接触到的任何数据库执行 SQL 提示词,其周安装量已超过 80 万次。这些数字中没有一个代表企业的 IT 决策。

共享提示词的“夺旗日”:当一次修改引发三十个团队的性能回归

· 阅读需 12 分钟
Tian Pan
Software Engineer

对共享系统提示词的第一次修改感觉就像是优秀的工程实践。三个团队都在各自智能体的顶部粘贴了相同的 18 行安全前导指令,有人注意到了这一点,内部平台团队说了一个显而易见的提议:让我们把它中心化吧。于是 prompts.common.safety_preamble@v1 出现在了注册仓库中。由于这是阻力最小的路径,加上安全团队很高兴能由一个团队统一负责措辞,30 个团队在短短一个季度内就采用了它。在接下来的两个季度里,这看起来就像是一个完美的 DRY (Don't Repeat Yourself) 胜利。

随后,安全团队需要对措辞进行微调。可能是新的合规条例收紧了助手可以主动提供的用户信息范围,也可能是红队发现需要向拒绝条款中增加一句话。平台团队完成了修改,发布了 v2 版本。不到一天,支持队列就充满了消费团队的消息:我们的评估 (eval) 下降了、我们的格式崩了、我们的工具调用率减半了、我们的语气变了、延迟增加了(因为模型开始进行更多推理)。每个团队都希望回退修改。而安全团队需要发布它。没有人能在不进行重新评估的情况下升级,但又没有人负责重新评估。欢迎来到共享提示词的“旗帜日 (flag day)”。

流式 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)——已经解决了你即将重新发现的那些失败模式。而你的智能体框架在默认情况下,没有引入其中的任何一项。

Token 放大:烧掉你账单的提示词注入攻击

· 阅读需 11 分钟
Tian Pan
Software Engineer

用户提交了一个 0.01的请求。你的智能体读取了一个网页。40秒后,该次对话的推理账单变成了0.01 的请求。你的智能体读取了一个网页。40 秒后,该次对话的推理账单变成了 42。该查询在技术上是成功的——智能体返回了一个合理的答案。只是为了得到这个答案,它经历了三个嵌套的子智能体、一次 200K token 的文档获取,以及一个递归的计划优化循环。这些扇出(fanout)操作并非用户的本意,而是隐藏在智能体所读取页面中的一句话。

这就是代币放大(token amplification):一种提示词注入攻击,它不窃取数据,不调用未授权工具,也不会留下明显的安全特征。它只是烧光你的账单。云账单是攻击载荷,而用户的请求则是载体。

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

· 阅读需 13 分钟
Tian Pan
Software Engineer

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

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

你的工具目录遵循幂律分布,而你却在针对长尾进行优化

· 阅读需 13 分钟
Tian Pan
Software Engineer

调取任何生产环境智能体(agent)的一周工具调用追踪(tool-call traces),你会发现其规律如出一辙:三四个工具处理了 90% 的调用,其余数十个工具则瓜分了剩下的 10%。工具目录呈现幂律分布(power law),但框架却将其视为均匀列表。每个工具描述都会出现在每个系统提示词(system prompt)中,每个选择准则都对工具一视同仁,每个评估(eval)在对目录进行采样时,都仿佛 search-files 调用和 refund-issue 调用来自同一分布。事实并非如此。

这种“扁平化”处理的代价在爆发前往往是隐形的。团队增加第 18 个工具,规划器(planner)对最初三个工具的准确率下降了两个百分点,却没人能将这种退化归因于特定变更,因为所有指标都同时发生了偏移。而评估套件本身在目录中也是均匀分布的,它将这些下滑平均成一个看起来依然正常的数字。与此同时,本轮对话中模型不会调用的工具描述所消耗的 token,已经超过了用户实际提示词的 token。

工具组合提权:你的安全审查清理了节点,而非边缘

· 阅读需 12 分钟
Tian Pan
Software Engineer

read_file 是安全的。send_email 是安全的。你的安全审计对照各自的威胁模型分别批准了它们:对已知目录的只读访问,以及通过带有速率限制和收件人日志记录的已认证中继发送的出站邮件。每一个都通过了,两者都已注册。随后智能体将它们组合在一起,而客服工单中的一行注入文本就将这对组合变成了外泄工具,原有的审计对此根本没有描述这种风险的术语。

危险并不存在于工具图谱的任何节点中,而是在于边。你运行的每次针对单个工具的安全审计都是对顶点的判定;而智能体实际的权限表面是目录中的路径集合,这个集合呈二次方增长,而你的审计流程却只能线性扩展。当你的智能体拥有 15 个注册工具时,你审计了 15 个项,却发布了大约 200 个可达的两步组合,其中没有一个经过人工审核。

拒绝还是上报:置信度门控 AI 中的双阈值问题

· 阅读需 14 分钟
Tian Pan
Software Engineer

大多数生产环境中的 AI 功能在发布时只带有一个置信度阈值。在阈值之上,模型给出回答;在阈值之下,用户会得到一句生硬的“我不确定”。这个单一的数值同时承担着两个完全不同的任务,这就是为什么即便你对已回答查询的准确率看起来不错,但信任度指标却已经连续两个季度下滑的原因。

正确的设计至少应该有两个切分点。一个“弃权”(abstain)阈值设在低位:低于该值时,模型拒绝回答,因为此时保持沉默比给出任何答案都更有价值。一个“升级”(escalate)阈值设在中间:在两个切分点之间,系统将案例交给人工审核员,而不是直接将其丢弃。将它们合并成一个刻度盘,你发布的产品在出错时和不确定时会让人感到同样无用——在用户只需打开另一个标签页就能找到免费替代品的市场中,这是最糟糕的处境。

这并不是什么新鲜想法。拒绝选项分类器(reject-option classifier)的文献自 20 世纪 70 年代以来就一直在主张拆分阈值,将“歧义”拒绝(输入介于已知类别之间)与“距离”拒绝(输入远离任何训练数据)区分开来。生产环境中的 AI 团队总是在以惨痛的方式重新学习这一教训,通常是在首次发布大约六个月后,当支持队列中挤满了询问“这玩意儿是坏了还是怎么了”的人时。

供应商 99.9% 的 SLA 对你的 Agent 来说衡量边界错了

· 阅读需 14 分钟
Tian Pan
Software Engineer

一个模型提供商发布了 99.9% 的可用性 SLA。采购团队将其理解为“三个九,每年四个小时的停机时间,对于非 0 级(非核心)工作负载是可以接受的”。六个月后,智能体(Agent)功能上线,值班仪表板显示用户感知的任务成功率约为 98% —— 这个数字没有写进任何合同,在提供商的状态页面上也找不到,而且没有人为此负责。提供商满足了他们的 SLA,而产品却没达到其 SLO。两者同时成立,而这种差距并不是一个 bug —— 这是一个算术问题。

大多数团队都忽略了算术这部分。提供商的 99.9% 是针对同步请求工作负载进行衡量的 —— 一个用户,一个提示词,一个响应,一个计费事件。而智能体并不会产生这种工作负载。一个用户感知的任务会扇出(fan out)为 8 到 20 次推理调用,它会对瞬时错误进行重试,对慢速调用进行对冲(hedge),并聚合部分输出。每一次调用都是对提供商故障分布的一次独立抽样,如果任何关键调用失败,任务就会失败。SLA 覆盖的边界和用户感受到的边界并不是同一个边界。

你的智能体发件箱将是你的下一个送达率事故

· 阅读需 13 分钟
Tian Pan
Software Engineer

当这种情况第一次发生时,值班工程师正盯着已经全红的 Gmail Postmaster 仪表盘,支持信箱因为客户重置密码邮件落入垃圾邮件箱而告急,而导致这一切的智能体(Agent)仍在运行。在当地时间凌晨 4 点到上午 9 点之间,它从公司的主要发送域名发送了 8 万封“个性化跟进邮件”,且全部使用了计费系统所用的同一个 DKIM 密钥签名。等有人注意到时,花费三年建立的域名声誉已毁于一旦,接下来六周内,公司所依赖的每一条事务性消息的收件箱投递率也将随之化为乌有。

从智能体发送邮件看起来就像是一个单行的工具调用。send_email(to, subject, body) 是最经典的演示,每个框架都将其作为入门集成提供。但邮件不同于其他工具。错误的数据库查询可以回滚,错误的 API 调用会返回错误。而一批糟糕的邮件会降低你公司发送的每一封其他邮件的送达率,且持续数周之久。这里没有可以回滚的事务,因为邮件已经发送到了接收方的邮件服务器,而这些服务器正在记录你域名的声誉历史。

为什么 AI 生成的注释腐烂得比代码还快

· 阅读需 12 分钟
Tian Pan
Software Engineer

当智能体(agent)在同一个 diff 中编写函数和注释时,该注释并不是文档。它是代码在编写时的转述,由同一个模型从同一个上下文中生成。当代码第一次发生变动时,它就会悄然出错。函数被重构,参数类型改变,或者添加了提前返回(early-return),但注释却保持不变。到下个季度,注释所编码的规范已不再与代码匹配,而下一位读者会因为注释更易读而选择相信它。

这是一个古老的失效模式 —— 人类修改代码,注释保持陈旧 —— 但智能体从三个维度同时加速了这一进程。注释量增加了,因为智能体无论是否需要,都会给每个函数添加文档块(doc block)。注释的语法非常完美,所以审阅者不会将其标记为低质量。而且,注释用与代码实际执行不同的术语来转述代码,因此它们看起来像文档,但实际上编码了第二套规范,这套规范独立于第一套规范而漂移。