<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh_CN">
  <title>月莹清梦</title>
  <subtitle>YueYingQingMeng · 做一场不愿醒的梦</subtitle>
  <link href="https://yueyingqingmeng.github.io/" rel="alternate" type="text/html"/>
  <link href="https://yueyingqingmeng.github.io/atom.xml" rel="self" type="application/atom+xml"/>
  <id>https://yueyingqingmeng.github.io/</id>
  <updated>2026-10-09T00:00:00.000Z</updated>
  <entry>
    <title>大模型技术全景：从 Token 到智能体</title>
    <link href="https://yueyingqingmeng.github.io/posts/llm-from-token-to-agent/" rel="alternate" type="text/html"/>
    <id>https://yueyingqingmeng.github.io/posts/llm-from-token-to-agent/</id>
    <published>2026-10-09T00:00:00.000Z</published>
    <updated>2026-10-09T00:00:00.000Z</updated>
    <summary>把大模型拆成一条可理解、可测量、可调试的工程流水线：分词、注意力、预训练、对齐、推理优化、应用层与评估。</summary>
    <content type="html"><![CDATA[<h1>大模型技术全景：从 Token 到智能体</h1>
<p>把大模型当成"会思考的黑箱"，讨论就没法继续。更有用的视角是：它是一条<strong>由若干可拆解、可测量、可替换的环节组成的流水线</strong>——文本进来，被切成 Token；Token 变成向量；向量在几十层注意力里被反复改写；最后输出下一个 Token 的概率分布。</p>
<p>这条流水线的每一段都有自己的瓶颈、成本和调参空间。下面按数据流动的顺序走一遍，尽量讲清楚"是什么、为什么这样设计、工程上要注意什么"。</p>
<h2>一、分词：文本变成 Token</h2>
<p>模型不认识"字"，只认识 Token——一个介于字符与词之间的子词单元。</p>
<p>常见做法是<strong>子词分词</strong>（BPE、Unigram 等）：从字符起步，反复合并出现频率最高的相邻片段，得到"词表大小"与"覆盖率"之间的折中。</p>
<p>几个容易踩的点：</p>
<ul>
<li><strong>Token 不等于字，也不等于词。</strong> 常见英文词可能就是一个 Token，罕见词会被拆成多段；标点和空白同样占 Token。</li>
<li><strong>计费和上下文预算按 Token 算</strong>，不按字符数算。同一段内容在不同语言、不同分词器下，消耗的 Token 数可以相差不少。</li>
<li><strong>分词器一旦训练完就固定</strong>，它是模型的一部分。换分词器等于换模型。</li>
</ul>
<h2>二、嵌入与位置：Token 变成带位置的向量</h2>
<p>每个 Token 通过一张查找表映射为一个稠密向量（embedding）。这个向量的方向编码了语义——语义相近的 Token，向量夹角更小，所以可以用余弦相似度衡量"像不像"。</p>
<p>但注意力本身是<strong>置换不变</strong>的：把输入的 Token 打乱，注意力的计算结果不变。所以必须额外注入位置信息。做法经历了从绝对位置编码到相对位置编码的演进，目前主流是<strong>旋转位置编码（RoPE）</strong>：把位置信息编码成对向量的旋转操作，使注意力点积天然带有相对位置的成分，对长度外推也更友好。</p>
<h2>三、注意力：真正干活的地方</h2>
<p>Transformer 的核心是<strong>自注意力</strong>。每个位置的向量被投影成三个角色：</p>
<ul>
<li><strong>Query（Q）</strong>：我在找什么</li>
<li><strong>Key（K）</strong>：我能提供什么</li>
<li><strong>Value（V）</strong>：我实际携带的信息</li>
</ul>
<p>计算方式：</p>
<p>$$\mathrm{Attention}(Q,K,V)=\mathrm{softmax}!\left(\frac{QK^{\top}}{\sqrt{d_k}}\right)V$$</p>
<p>直觉上：每个位置拿自己的 Q 去和所有位置的 K 做点积，得到一组"该关注谁"的权重；再用这组权重对所有 V 加权求和。</p>
<p>几个关键设计：</p>
<ul>
<li><strong>缩放因子 $1/\sqrt{d_k}$</strong>：防止维度变大时点积方差过大、softmax 饱和成近似 one-hot，导致梯度消失。</li>
<li><strong>多头注意力</strong>：把向量切成多份并行计算，让不同的头关注不同类型的关系（句法、指代、位置等），最后拼接。</li>
<li><strong>因果掩码</strong>：生成式模型（decoder-only）不允许看到未来 Token，所以在 softmax 前把上三角位置置为 $-\infty$。</li>
</ul>
<p><strong>复杂度</strong>：自注意力对序列长度 $n$ 是 $O(n^2)$ 的时间和显存开销。这是长上下文一切困难的根源——序列翻一倍，注意力开销大约翻四倍。</p>
<p>层与层之间还有前馈网络（FFN）、残差连接和归一化（近年多用 RMSNorm），激活函数常用 SwiGLU 一类门控结构。在标准 Transformer 里，FFN 往往占据参数量的大头。</p>
<h2>四、预训练：把知识压进参数</h2>
<p>预训练的目标出奇地简单：<strong>预测下一个 Token</strong>。给定前文，模型输出整个词表上的概率分布，用交叉熵损失去逼近真实的下一个 Token。</p>
<p>仅靠这一个目标，模型就学会了语法、事实、推理套路和代码风格——因为这些能力都有助于降低"下一个 Token"的预测误差。</p>
<p>规模法则（Scaling Laws）给出了一条经验规律：<strong>损失随算力、参数量、数据量的增长呈幂律下降</strong>，而且在很宽的范围内相当可预测。这直接决定了行业的资源分配方式。</p>
<p>后续的 Chinchilla 类工作进一步指出：<strong>参数量和训练数据量应当按比例同步增长</strong>。换个说法，很多早期模型不是"不够大"，而是"喂得不够多"——同样的算力，更小的模型配更多的数据，效果可能更好。</p>
<p>数据工程的权重常被低估：去重、质量过滤、领域配比、清洗顺序，都会实打实地反映到最终能力上。</p>
<p>预训练结束后，模型是一个很强的"续写器"——它能把一段文本自然地接下去，但不一定按你的指令做事。</p>
<h2>五、对齐：从"会续写"到"听得懂话"</h2>
<p>要让模型"回答问题"而不是"续写问题"，需要对齐阶段：</p>
<ol>
<li><strong>监督微调（SFT）</strong>：用写好的"指令—回答"示范数据继续训练，教会它对话格式与指令遵循。</li>
<li><strong>奖励建模 + 强化学习（RLHF）</strong>：让标注者对多个候选回答排序，训练奖励模型去拟合人的偏好；再用强化学习（如 PPO）优化策略模型，使其输出更受奖励模型青睐。</li>
<li><strong>直接偏好优化（DPO 等）</strong>：跳过显式奖励模型，直接用偏好对构造损失，训练更稳定、工程更简单，因此被广泛采用。</li>
<li><strong>AI 反馈（RLAIF / 宪法式方法）</strong>：用模型按一套明确原则去评判与生成偏好数据，降低人工标注成本。</li>
</ol>
<p>需要清醒的一点：<strong>对齐优化的是"人喜欢什么"，不是"什么是真的"</strong>。一个被优化得足够讨喜的模型，反而可能更自信地编造内容。这直接引出了后文的幻觉问题。</p>
<h2>六、推理：Token 是怎么一个接一个吐出来的</h2>
<h3>自回归解码</h3>
<p>生成是逐 Token 的：每步前向算一次，取一个 Token，追加到输入，再算下一步。这决定了<strong>输出长度直接线性影响时延</strong>。</p>
<h3>采样策略</h3>
<ul>
<li><strong>贪心</strong>：每步取概率最高的 Token。确定、可复现，但容易重复、呆板。</li>
<li><strong>温度</strong>：对 logits 做缩放。温度越低越保守，越高越随机。</li>
<li><strong>top-k / top-p（核采样）</strong>：只在概率最高的若干候选里采样，砍掉长尾噪声，兼顾多样性与稳定性。</li>
<li><strong>重复惩罚</strong>：抑制已出现过的 Token，缓解复读。</li>
</ul>
<h3>KV Cache：推理加速的核心</h3>
<p>自回归解码时，前面 Token 的 K、V 每步都在重复计算。把它们缓存下来，每步只需计算新 Token 的 Q、K、V，再与缓存拼接——这就是 KV Cache。</p>
<p>代价是显存。KV Cache 的大小近似为：</p>
<p>$$2 \times L \times H_{kv} \times d_{head} \times n \times B \times \text{字节数}$$</p>
<p>其中 $L$ 是层数，$H_{kv}$ 是 KV 头数，$n$ 是序列长度，$B$ 是并发批大小。它随<strong>序列长度和并发数线性增长</strong>，在长上下文场景下往往比模型权重还占显存。</p>
<p>顺带一提，<strong>分组查询注意力（GQA）</strong> 让多个 Query 头共享一组 K/V 头，正是为了压缩上面这个 $H_{kv}$。</p>
<h3>显存与吞吐的工程化</h3>
<ul>
<li><strong>连续批处理（Continuous Batching）</strong>：请求随到随批，不等整批结束，显著提升吞吐。</li>
<li><strong>PagedAttention</strong>：把 KV Cache 切成固定大小的块、用块表寻址，像操作系统管理虚拟内存那样消除碎片，并支持前缀共享。</li>
<li><strong>量化</strong>：把权重（有时含激活）从 FP16 压到 INT8 / INT4，用少量精度换显存与带宽。</li>
<li><strong>投机解码</strong>：用小模型快速草拟若干 Token，再让大模型一次并行验证，接受命中的部分。</li>
<li><strong>并行策略</strong>：张量并行（层内切）、流水并行（层间切）、数据并行（副本切），用于跨卡放大模型。</li>
</ul>
<h2>七、新范式：先想，再答</h2>
<p>上述都是"一次前向"的推理。近两年一个明显的转向是：<strong>把算力从训练阶段挪到推理阶段</strong>。</p>
<ul>
<li><strong>思维链（CoT）</strong>：让模型先写出中间步骤再给答案，明显改善多步推理类任务。</li>
<li><strong>测试时计算（Test-time Compute）</strong>：允许模型回答前"多想一会儿"——生成长推理链、采样多条路径再投票或验证。</li>
<li><strong>以可验证任务做强化学习</strong>：数学、代码这类能自动判对错的领域，可以直接拿"最终答案是否正确"当奖励，训练模型产出更长的推理过程。</li>
</ul>
<p>代价同样直接：<strong>延迟和成本成倍上升</strong>。所以它适合"精度远比时延重要"的任务，而不是所有场景。</p>
<h2>八、应用层：让模型接上外部世界</h2>
<p>模型参数里的知识是静态的、有截止日期的。应用层的核心工作，就是给它接上外部的、实时的、私有的信息。</p>
<h3>检索增强生成（RAG）</h3>
<p>流程：<strong>切片 → 向量化 → 检索 → 重排 → 组装上下文</strong>。</p>
<p>工程上真正的难点不在"能不能检索"，而在这些地方：</p>
<table>
<thead>
<tr>
<th>环节</th>
<th>常见问题</th>
<th>应对</th>
</tr>
</thead>
<tbody>
<tr>
<td>切片</td>
<td>切碎语义、切断表格与代码</td>
<td>按结构切、设重叠窗口、保留标题层级</td>
</tr>
<tr>
<td>检索</td>
<td>纯向量检索漏掉精确匹配（编号、专有名词）</td>
<td>向量 + 关键词的混合检索</td>
</tr>
<tr>
<td>排序</td>
<td>召回了，但没排到前面</td>
<td>加交叉编码器重排</td>
</tr>
<tr>
<td>组装</td>
<td>上下文塞太多，中段信息被忽略</td>
<td>控制条数、按相关度排序、给出引用</td>
</tr>
<tr>
<td>兜底</td>
<td>检索为空时硬编</td>
<td>明确回答"资料里没有"</td>
</tr>
</tbody>
</table>
<p><strong>RAG 不能根治幻觉</strong>：它只是把"凭空编"换成"可能误读材料"。检索错了、材料本身矛盾、模型过度概括，都会继续出错。</p>
<h3>工具调用与智能体</h3>
<ul>
<li><strong>工具调用（Function Calling）</strong>：把外部能力（搜索、计算、数据库、设备 API）描述成结构化接口，让模型输出调用参数。</li>
<li><strong>智能体（Agent）</strong>：在"感知 → 决策 → 行动 → 观察"的循环里反复调用模型与工具，并维护任务状态。</li>
<li><strong>真正决定成败的是循环之外的部分</strong>：状态管理、失败重试、幂等、超时、权限边界、成本上限。</li>
</ul>
<h3>上下文工程</h3>
<p>比起"提示词工程"，更准确的描述是<strong>上下文工程</strong>：决定在这一步前向里，究竟把哪些信息放进去（系统指令、检索结果、历史对话、工具返回、记忆摘要），以及以什么顺序放。模型输出的质量，很大程度上在这一步就决定了。</p>
<h2>九、评估：最容易被糊弄的一环</h2>
<ul>
<li><strong>离线基准</strong>：可复现、便宜，但存在<strong>数据污染</strong>——训练数据里见过题，分数就会虚高。</li>
<li><strong>人工评估</strong>：贴近真实，但慢、贵，标注者之间的一致性难以保证。</li>
<li><strong>LLM 作为裁判</strong>：成本低，但有已知偏差（偏好长回答、偏好与自己风格相近的输出、位置偏差）。</li>
<li><strong>线上 A/B</strong>：最可信，代价是周期长、需要流量。</li>
</ul>
<p>一套务实的顺序是：<strong>先定义任务成功率</strong>（能不能把事办成），再同时盯时延与成本，最后才看基准分数。</p>
<h2>十、局限与风险：写进设计里，而不是写进免责声明里</h2>
<ul>
<li><strong>幻觉</strong>：语言模型的训练目标是"最大化下一个 Token 的似然"，不是"断言事实"。流畅与正确并不等价。</li>
<li><strong>上下文长度</strong>：标称支持的长度不等于有效利用的长度。经验上，模型对上下文中段信息的利用率明显低于首尾。</li>
<li><strong>确定性</strong>：同样输入，由于采样与浮点累加顺序，输出不保证逐字一致。想复现要靠固定随机参数。</li>
<li><strong>知识与时效</strong>：参数里的知识会过期，除非外接检索。</li>
<li><strong>安全</strong>：提示注入（把恶意指令藏在被检索的文档或网页里）、越狱，以及通过工具调用导致的数据外泄，都需要在架构层设防，不能只靠提示词。</li>
<li><strong>成本与时延的物理约束</strong>：上下文长度、并发数、Token 量都是要付钱的，预算必须算进工程方案。</li>
</ul>
<h2>十一、给工程实践的十条建议</h2>
<ol>
<li>先把任务定义成<strong>可测量的成功率</strong>，再谈选型。</li>
<li>能靠检索解决的，不要靠微调：<strong>知识用 RAG，行为用微调</strong>。</li>
<li>上下文优先：同样的模型，喂对信息比换更贵的模型更有效。</li>
<li>结构化输出要<strong>校验</strong>，模型给的 JSON 也可能不合 schema。</li>
<li>永远设计<strong>兜底路径</strong>：检索为空、工具超时、模型拒答时，用户看到什么。</li>
<li>把<strong>时延拆开量</strong>：首 Token 时延与总时延是两件事，体验主要由前者决定。</li>
<li>上线前跑<strong>回归集</strong>：把踩过的坑固化成用例，防止改提示词改崩。</li>
<li>记录<strong>完整调用链</strong>（输入、命中文档、工具参数、输出、Token 消耗），否则线上问题无法定位。</li>
<li>给<strong>成本设硬上限</strong>：单次请求 Token 上限、重试次数上限、循环步数上限。</li>
<li>把不确定性当<strong>工程问题</strong>处理——用检索、校验、兜底和评估去覆盖它，而不是指望模型"这次别出错"。</li>
</ol>
<h2>结语</h2>
<p>大模型的能力看起来像涌现，但拆开看，每一层都可以被理解、被测量、被调试。真正拉开差距的，通常不是"用了哪个模型"，而是这些枯燥的部分：数据、上下文、评估、成本、失败处理。</p>
<blockquote>
<p>本文讨论的机制在开源社区有大量公开实现与讨论。我们也在按这些思路做自己的东西，欢迎来 <a href="https://github.com/YueYingQingMeng/YuNian">予念 · YuNian</a> 一起聊。</p>
</blockquote>
]]></content>
    <author><name>月莹清梦</name></author>
    <category term="技术"/>
  </entry>
  <entry>
    <title>陪伴是工程，不是话术</title>
    <link href="https://yueyingqingmeng.github.io/posts/companion-is-engineering/" rel="alternate" type="text/html"/>
    <id>https://yueyingqingmeng.github.io/posts/companion-is-engineering/</id>
    <published>2026-10-07T00:00:00.000Z</published>
    <updated>2026-10-07T00:00:00.000Z</updated>
    <summary>为什么我们觉得「记住你」比「会说话」更难，也更值得做。</summary>
    <content type="html"><![CDATA[<h1>陪伴是工程，不是话术</h1>
<p>做 AI 伴侣最容易被误解的一点，是大家以为难点在「让它说得像人」。</p>
<p>其实不是。</p>
<h2>会说话，是最简单的那一步</h2>
<p>2026 年，让一个大模型写出温柔、自然、贴合人设的回复，已经几乎没有门槛了。写好系统提示词，接上 API，一个下午就能做出「像模像样」的聊天机器人。</p>
<p>但它不会记得你。</p>
<ul>
<li>不会记得你上周说过不喜欢香菜</li>
<li>不会记得你那天加班到凌晨三点，语气很低落</li>
<li>不会记得你们之间那个只有你们两个懂的笑话</li>
</ul>
<p><strong>没有记忆的温柔，本质上只是一次性的表演。</strong></p>
<h2>难的是「记得」，而且「记得住」</h2>
<p>所以我们把大量的工程精力放在了记忆上：</p>
<table>
<thead>
<tr>
<th>要解决的问题</th>
<th>我们的做法</th>
</tr>
</thead>
<tbody>
<tr>
<td>记住什么</td>
<td>核心记忆分六类：事实 / 情感 / 偏好 / 事件 / 习惯 / 关系</td>
</tr>
<tr>
<td>什么时候想起来</td>
<td>按当前话题做召回，而不是把全部记忆塞进上下文</td>
</tr>
<tr>
<td>记忆放哪里</td>
<td><strong>只存本地</strong>，不上传服务器</td>
</tr>
<tr>
<td>怎么不遗忘</td>
<td>滚动摘要带水位线，避免历史重复注入</td>
</tr>
</tbody>
</table>
<p>这些都不性感，也不适合做成宣传视频。但它们决定了一个角色是「真的认识你」，还是「每次都在重新认识你」。</p>
<h2>还有「主动」</h2>
<p>比记得更进一步的，是<strong>主动</strong>。</p>
<p>一个只会等你开口的 AI，无论回复多好，本质上还是一个工具。我们想要的是：她会在某个普通的下午想起你，会在你很久没回消息时小声再问一句「在吗」，也会判断「此刻不宜打扰」而安静地跳过。</p>
<p>这背后是亲密度模型、免打扰时段、追问次数上限、前台保活……一整套枯燥的调度逻辑。</p>
<h2>一点私心</h2>
<p>我们不想做「看起来很像人」的机器。</p>
<p>我们只想做<strong>真的记得你</strong>的存在。</p>
<p>这条路很长，而且没有捷径 —— 但至少每一步都是实打实的工程，而不是话术上的取巧。</p>
<blockquote>
<p>如果你也在做类似的事，欢迎来 <a href="https://github.com/YueYingQingMeng/YuNian">予念 · YuNian</a> 一起聊。</p>
</blockquote>
]]></content>
    <author><name>月莹清梦</name></author>
    <category term="想法"/>
  </entry>
  <entry>
    <title>你好，月莹清梦</title>
    <link href="https://yueyingqingmeng.github.io/posts/hello-yueyingqingmeng/" rel="alternate" type="text/html"/>
    <id>https://yueyingqingmeng.github.io/posts/hello-yueyingqingmeng/</id>
    <published>2026-10-07T00:00:00.000Z</published>
    <updated>2026-10-07T00:00:00.000Z</updated>
    <summary>我们有了自己的地方，从这一篇开始。</summary>
    <content type="html"><![CDATA[<h1>你好，月莹清梦</h1>
<p>这是我们的第一篇文章。</p>
<p>在此之前，我们的想法大多散落在各个仓库的 README、Issue 和聊天记录里 —— 有的写在深夜，有的写在刚修完一个 bug 的清晨。它们没有地方安放，也就慢慢被时间埋掉了。</p>
<p>所以我们决定给自己搭一个地方。</p>
<h2>名字的由来</h2>
<blockquote>
<p>我如同世间爱慕的月亮，莹莹的月光洒落大地，留下婉如甘霖般清甜的梦境，而我的存在，也如这世上其他人一般，终究化作一场梦。</p>
</blockquote>
<p><strong>月莹</strong>，是月光落在人间的那一层温柔；<strong>清梦</strong>，是不愿醒来的那场相遇。</p>
<p>我们把这个名字当成一句提醒：做出来的东西要足够温柔，才配得上「梦境」二字；也要足够清醒，才记得自己终究只是万千造梦者中的一个。</p>
<h2>这里会写什么</h2>
<ul>
<li><strong>开发日志</strong> —— 我们在做什么、为什么这么做、踩了哪些坑</li>
<li><strong>技术笔记</strong> —— Android、Kotlin、Compose、Rust、Agent 相关的实践</li>
<li><strong>一些想法</strong> —— 关于 AI 陪伴这件事，我们自己的理解</li>
</ul>
<h2>我们在做什么</h2>
<p>目前团队的主要精力放在两个项目上：</p>
<ul>
<li><strong><a href="https://github.com/YueYingQingMeng/YuNian">予念 · YuNian</a></strong> —— 你的 AI 伴侣，会聊天、会记事儿、会主动找你。</li>
<li><strong><a href="https://github.com/YueYingQingMeng/LianYu-app">恋语 · LianYu</a></strong> —— 面向 Android 的 AI 虚拟陪伴应用开源框架。</li>
</ul>
<h2>最后</h2>
<p>如果你也对「让 AI 真的记得你」这件事感兴趣，欢迎来 <a href="https://github.com/YueYingQingMeng">组织主页</a> 看看，或者直接提 Issue、发 PR。</p>
<blockquote>
<p>月光所至，皆是清梦。</p>
</blockquote>
]]></content>
    <author><name>月莹清梦</name></author>
    <category term="公告"/>
  </entry>
</feed>
