<?xml version="1.0" encoding="utf-8" ?><rss version="2.0"><channel><title><![CDATA[2301_81410839的博客]]></title><description><![CDATA[]]></description><link>https://blog.youkuaiyun.com/2301_81410839</link><language>zh-cn</language><generator>https://blog.youkuaiyun.com/</generator><copyright><![CDATA[Copyright &copy; 2301_81410839]]></copyright><item><title><![CDATA[推理上下文借用跨越了哪些 Rust 安全边界]]></title><link>https://blog.youkuaiyun.com/2301_81410839/article/details/170245641</link><guid>https://blog.youkuaiyun.com/2301_81410839/article/details/170245641</guid><author>2301_81410839</author><pubDate>Sat, 07 Nov 2026 18:33:46 +0800</pubDate><description><![CDATA[一个推理上下文通常包含 KV 状态、工作缓冲和当前序列位置。把它借给一次生成任务，看起来只是传入。但外部推理库可能保存输入指针，设备任务也可能在 Rust 函数返回后继续访问这些内存。此时，源码里已经结束的借用，不一定对应真正结束的使用。安全封装需要把运行时的使用区间映射到 Rust 生命周期。先分清模型、上下文、单次请求三层，再决定引用该放在哪里。]]></description><category></category></item><item><title><![CDATA[模型句柄所有权跨越了哪些 Rust 安全边界]]></title><link>https://blog.youkuaiyun.com/2301_81410839/article/details/170202024</link><guid>https://blog.youkuaiyun.com/2301_81410839/article/details/170202024</guid><author>2301_81410839</author><pubDate>Sat, 07 Nov 2026 00:06:22 +0800</pubDate><description><![CDATA[把 C 推理库的model*包进 Rust 结构体，真正困难的部分往往还没开始。指针不是空值，并不代表模型仍然存活；结构体实现了Drop，也不能证明另一个线程没有同时调用释放函数。这里讨论一种明确的场景：外部库创建模型并交回一个句柄，调用方负责释放；推理上下文可能依赖该模型。目标是让安全 Rust 调用者不必重复处理这份外部契约。以下代码是绑定层骨架，外部符号须由所接入的运行时提供，不是一套可直接连接任意引擎的通用 API。]]></description><category></category></item><item><title><![CDATA[推理取消令牌需要模型运行时提供什么能力]]></title><link>https://blog.youkuaiyun.com/2301_81410839/article/details/170202014</link><guid>https://blog.youkuaiyun.com/2301_81410839/article/details/170202014</guid><author>2301_81410839</author><pubDate>Sat, 07 Nov 2026 00:05:45 +0800</pubDate><description><![CDATA[取消与自然结束可能同时发生。假设最后一个 token 已经产生，但取消信号也刚到达，服务究竟返回成功还是取消？两种策略都能成立，前提是整个链路一致。可以让已经提交并确认的完整结果优先，或者让尚未发送的结果服从取消状态。不要在 HTTP 层采用一种规则、日志里采用另一种规则，否则成功率和取消率会互相打架。流式输出还要划清“已发送”和“待发送”。取消不能收回已经发给客户端的 token，却可以丢弃尚未发送的后续输出。输出队列需要有界，否则计算停止后，队列里仍可能保留大量结果和引用。]]></description><category></category></item><item><title><![CDATA[常量折叠成立需要哪些语义前提]]></title><link>https://blog.youkuaiyun.com/2301_81410839/article/details/170201988</link><guid>https://blog.youkuaiyun.com/2301_81410839/article/details/170201988</guid><author>2301_81410839</author><pubDate>Sat, 07 Nov 2026 00:05:00 +0800</pubDate><description><![CDATA[表达式的输入都是常量，编译器就可以提前求值吗？对一个只有自然数加法的教学语言，答案很接近“可以”。换成带位宽、溢出规则、浮点异常和状态读取的真实推理图，这个判断就不够用了。常量折叠的目标是把计算换成一个等价常量。省掉一次运行时操作只是结果；等价性才是允许替换的依据。]]></description><category></category></item><item><title><![CDATA[分块矩阵乘法在哪些输入形状下容易出错]]></title><link>https://blog.youkuaiyun.com/2301_81410839/article/details/170201949</link><guid>https://blog.youkuaiyun.com/2301_81410839/article/details/170201949</guid><author>2301_81410839</author><pubDate>Sat, 07 Nov 2026 00:03:11 +0800</pubDate><description><![CDATA[分块矩阵乘法在方阵、整齐倍数尺寸上很容易写对。真正能检验实现的，是三个维度同时不整齐的时候：输出最后一行、最后几列，以及归约维度不足一块的那段乘加，分别受不同边界控制。设行主序矩阵 A 的形状为 M×K，B 为 K×N，结果 C 为 M×N。本文只讨论二维、连续、无转置的乘法，先把数值正确性与索引边界说清，再考虑布局和并行优化。]]></description><category></category></item><item><title><![CDATA[推理缓存一致性如何区分随机差异与真实退化]]></title><link>https://blog.youkuaiyun.com/2301_81410839/article/details/170201860</link><guid>https://blog.youkuaiyun.com/2301_81410839/article/details/170201860</guid><author>2301_81410839</author><pubDate>Fri, 06 Nov 2026 23:57:25 +0800</pubDate><description><![CDATA[本地推理里，“缓存”可能指已经分词的输入、提示前缀的 KV 状态，也可能是整段答案。它们的命中条件不同。本文重点讨论前缀 KV 缓存：复用已计算的前缀状态，让后续解码从正确位置继续。一个可用于回归的请求身份，至少应说明模型与权重版本、分词器及聊天模板、前缀 token ID、位置编码相关配置，以及会影响该状态的适配器或计算设置。具体键字段必须随运行时能力调整，不能只哈希可见文本。相同字符串经过不同模板，可能得到不同 token 序列；相同 token 在不同位置配置下，也不必拥有可互换的缓存。]]></description><category></category></item><item><title><![CDATA[给本地推理引擎实现推理错误转换]]></title><link>https://blog.youkuaiyun.com/2301_81410839/article/details/170139869</link><guid>https://blog.youkuaiyun.com/2301_81410839/article/details/170139869</guid><author>2301_81410839</author><pubDate>Thu, 05 Nov 2026 14:31:34 +0800</pubDate><description><![CDATA[原生推理接口返回一个整数，Rust 服务需要返回一个能被调用者处理的错误。这两者之间不应该只有。没有阶段、类别和原始原因，调用方无法判断该修改输入、等待资源、结束请求，还是隔离实例。错误转换的目标，是把底层信息放进稳定的服务语义里，同时保留追查原因的入口。它不负责修复已经损坏的内存，也不能把一次不符合 ABI 的调用变成安全操作。]]></description><category></category></item><item><title><![CDATA[在 Rust 执行器实现生成任务有界接入]]></title><link>https://blog.youkuaiyun.com/2301_81410839/article/details/170139786</link><guid>https://blog.youkuaiyun.com/2301_81410839/article/details/170139786</guid><author>2301_81410839</author><pubDate>Thu, 05 Nov 2026 14:30:20 +0800</pubDate><description><![CDATA[给推理接口加一个并发信号量，并不一定让服务有界。如果每条请求先创建任务，再在任务内部等待许可，运行中的推理数量虽然受控，等待中的任务、输入文本和会话对象仍可能持续增长。流量超过处理能力时，内存会先替队列承担压力。有界接入需要同时约束等待队列、正在执行的工作，以及每个请求可能占用的上下文资源。三个限制各自回答不同问题，不能只保留一个叫作的数字。]]></description><category></category></item><item><title><![CDATA[用 Rust 写出算子依赖排序最小实现]]></title><link>https://blog.youkuaiyun.com/2301_81410839/article/details/170139691</link><guid>https://blog.youkuaiyun.com/2301_81410839/article/details/170139691</guid><author>2301_81410839</author><pubDate>Thu, 05 Nov 2026 14:29:06 +0800</pubDate><description><![CDATA[计算图中，节点在文件里的顺序不一定是可以执行的顺序。一个加法节点只有等两个输入都准备好，才有资格进入就绪队列。拓扑排序做的就是这件事：为一个有向无环图找到满足依赖的节点序列。本文实现最小的 Kahn 算法，输入是一组节点及其依赖编号，输出是一种合法顺序。它处理静态数据依赖，不负责设备异步完成、内存回收和跨请求调度。先把“先后关系”算对，再给执行器增加并发能力。]]></description><category></category></item><item><title><![CDATA[建立累加精度选择的参考实现]]></title><link>https://blog.youkuaiyun.com/2301_81410839/article/details/170139598</link><guid>https://blog.youkuaiyun.com/2301_81410839/article/details/170139598</guid><author>2301_81410839</author><pubDate>Thu, 05 Nov 2026 14:27:48 +0800</pubDate><description><![CDATA[这个算子使用 FP16”并不足以描述它的数值行为。权重可以用 FP16 存储，乘法使用某种设备指令，部分和进入 FP32 累加器，最后再转回 FP16。另一个内核即使输入输出类型一样，中间舍入和归约顺序也可能不同。参考实现首先要把这些阶段拆开，明确每一步的类型和规则。本文给出选择与验证思路，不把任何一种累加器宣布为所有模型、所有设备上的最佳方案。]]></description><category></category></item><item><title><![CDATA[为本地推理服务搭建上下文长度边界]]></title><link>https://blog.youkuaiyun.com/2301_81410839/article/details/170139508</link><guid>https://blog.youkuaiyun.com/2301_81410839/article/details/170139508</guid><author>2301_81410839</author><pubDate>Thu, 05 Nov 2026 14:26:35 +0800</pubDate><description><![CDATA[用户提交的文本没有超过字符限制，推理却在 prefill 或生成阶段失败，常见原因是服务把字符数当成了上下文长度。模型实际消费的是 token，而 token 还包含聊天模板、角色标记和特殊符号。只统计输入框里的文字，预算从一开始就少算了一部分。上下文边界应在请求准入时确定，并在执行时再次验证。它同时涉及模型语义、运行配置和资源容量，不能用模型介绍页上的一个最大长度替代全部检查。]]></description><category></category></item><item><title><![CDATA[给本地推理引擎实现生成回调生命周期]]></title><link>https://blog.youkuaiyun.com/2301_81410839/article/details/170052923</link><guid>https://blog.youkuaiyun.com/2301_81410839/article/details/170052923</guid><author>2301_81410839</author><pubDate>Wed, 04 Nov 2026 20:56:53 +0800</pubDate><description><![CDATA[本地推理引擎通过 C 回调报告 token 或执行进度时，通常只接受函数指针和一个void*用户数据。Rust 闭包里的借用关系不会自动穿过这道 ABI。原生端保存了地址，编译器却不知道它何时再来访问；这正是回调封装最需要解释清楚的部分。设计可以从一个问题开始：注销函数返回时，是否保证所有正在执行的回调都已结束？若这个答案不明确，释放用户数据的时机就没有依据。函数指针能调用成功，只能证明连接已经建立，不能证明生命周期正确。]]></description><category></category></item><item><title><![CDATA[在 Rust 执行器实现推理实例预热]]></title><link>https://blog.youkuaiyun.com/2301_81410839/article/details/170052876</link><guid>https://blog.youkuaiyun.com/2301_81410839/article/details/170052876</guid><author>2301_81410839</author><pubDate>Wed, 04 Nov 2026 20:55:40 +0800</pubDate><description><![CDATA[模型文件加载成功，只能说明权重和一部分运行时对象已经建立。首次执行还可能触发内核选择、图编译、设备缓冲分配和页面访问。如果实例一加载完就进入负载均衡，第一批请求会替服务完成这些工作，启动成本也会混进用户延迟。预热的目的，是在受控输入和资源预算下走过关键执行路径，并检查实例能否完成一次有效推理。它无法消除所有冷路径，也不应该被当作跳过容量验证的理由。]]></description><category></category></item><item><title><![CDATA[用 Rust 写出张量形状推断最小实现]]></title><link>https://blog.youkuaiyun.com/2301_81410839/article/details/170052834</link><guid>https://blog.youkuaiyun.com/2301_81410839/article/details/170052834</guid><author>2301_81410839</author><pubDate>Wed, 04 Nov 2026 20:54:29 +0800</pubDate><description><![CDATA[形状推断常被写成几行向量拼接：拿到输入的最后两个维度，生成输出形状。这样做忽略了一个更基本的问题：输入是否满足算子契约？如果归约维不相等，正确结果是报告错误，而不是继续产生一个看起来合理的输出形状。本文实现二维矩阵乘法的保守形状推断。它支持已知和未知维度，显式保留尚未证明的约束，不覆盖广播批维、向量提升或完整的 ONNX MatMul 语义。]]></description><category></category></item><item><title><![CDATA[建立量化尺度广播的参考实现]]></title><link>https://blog.youkuaiyun.com/2301_81410839/article/details/170052788</link><guid>https://blog.youkuaiyun.com/2301_81410839/article/details/170052788</guid><author>2301_81410839</author><pubDate>Wed, 04 Nov 2026 20:53:18 +0800</pubDate><description><![CDATA[量化权重已经解包成整数，接下来只要乘尺度，看起来没有太多可写。真正的麻烦在索引：这个尺度属于整个张量、某个通道，还是某个分块？一旦选错，代码仍然能生成长度正确的浮点数组，数值却已经失去原来的含义。本文建立一个范围明确的参考实现：行主序 int8 矩阵Q[M,N]，每行一个尺度和零点，输出。它只覆盖这项自定义约定，不是完整 ONNX 算子或所有低比特模型的通用反量化器。]]></description><category></category></item><item><title><![CDATA[为本地推理服务搭建采样参数锁定]]></title><link>https://blog.youkuaiyun.com/2301_81410839/article/details/170052736</link><guid>https://blog.youkuaiyun.com/2301_81410839/article/details/170052736</guid><author>2301_81410839</author><pubDate>Wed, 04 Nov 2026 20:52:05 +0800</pubDate><description><![CDATA[一次回归出现不同回答，先检查 seed，发现没有变，就把差异归到模型头上，这条排查路径往往太短。采样受温度、候选截断、惩罚项、采样器顺序、随机数状态和停止规则共同影响；模型与运行内核也会改变进入采样器的 logits。采样参数锁定需要让每条请求拥有一份经过验证、执行期间不再变化的有效配置。它能减少不必要的变量，帮助解释差异，但不能保证不同硬件和后端逐 token 一致。]]></description><category></category></item><item><title><![CDATA[给本地推理引擎实现分词缓冲区封装]]></title><link>https://blog.youkuaiyun.com/2301_81410839/article/details/169953096</link><guid>https://blog.youkuaiyun.com/2301_81410839/article/details/169953096</guid><author>2301_81410839</author><pubDate>Tue, 03 Nov 2026 23:47:20 +0800</pubDate><description><![CDATA[分词接口看起来只是把字符串变成一串整数。真正需要封装的，是这串整数所在的内存：谁负责分配，失败后哪些位置仍可读取，下次分词能否复用，以及推理任务拿到的切片能活多久。把这些问题交给调用者，每个接入点都会重新写一遍边界判断。本文讨论同步分词接口的缓冲区设计。分词器可以来自 C 库，也可以是 Rust 实现；先把安全接口立住，再把具体 ABI 放进一个小适配层。这里不声称某个容量策略已经带来性能收益。]]></description><category></category></item><item><title><![CDATA[在 Rust 执行器实现会话上下文回收]]></title><link>https://blog.youkuaiyun.com/2301_81410839/article/details/169953056</link><guid>https://blog.youkuaiyun.com/2301_81410839/article/details/169953056</guid><author>2301_81410839</author><pubDate>Tue, 03 Nov 2026 23:46:11 +0800</pubDate><description><![CDATA[本地推理服务通常希望保留模型权重，把上下文反复借给不同请求。问题出在“归还”二字：HTTP 请求已经结束，不等于生成循环已经退出；生成循环退出，也不等于 GPU 已经不再使用那块内存。若把这些时刻合并为一次drop，下一位租用者可能读到上一轮状态，甚至和尚未结束的计算同时修改上下文。回收应是一段由执行器负责完成的协议。请求侧只能提出结束意图，负责持有原生上下文的执行单元才有权宣告它可复用。]]></description><category></category></item><item><title><![CDATA[用 Rust 写出算子融合条件最小实现]]></title><link>https://blog.youkuaiyun.com/2301_81410839/article/details/169953014</link><guid>https://blog.youkuaiyun.com/2301_81410839/article/details/169953014</guid><author>2301_81410839</author><pubDate>Tue, 03 Nov 2026 23:44:57 +0800</pubDate><description><![CDATA[计算图里出现Add → ReLU，并不意味着编译器可以直接把两个节点合成一个。中间结果可能还有别的用户，输入可能需要广播，后端也可能只支持某些布局。融合逻辑若只比较算子名字，错误会藏在那些“看起来差不多”的图中。本文限定一个可检查的小问题：在同一基本块内，把形状相同、类型相同的纯逐元素加法与 ReLU 替换为后端已经定义好的融合算子。它是合法性判断的最小起点，不是任意图融合器。]]></description><category></category></item><item><title><![CDATA[建立低比特权重解包的参考实现]]></title><link>https://blog.youkuaiyun.com/2301_81410839/article/details/169952973</link><guid>https://blog.youkuaiyun.com/2301_81410839/article/details/169952973</guid><author>2301_81410839</author><pubDate>Tue, 03 Nov 2026 23:43:45 +0800</pubDate><description><![CDATA[看到“4 bit 权重”，容易先想到把一个字节拆成两个整数。真正容易出错的地方，是拆出的整数对应哪个权重、如何解释符号、该乘哪一个尺度，以及尾部填充是否应该参与计算。把这些约定写明白，标量解包代码才有资格成为 SIMD 或 GPU 内核的参考答案。本文定义一个用于讲解的自有格式：两个有符号 int4 使用二进制补码存进一个字节，低半字节保存较早的权重，每个数据块有一个正的有限f32尺度，反量化为。它不是 GGUF、Q4_0、GPTQ 或 AWQ 的格式说明。]]></description><category></category></item></channel></rss>