网易首页 > 网易号 > 正文 申请入驻

多轮对话突然失忆?.NET聊天代码在三处弄丢加密推理

0
分享至

有一种bug不会抛异常。日志里没有一行变红,测试也不会失败。推理模型第一轮答得很好,到了第二轮却像第一轮从未发生过。你先后怀疑提示词、温度参数、模型本身,真正的原因往往只是自己聊天循环里的一行代码。

机制是这样的:通过Microsoft.Extensions.AI调用 OpenAI 的 Responses API,使用推理模型,服务端不存储内容(store=false,即零数据保留),同时请求加密推理时,响应里会带一个加密推理项。在 .NET 中它表现为一个TextReasoningContent部分,含一个ProtectedData字符串,以及放在AdditionalProperties["reasoningItemId"]里的 item id。服务端不会替你记住它。下一轮如果不把它发回去,模型就无法延续自己的推理链。

有人基于 Microsoft.Extensions.AI 10.11 做了一个 .NET 10 小样例来定位这个问题。它跑在一个离线的假模型上,该假模型会输出真实的 TextReasoningContent 部分,并在回答里报告自己收到了多少个加密项(priorProtected=N),因此不用 API key 也能看到这个 bug。样例共38 个测试(29 个单元测试、9 个集成测试)。下面是被观察到推理内容消失的三个位置,每一处都配了测试。

要保住的是什么

推理调用返回的每条 assistant 消息,装的不只是文本。真正要紧的是这些部分。真实客户端来自 Responses 适配器,而不是 Chat Completions 那个:

  • OpenAIClient(apiKey).GetResponsesClient().AsIChatClient(modelId)拿到客户端(该 API 属实验性 OPENAI001,样例在 Directory.Build.props 里统一抑制了一次警告)。

记住这张表。下面三处泄漏归根到底是一件事:某个环节只留下了 TextContent,把其余部分扔了。

泄漏一:用 response.Text 重建 assistant 消息

几乎每篇聊天教程都教这一行:history.Add(new ChatMessage(ChatRole.Assistant, response.Text))。response.Text 只是文本部分的便捷视图,推理部分永远进不了历史。样例的 CLI 照此操作再追问时,打印结果是这样的:

  • Response had ProtectedData: True
  • History has ProtectedData after text-only append: False
  • Follow-up text: Offline (Medium, stateless, priorProtected=0): answered "Follow-up".

响应里有加密推理,历史里没有。追问发出去时,携带的先前推理项是零。修法是追加整个响应:history.AddMessages(response)。样例把它包在一个小助手ReasoningHistory.AppendResponse(history, response)后面,免得日后有人把它“简化”回去。测试故意展示失败:TextOnly_Append_Loses_ProtectedData断言历史里没有受保护的推理内容,而它的孪生测试AppendResponse_Preserves_ProtectedData用助手做同样的事,断言相反。样例 API 甚至有一个故意写错的端点POST /api/chat/turn/wrong,只追加文本,其响应报告 hasProtectedInResponse: true、hasProtectedInHistory: false,方便向团队演示这个 bug。

泄漏二:流式输出,加密块最后才到

流式让问题更糟,因为实时输出看起来是完整的。更新大致按这个顺序到达:先是推理摘要分块,然后是回答文本分块,最后是一个只带加密部分、没有任何可见文本的最终更新。样例的假模型复刻了这个顺序,并有单元测试盯着它,防止假模型跑偏。

常见的 UI 循环会把文本分块拼成一个字符串,再把这个字符串存成 assistant 消息。用户看到的内容都在,加密部分不在,因为它从来就没有文本。修法是保留每一次更新,把它们合并回一个响应再追加:遍历GetStreamingResponseAsync时把每个 update 收进列表,同时照常 yield 给 UI,最后调用updates.ToChatResponse()合并,再交给 AppendResponse。ToChatResponse() 会把分块合并成消息,于是摘要文本和最后一次更新里的 ProtectedData 都进了历史。演示在流结束后打印:After stream, history reasoning parts: 2, protected: True。测试StreamAsync_Coalesces_Into_History_With_ProtectedData排空流后断言 HasProtectedReasoning(history) 为真。

泄漏三:经过会话存储的那一趟

聊天历史迟早要离开内存,进缓存、进数据库、进 JSON 列,因为存在人工介入的暂停,或者有第二台服务器。这一趟有两种丢推理的方式:

  • DTO 只带 role 和 text。这就是泄漏一换了个地方,藏进了持久层。要存完整的内容列表,而不是拍平的字符串。
  • 回程时的类型变化。经过 System.Text.Json 往返后,AdditionalProperties 里的 reasoningItemId 值回来时是 JsonElement,不再是 string。写 value as string 的代码会悄悄拿到 null。

样例用防御式写法读这个 id:值若是 string 直接返回,若是 ValueKind 为 String 的 JsonElement 就取 GetString(),其余情况走 ToString()。测试GetReasoningItemId_Reads_JsonElement_After_Serialization把字典序列化、反序列化进一个新的 TextReasoningContent,再检查 id 仍能读回 "rsn_json"。

范围要说清楚:样例的 SessionStore 是内存实现(标注了“仅演示”),项目里没有数据库往返。它测的是最先咬人的那一环,也就是字典过一遍 JSON。

反向泄漏:别让它进日志

一旦把 ProtectedData 留在身边,下一个风险是它跑到不该去的地方,比如一个保留一年的日志索引。样例的ReasoningAuditChatClient是一个 DelegatingChatClient,只记录 effort、token 用量(含 ReasoningTokenCount)和截断的推理摘要,别的什么都不记。它还带了一个故意较真的绊线:AssertNoProtectedDataInLogPayload,即将写入日志的载荷里只要出现假模型的 enc_ 前缀就抛异常。这听起来偏执,直到有人在事故处理时加上一句“把整个响应都记下来”。

一个测试兜住三处

如果只加一个测试,就让它是对假模型跑的真实两轮对话,并让假模型报告自己收到了什么:MultiTurn_Preserves_Encrypted_Items先以低推理强度发第一轮,再以高推理强度发第二轮,断言第二轮文本里含 priorProtected=1,且历史里推理部分计数为 2。日后无论引入三处泄漏中的哪一处,第二轮都会以 priorProtected=0 回来,这个测试就会失败。

没有验证的部分

38 个测试全部跑在离线假模型上。它产出的内容类型与 OpenAI 适配器一致,但它不是 OpenAI,CI 从不发起真实调用。要在网络上做真正无状态的调用,还需要关掉存储输出并要求包含加密推理(项目 README 指向 ChatOptions.RawRepresentationFactory 和 CreateResponseOptions)。样例没有跑这条路径,依赖它之前请核对当前的 OpenAI .NET 文档。另外,如果使用带 ConversationId 的存储响应,服务端会保留先前的项,泄漏一的伤害会小一些;但为了回放和审计,你仍然希望自己的历史里存着完整消息。

完整可运行的版本包含 Core 库(历史助手、普通与流式轮次的聊天服务、推理审计中间件、离线推理客户端)、一个同时带正确与故意写错端点的最小 API、一个 CLI 演示和全部 38 个测试,外加一份分步 PDF 指南,无需 API key 即可运行。准备发起真实调用时,把 ReasoningChat:Provider 设为 openai,并通过 user-secrets 或环境变量提供密钥。

你的聊天历史在两轮之间存在哪里,推理部分有没有熬过这一趟,值得现在就查一遍。

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
海南男子钓获稀有海鱼,鳞片晶莹发绿,像玉雕工艺品!网友:所以说龙一定存在

海南男子钓获稀有海鱼,鳞片晶莹发绿,像玉雕工艺品!网友:所以说龙一定存在

狸猫之一的动物圈
2026-10-21 09:04:47
于东来:已拿出2000万元投资爱情研究小组,让大家明白什么是爱然后会爱,孩子教育研究小组也投2千万

于东来:已拿出2000万元投资爱情研究小组,让大家明白什么是爱然后会爱,孩子教育研究小组也投2千万

界面新闻
2026-10-21 16:27:22
学医的有多相信玄学?网友:有时候不得不服

学医的有多相信玄学?网友:有时候不得不服

康富贵碎碎念
2026-10-22 11:49:43
信号强烈!日本连发四条中国海军动态,西太平洋博弈大幕正式拉开

信号强烈!日本连发四条中国海军动态,西太平洋博弈大幕正式拉开

华史谈
2026-10-20 13:04:04
中国当前最危险的,可能不是台湾,更不是美日!真正致命的,是一双藏在暗处的手,正在不声不响地扼住我们的咽喉

中国当前最危险的,可能不是台湾,更不是美日!真正致命的,是一双藏在暗处的手,正在不声不响地扼住我们的咽喉

扶苏聊历史
2026-10-12 10:16:50
万万没想到,那曲7级地震震中区域人烟稀少

万万没想到,那曲7级地震震中区域人烟稀少

桃叶渡春
2026-10-23 00:45:05
中日不能开战?台湾退将直言,一旦日本出兵台海,30分钟内瘫痪!

中日不能开战?台湾退将直言,一旦日本出兵台海,30分钟内瘫痪!

君墨谈史
2026-10-21 14:35:26
你还在纠结32GB还是64GB内存:单条1TB DDR6已经公布!

你还在纠结32GB还是64GB内存:单条1TB DDR6已经公布!

快科技
2026-10-22 15:49:15
员工离职情绪高涨,宝马提前关闭补偿计划

员工离职情绪高涨,宝马提前关闭补偿计划

观察者网
2026-10-22 18:22:07
塔什干亚锦赛:世界冠军大崩盘!王艺迪全输,蒯曼大获全胜

塔什干亚锦赛:世界冠军大崩盘!王艺迪全输,蒯曼大获全胜

寒光竹影m
2026-10-22 10:20:42
俄乌战争这场仗打不下去了

俄乌战争这场仗打不下去了

凤眼论
2026-10-21 20:36:36
狂加430万部!消费者买爆iPhone Duo,苹果紧急追加供应链订单

狂加430万部!消费者买爆iPhone Duo,苹果紧急追加供应链订单

IT之家
2026-10-22 13:33:37
我国越来越多的人患脑梗?建议:停止食用“4物”,保护大脑

我国越来越多的人患脑梗?建议:停止食用“4物”,保护大脑

任医生聊健康
2026-09-17 13:15:13
奢靡荒唐的白马会所:性交易泛滥,让无数富婆挥金如土

奢靡荒唐的白马会所:性交易泛滥,让无数富婆挥金如土

天启大世界
2026-10-13 17:17:54
北约爆发大规模抗议,要求赶走鲁比奥,与以色列断交

北约爆发大规模抗议,要求赶走鲁比奥,与以色列断交

磊子讲史
2026-10-10 14:25:51
6.8万人见证 欧冠3连胜!73岁老帅带队狂飙 奖金5010万欧元

6.8万人见证 欧冠3连胜!73岁老帅带队狂飙 奖金5010万欧元

叶青足球世界
2026-10-22 08:58:53
陈惠敏承认街头打不过梁小龙,可梁小龙却说只能给黄元申当徒弟

陈惠敏承认街头打不过梁小龙,可梁小龙却说只能给黄元申当徒弟

一盅情怀
2026-10-21 14:08:09
杨超越在工厂打工时候的照片曝光!网友炸了:这妥妥的厂花啊!

杨超越在工厂打工时候的照片曝光!网友炸了:这妥妥的厂花啊!

黎兜兜
2026-08-25 22:25:21
白应苍在执行死刑前坦言:缅北四大家族犯下最大的判断错误,是中方已经动了真格

白应苍在执行死刑前坦言:缅北四大家族犯下最大的判断错误,是中方已经动了真格

唠叨说历史
2026-10-22 17:30:41
房事不戴套被妻子拒绝,男子怒杀妻儿后奸杀女儿,福永冰柜藏尸案

房事不戴套被妻子拒绝,男子怒杀妻儿后奸杀女儿,福永冰柜藏尸案

易玄
2026-10-22 11:13:16
2026-10-23 02:44:49
闪存猎手
闪存猎手
全网蹲好价的野生捕手,算力与羊毛都不可辜负。
296文章数 82关注度
往期回顾 全部

科技要闻

腾讯云谷歌紧急行动!互联网安全出大事

头条要闻

西藏7.0级地震亲历者:房子震得嘎嘎叫 不敢回家

头条要闻

西藏7.0级地震亲历者:房子震得嘎嘎叫 不敢回家

体育要闻

卢卡:伦德伯格,欢迎来到NBA

娱乐要闻

芭莎盛典,张小斐因救场实现口碑暴涨

财经要闻

宁德,跌成了一只红利股?

汽车要闻

搭城市NOA/续航555KM 捷达M6上市售7.98万起

态度原创

本地
教育
时尚
房产
公开课

本地新闻

一场垂直登高赛跑出了"山城"的真正内核

教育要闻

研三秋招找工作才发现:有没有论文不重要,重要的是英语六级不能少,好多国央企都卡六级

网红老头的荤话,售价16800

房产要闻

租金大跳水!荒了6年,海口这个地标商业,开始急了!

公开课

李玫瑾:为什么性格比能力更重要?

无障碍浏览 进入关怀版