From bd4aaeedcf2a330dca77b208bcd53c8c6434f1c6 Mon Sep 17 00:00:00 2001 From: CyC2018 Date: Fri, 30 Oct 2026 20:19:08 +0800 Subject: [PATCH] =?UTF-8?q?Update=20=E5=AD=A6=E4=B9=A0=E8=B7=AF=E7=BA=BF?= =?UTF-8?q?=20-=20=E5=A4=A7=E6=A8=A1=E5=9E=8B=E5=BA=94=E7=94=A8=E5=BC=80?= =?UTF-8?q?=E5=8F=91.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 补充 Transformer 结构细节与 RAG 递归切分说明,调整上下文预算、Agent 工具校验及安全防护内容,并补充接口重试等动手实验与相关文档引用。 --- notes/学习路线 - 大模型应用开发.md | 116 +++++++++++++++-------------- 1 file changed, 60 insertions(+), 56 deletions(-) diff --git a/notes/学习路线 - 大模型应用开发.md b/notes/学习路线 - 大模型应用开发.md index 432cdff2..f5b98454 100644 --- a/notes/学习路线 - 大模型应用开发.md +++ b/notes/学习路线 - 大模型应用开发.md @@ -100,14 +100,14 @@ Token 是模型处理文本的单位,也是计费和上下文长度的单位 参考要点 1. 目前的大模型基本是只保留解码器的 Decoder-only 结构;Token 经词嵌入变成向量(Qwen2.5-7B 为 3584 维),依次经过几十个相同的层(28 层),每层先用注意力从前文收集信息,再用前馈网络逐位置加工;子层都带残差连接和归一化(多为 Pre-Norm 的 RMSNorm);最后一个位置经线性层得到 logits,softmax 后得到下一个 Token 的概率。 -2. 几乎都在每层注意力和前馈网络的矩阵中;Qwen2.5-7B 的前馈网络三个矩阵(3584 → 18944 → 3584)占全部参数的 75%;GQA 使 k_proj、v_proj 只有 q_proj 的七分之一,总计约 76 亿个参数。 +2. 几乎都在矩阵中:每层的注意力和前馈网络,以及词嵌入和输出层(Qwen2.5-7B 中各约 7%);Qwen2.5-7B 的前馈网络三个矩阵(3584 → 18944 → 3584)占全部参数的 75%;GQA 使 k_proj、v_proj 只有 q_proj 的七分之一,总计约 76 亿个参数。 3. Token 是分词器切出的文本片段,模型只处理它在词表中的编号,常用字节级 BPE 反复合并最高频的相邻片段;上下文窗口和费用都按 Token 计算;中英文不同,DeepSeek 估算 1 个中文字符约 0.6 个 Token、1 个英文字符约 0.3 个,准确数量以 usage 为准。 动手:下载 Qwen2.5-7B-Instruct 的 config.json,按[参数都在哪里](大模型应用.md#2-参数都在哪里)一节的方法算出一层中注意力和前馈网络的参数量,再与[附录 A16](大模型应用.md#a16-qwen25-7b-与-qwen3-30b-a3b-的参数量)对照。 -预期:每层注意力 29,364,736 个参数、前馈网络 203,685,888 个(加归一化共 233,057,792 个),28 层加两个嵌入共 7,615,616,512 个,与附录 A16 一致。 +预期:每层注意力 29,364,736 个参数(含 q、k、v 的偏置 4,608 个)、前馈网络 203,685,888 个(加两个 RMSNorm 共 233,057,792 个),28 层、两个嵌入加最后的归一化共 7,615,616,512 个,与附录 A16 一致。 算法(哈希表,简单):[1. 两数之和](https://leetcode.cn/problems/two-sum/),题解见[数组中两个数的和为给定值](Leetcode%20题解%20-%20哈希表.md#1-数组中两个数的和为给定值)。 @@ -115,7 +115,7 @@ Token 是模型处理文本的单位,也是计费和上下文长度的单位 ### 第 2 天:注意力机制 -注意力是 Transformer 的核心,对着“饿”的例子把 Q、K、V 的计算走一遍。FlashAttention 一节说明了长上下文时计算的瓶颈在哪里。 +注意力是 Transformer 的核心,对着“饿”的例子把 Q、K、V 的计算走一遍。注意力本身不区分先后,位置编码一段看 RoPE 怎样让分数只取决于内容和相对距离。计算量与 FlashAttention 一节说明上下文变长后注意力的开销怎样增长;FlashAttention 结果不变,省的是显存读写。 阅读:《大模型应用》的[注意力机制](大模型应用.md#注意力机制)。选读:[进阶:注意力机制](大模型应用%20-%20进阶.md#注意力机制)。 @@ -144,7 +144,7 @@ Token 是模型处理文本的单位,也是计费和上下文长度的单位 ### 第 3 天:生成、KV Cache 与采样 -模型每次只生成一个 Token。KV Cache 避免重复计算前面 Token 的 K 和 V,也是推理时显存的主要来源。采样参数决定每一步怎样从概率分布中选出 Token。 +模型每次只生成一个 Token。KV Cache 避免重复计算前面 Token 的 K 和 V,代价是占用显存,它的大小决定了一张显卡能同时服务多少请求。采样参数决定每一步怎样从概率分布中选出 Token。 阅读:《大模型应用》从[自回归生成与 KV Cache](大模型应用.md#自回归生成与-kv-cache)读到[采样参数](大模型应用.md#采样参数)。选读:[进阶:自回归生成与 KV Cache](大模型应用%20-%20进阶.md#自回归生成与-kv-cache)。 @@ -158,7 +158,7 @@ Token 是模型处理文本的单位,也是计费和上下文长度的单位 参考要点 1. 因果掩码下前文 Token 的 K、V 不再变化,缓存起来复用就是 KV Cache;预填充一次算好输入的 K、V,解码每步只为新 Token 计算 Q、K、V,再与缓存做注意力,不再重算前文;代价是显存,Qwen2.5-7B 每个 Token 56 KB,32K Token 约 1.75 GB。 -2. MHA 中每个查询头都有自己的 K、V;GQA 让多个查询头共享一组 K、V,Qwen2.5-7B 的 28 个查询头共享 4 组,每个 Token 缓存 56 KB,MHA 要 392 KB;MQA 中所有查询头共享一组,缓存最小,但效果下降更明显。 +2. MHA 中每个查询头都有自己的 K、V;GQA 让多个查询头共享一组 K、V,Qwen2.5-7B 的 28 个查询头共享 4 组,每个 Token 缓存 56 KB,MHA 要 392 KB;MQA 中所有查询头共享一组,缓存最小,但效果下降更明显;GQA 减少的是缓存和解码每步读取的数据量,计算量基本不变,每个查询头仍有自己的 Q,所以效果接近 MHA。 3. temperature 把分数除以 T 再 softmax,T < 1 时分布更尖、T > 1 时更平,例如最高概率 0.50 在 T = 0.5 时升到 0.75;top-p 只在累计概率刚达到 p 的高概率 Token 中采样,候选数随分布变化;抽取字段、调用工具用低温度,写作可调高。 @@ -167,7 +167,7 @@ Token 是模型处理文本的单位,也是计费和上下文长度的单位 预期:每个 Token 2 × 28 × 4 × 128 × 2 = 56 KB,一个 32K 请求 1.75 GB,8 个请求共 14 GB,与约 14.2 GB 的权重相当。 -算法(滑动窗口,中等):[3. 无重复字符的最长子串](https://leetcode.cn/problems/longest-substring-without-repeating-characters/),题解见[剑指 Offer 48](48.%20最长不含重复字符的子字符串.md)。 +算法(滑动窗口,中等):[3. 无重复字符的最长子串](https://leetcode.cn/problems/longest-substring-without-repeating-characters/),题解见[无重复字符的最长子串](Leetcode%20题解%20-%20双指针.md#11-无重复字符的最长子串)。 明天:第 4 天,训练过程(大模型应用:训练过程)。 @@ -194,7 +194,7 @@ Token 是模型处理文本的单位,也是计费和上下文长度的单位 动手:用 Python 按[DPO](大模型应用.md#3-dpo)一节的公式,对几组给定的 chosen 和 rejected 对数概率计算 DPO 损失,观察 β 取 0.1 和 0.5 时损失的变化。 -预期:两个回答相对参考模型的变化都为 0 时损失为 log 2 ≈ 0.693;较好回答高 2、较差回答低 1 时,β = 0.1 的损失约 0.554,β = 0.5 约 0.201,β 越大损失对同样的概率差越敏感。 +预期:两个回答相对参考模型的变化都为 0 时损失为 log 2 ≈ 0.693;较好回答高 2、较差回答低 1 时,β = 0.1 的损失约 0.554,β = 0.5 约 0.201,β 越大,损失对同样的概率差越敏感:较好回答的变化大于较差回答时损失更低,小于时更高,相等时不变。 算法(链表,简单):[206. 反转链表](https://leetcode.cn/problems/reverse-linked-list/),题解见[链表反转](Leetcode%20题解%20-%20链表.md#2-链表反转)。 @@ -217,13 +217,13 @@ Token 是模型处理文本的单位,也是计费和上下文长度的单位 1. LoRA 冻结原矩阵 W,只训练小矩阵 B、A,h = Wx + (α / r)·BAx,B 初始化为 0,训练开始时与原模型相同;可训练参数很少(Qwen2.5-7B 全部线性层 r = 16 时占 0.53%),训练后合并进 W,推理无额外开销;QLoRA 再把冻结的权重量化为 4 位 NF4 存储、计算时还原为 BF16,7B 权重从 15.2 GB 降到约 4 GB。 2. 需要私有资料或经常更新的知识、要给出依据时用 RAG;要固定风格和格式、学会某种专业任务,提示词仍常出错时用微调;只是补少量规则和示例时用提示词;一般先提示词、再 RAG、最后微调,写进参数的知识难更新、无法给出来源。 -3. 模型在新数据上训练后原有能力明显下降,例如只用客服对话微调后写代码变差,模型越大越严重;缓解:混入通用指令数据,用 LoRA、较小的学习率和较少的轮数并早停,训练前后都在通用评测集上评测。 +3. 模型在新数据上训练后原有能力明显下降,例如只用客服对话微调后写代码变差,1B~7B 模型的实验中模型越大越严重;缓解:混入通用指令数据,用 LoRA、较小的学习率和较少的轮数并早停,训练前后都在通用评测集上评测。 动手:按[附录 A17](大模型应用.md#a17-sft-样本的损失掩码)的方法,用 Qwen2.5 的对话模板构造一条 SFT 样本,标出哪些 Token 参与计算损失。 -预期:只有 assistant 的回答及其后的 <|im_end|> 和换行计入损失,system 和 user 部分的标签为 -100;附录中的样本共 48 个 Token,提示部分 31 个,计入损失 17 个。 +预期:只有 assistant 的回答及其后的 <|im_end|> 和换行计入损失,system、user 消息和助手回答的开头(<|im_start|>assistant 和换行)标签为 -100;附录中的样本共 48 个 Token,提示部分 31 个,计入损失 17 个。 算法(链表,简单):[21. 合并两个有序链表](https://leetcode.cn/problems/merge-two-sorted-lists/),题解见[归并两个有序的链表](Leetcode%20题解%20-%20链表.md#3-归并两个有序的链表)。 @@ -231,7 +231,7 @@ Token 是模型处理文本的单位,也是计费和上下文长度的单位 ### 第 6 天:幻觉与推理模型 -幻觉一节按定义、原因、缓解的顺序读,Agent 中的幻觉是调用工具后出现的新问题。推理模型一节很短,说明它和普通模型的区别。 +幻觉一节按定义、原因、缓解的顺序读,Agent 中的幻觉出现在调用工具的过程中,重点看为什么要在工具结果和代码上约束,只靠提示词不够。推理模型一节很短,说明它和普通模型的区别。 阅读:《大模型应用》从[幻觉](大模型应用.md#幻觉)读到[推理模型](大模型应用.md#推理模型)。 @@ -245,14 +245,14 @@ Token 是模型处理文本的单位,也是计费和上下文长度的单位 参考要点 1. 幻觉指生成看似合理、但与事实或给定资料不符的内容,分事实性幻觉和忠实性幻觉;根本原因是训练目标是生成通顺的下一个 Token 而不是核对事实,只按答对比例打分的评测又鼓励猜测;此外还有知识缺失、采样出错后顺着错误生成、上下文过长或资料有噪声。 -2. 检测:有资料时把回答拆成结论逐条检查依据,引文和数字用代码核对;没有资料时多次采样比较,编造的内容每次不同;缓解:用 RAG 提供资料并允许回答不知道,降低温度、要求引用,用程序或另一个模型校验,展示来源、高风险结果人工确认。 +2. 检测:有资料时把回答拆成结论逐条检查依据,引文和数字用代码核对;RAG 答错时先看正确的资料是否在提示词中,区分检索和生成的问题;没有资料时多次采样比较,编造的内容往往每次不同;缓解:用 RAG 提供资料并允许回答不知道,降低温度、要求引用,用程序或另一个模型校验,展示来源、高风险结果人工确认。 3. 编造参数,例如用户没给订单号就自己编一个去查;编造或误读工具结果,例如接口超时仍说“正在运输中”、把 updated_at 当成送达时间;声称做了没做的事,例如没调用退款工具却说已退款;应对要靠工具和代码:结果字段写清楚、校验参数来源、用代码核对关键信息。 动手:阅读[附录 A19](大模型应用.md#a19-agent-中的工具幻觉),说出模型在什么情况下编造了工具结果中没有的信息,以及改写提示词和工具结果后怎样消除。 -预期:缺订单号时模型 10 次都先询问,没有编造参数;物流接口超时时,只写流程的提示词下 3/10 次编造“运输中”,加上如实告知的要求后为 0;结果中没有送达时间时多数把 updated_at 当作送达时间,改为 location_updated_at 并给出 "eta": null 后为 0。 +预期:缺订单号时模型 10 次都先询问,没有编造参数;物流接口超时时,只写流程的提示词下 3/10 次编造“运输中”,加上如实告知的要求后为 0;结果中没有送达时间时,只写流程 10 次都给出了送达时间,加上如实告知后仍有 9 次,其中 8 次把 updated_at 当成送达时间;改为 location_updated_at,附上“承运商暂未提供预计送达时间”的说明并给出 "eta": null 后,两种提示词下都为 0。 算法(链表,简单):[141. 环形链表](https://leetcode.cn/problems/linked-list-cycle/),题解见[判断链表是否存在环](Leetcode%20题解%20-%20双指针.md#6-判断链表是否存在环)。 @@ -275,7 +275,7 @@ Token 是模型处理文本的单位,也是计费和上下文长度的单位 ### 第 7 天:提示词与结构化输出 -提示词一节讲写法。结构化输出讲怎样让程序可靠地解析模型的回答:约束解码从源头保证格式,解析失败时还要修复和重试。 +提示词一节讲系统消息与用户消息的分工、提示词的写法,以及改动后怎样在评测集上比较。结构化输出讲怎样让程序可靠地解析模型的回答:约束解码从源头保证格式,不支持时靠修复和带着错误重试兜底,业务规则仍要在代码中校验。 阅读:《大模型应用》从[提示词](大模型应用.md#提示词)读到[结构化输出](大模型应用.md#结构化输出)。 @@ -288,13 +288,13 @@ Token 是模型处理文本的单位,也是计费和上下文长度的单位
参考要点 -1. 写清任务、约束、输出格式和示例,要求具体,例如“不超过 100 字”而不是“简洁一些”;说明信息不足时怎么处理,否则模型倾向编造;用少样本示例说明格式,多步推理让模型先写步骤(CoT);修改后在固定评测集上回归。 +1. 身份、规则和输出格式放在系统消息中,写清任务、约束、输出格式和示例;要求具体,例如“不超过 100 字”而不是“简洁一些”;说明信息不足时怎么处理,否则模型倾向编造;用少样本示例说明格式,多步推理让模型先写步骤(CoT);改动在评测集上比较,每条运行多次,从失败的样例入手补规则或示例。 2. 优先用约束解码:每生成一个 Token 前按 Schema 屏蔽会让输出不合法的 Token;JSON 模式只保证是合法 JSON,不保证字段;不支持时先修复(去掉代码块标记、截取首个 { 到末个 }),再用 JSON Schema 校验,失败时带着具体错误重试 1~2 次,仍失败就返回默认值或转人工。 3. 不一定,约束解码和 Schema 校验只保证格式;订单是否属于当前用户、退款是否超过实付金额这类业务规则要在代码中校验;还要检查 finish_reason 是否为 length,以及字段类型是否与代码一致。
-动手:按[附录 A22](大模型应用.md#a22-模型输出-json-的修复校验与重试)的方法,让模型从一段订单描述中抽取 JSON,用 JSON Schema 校验,失败时把错误信息发回模型重试。 +动手:按[附录 A22](大模型应用.md#a22-模型输出-json-的修复校验与重试)的方法,让模型从 10 条左右的客服消息(其中一条同时提到两个订单)中抽取订单号、意图和金额,先修复再用 JSON Schema 校验,失败时把错误信息发回模型重试。 预期:常见的失败是 JSON 包在代码块里,修复后即可解析(附录中 40 次输出直接解析成功 26 次,修复后 40 次,通过校验 38 次);一条消息含两个订单号这类超出 Schema 设计的输入,带着错误重试后仍失败,需要修改 Schema。 @@ -319,25 +319,25 @@ Token 是模型处理文本的单位,也是计费和上下文长度的单位 1. 提示词工程关注怎样写好指令,尤其是系统提示词;上下文工程决定每次调用前把哪些内容、按什么顺序放进窗口,包括规则、工具定义、检索资料、对话历史和记忆;Agent 每一步都有新的工具结果,每次调用前都要重新挑选和压缩。 2. 方法有截断(只留最近几轮,丢失早期内容)、摘要(多一次调用,可能漏掉或改写细节)、清理旧的工具结果(风险最小)和外置到文件,工具调用和结果要成对删除;常组合成“系统提示词 + 摘要 + 最近几轮原文 + 当前问题”;时机按 Token 数而不是轮数,约 70% 时在后台生成摘要,到上限时必须先压缩。 -3. 订单号、金额、地址等由代码从工具参数和结果中提取单独保存,承诺通过工具写进记录;摘要分项输出、编号和金额照原文抄写,新摘要在旧摘要的基础上合并;用关键事实覆盖和探针问题检查,实测 3B 的结构化摘要保留 9.7 条事实,普通摘要只有 4.3 条(共 14 条)。 +3. 订单号、金额、地址等由代码从工具参数和结果中提取单独保存,承诺通过工具写进记录;摘要分项输出、编号和金额照原文抄写,“已办理”只写有工具结果确认的操作,新摘要在旧摘要的基础上合并;用关键事实覆盖和探针问题检查,实测 3B 的结构化摘要保留 9.7 条事实,普通摘要只有 4.3 条(共 14 条)。 -动手:按[附录 A4](大模型应用.md#a4-普通摘要与结构化摘要)的方法,对一段 20 轮的客服对话分别做普通摘要和结构化摘要,检查订单号、金额等关键事实是否保留。 +动手:按[附录 A4](大模型应用.md#a4-普通摘要与结构化摘要)的方法,自己写一段 10 轮左右、包含订单号、金额、地址和取件时间的客服对话,分别做普通摘要和结构化摘要,检查这些关键事实是否保留。 预期:结构化摘要保留的关键事实明显多于普通摘要(附录中 Qwen2.5-3B 平均 9.7 对 4.3 条,共 14 条),但手机尾号这类只提过一次的信息仍可能丢失。 算法(栈和队列,简单):[20. 有效的括号](https://leetcode.cn/problems/valid-parentheses/),题解见[用栈实现括号匹配](Leetcode%20题解%20-%20栈和队列.md#4-用栈实现括号匹配)。 -综合题:一个客服机器人的每次请求都要带上系统提示词、工具定义、用户资料和最近的对话:怎样安排它们的顺序?Token 超出预算时先裁掉什么?(见[放什么、按什么顺序](大模型应用.md#1-放什么按什么顺序)、[Token 预算](大模型应用.md#2-token-预算)、[让前缀缓存命中](大模型应用.md#3-让前缀缓存命中)) +综合题:一个客服机器人的每次请求都要带上系统提示词、工具定义、用户资料和最近的对话:怎样安排它们的顺序?Token 超出预算时先裁掉什么?(见[放什么、按什么顺序](大模型应用.md#1-放什么按什么顺序)、[Token 预算](大模型应用.md#2-token-预算)、[压缩的方法与时机](大模型应用.md#3-压缩的方法与时机)、[让前缀缓存命中](大模型应用.md#3-让前缀缓存命中))
答题思路 -1. 不变的内容放最前:系统提示词、工具定义按固定顺序在开头,保证前缀缓存命中,当前时间、用户名不要插在开头。 -2. 变化的内容放后面:用户资料、对话摘要、最近几轮原文、当前问题依次追加,历史原样追加不重新拼接;重要规则放在开头或结尾,避免 Lost in the Middle。 +1. 不变的内容放最前:系统提示词、工具定义按固定顺序在开头,让每次请求的前缀相同,提高前缀缓存的命中率,当前时间、用户名不要插在开头。 +2. 其后按变化频率放:用户资料在会话内不变时紧跟工具定义,再依次追加对话摘要、最近几轮原文和当前问题,历史原样追加不重新拼接;重要规则放在开头或结尾,避免 Lost in the Middle。 3. 先算预算:历史可用 = 窗口 − 预留输出 − 固定部分 − 检索资料上限 − 当前问题,例如 32K 窗口、预留 2K 输出、检索 4K 时历史约 25K。 -4. 超出时先清理旧的工具结果,再把较早的对话并入摘要,保留最近几轮原文,工具调用和结果成对删除;系统规则和当前问题不裁。 +4. 超出时先清理旧的工具结果,再把较早的对话并入摘要,保留最近几轮原文,工具调用和结果成对删除;最近几轮中某条工具结果或粘贴的文档过大时先外置,只留相关片段,仍放不下再减少保留的轮数;系统规则、任务状态和当前问题不裁。 5. 工具定义占比大时按需加载工具(例子中 6 个工具占 701 个 Token),但动态增减工具和频繁压缩都会破坏前缀缓存,要权衡。
@@ -348,7 +348,7 @@ Token 是模型处理文本的单位,也是计费和上下文长度的单位 ### 第 9 天:RAG 的流程、文档解析与切片 -先看 RAG 的完整流程,再看前两步:文档解析和切片。切片的对比实验说明了不同切法对召回率的影响。 +先看 RAG 的完整流程,再看前两步:文档解析和切片。切片一节细读递归切分和对比实验,后者说明了不同切法对召回率的影响。 阅读:《大模型应用》从[RAG 的流程](大模型应用.md#流程)读到[RAG 的切片](大模型应用.md#切片)。 @@ -361,15 +361,15 @@ Token 是模型处理文本的单位,也是计费和上下文长度的单位
参考要点 -1. 离线:解析文档、切片,用 Embedding 模型转为向量存入向量数据库,同时建立关键词索引;在线:改写问题,向量和关键词两路召回,合并后重排,把最相关的几段和问题放进提示词,生成带引用的回答;文档更新时只重建内容哈希变化的文档,并删除旧切片。 -2. 按标题、段落等结构切,表格和代码块保持完整,相邻切片保留重叠,切片带上标题路径;也可以用小切片检索、返回所在的完整段落(父子切片);大小没有通用最优值,以 Embedding 模型的最大长度为上限,事实类问题用小切片,最后在评测集上比较召回率。 -3. PDF 只记录“在某坐标画某字”,没有段落和表格,直接读文本层会混入页眉页脚、句子在折行处断开;扫描件要先 OCR,表格可能被逐列输出;用版面分析识别标题、正文、表格和阅读顺序,表格转为 Markdown,按行切分时每行带上表头。 +1. 离线:解析文档、切片,用 Embedding 模型转为向量存入向量数据库,同时建立关键词索引;在线:改写问题,向量和关键词两路召回,合并后重排,把最相关的几段和问题放进提示词,生成带引用的回答;提示词中给切片编号,要求每个结论标注来源,资料中没有答案时如实回答没找到。 +2. 按标题、段落等结构切,表格和代码块保持完整,相邻切片保留重叠,切片带上标题路径;一节超过上限时递归切分,按空行、换行、句号、逗号由粗到细尝试,LangChain 默认的分隔符没有中文标点,要补上;没有标题的长文本可以语义切分,在相邻两句相似度明显下降处切开;也可以用小切片检索、返回所在的完整段落(父子切片);大小没有通用最优值,以 Embedding 模型的最大长度为上限,事实类问题用小切片,最后在评测集上比较召回率。 +3. PDF 只记录“在某坐标画某字”,没有段落和表格,直接读文本层会混入页眉页脚、句子在折行处断开;扫描件要先 OCR,表格可能被逐列输出;用版面分析识别标题、正文、表格和阅读顺序,表格转为 Markdown,按行切分时每行带上表头;跨页的表格在列数、列宽一致且中间没有新标题时拼成一张,去掉重复的表头。
-动手:用 pypdf 提取一份 PDF 的文本,分别按固定长度和按段落切片,比较两种切片的边界是否切断了句子。 +动手:用 pypdf 提取一份 PDF 的文本,看页眉页脚是否混入正文、句子是否在折行处断开;再参照[附录 A12](大模型应用.md#a12-切片方式top-k-与相似度阈值),把一份中文 Markdown 文档分别按固定 200 字和递归切分(200 字,分隔符补上中文标点)切片,数一数各有多少切片在句子中间断开。 -预期:固定长度切片的边界常落在句子中间,按段落切的边界都在段落结尾、句子完整,但各片段长度不均。 +预期:PDF 的文本层常混入页眉页脚,句子在折行处断开;附录的语料中,固定 200 字有 88% 的切片在句子中间断开,补上中文标点的递归切分为 0%;换一份文档数字会不同,递归切分仍断在句中的,多是句子中间有换行或单句超过上限。 算法(二分查找,中等):[33. 搜索旋转排序数组](https://leetcode.cn/problems/search-in-rotated-sorted-array/)。 @@ -391,7 +391,7 @@ Embedding 把文本变成向量,相似度检索靠它完成。向量索引回 参考要点 1. 分词后输入 Transformer 编码器,每个 Token 得到一个向量,再池化(取 [CLS] 或平均值,与训练时一致)成固定长度的向量并归一化;对比学习使意思相近的文本向量靠近;余弦相似度看方向是否接近,归一化后等于点积、计算更快,排序与欧氏距离等价。 -2. 把向量组织成多层图,每个向量连接附近的若干向量,层越高向量越少、连线跨度越大,最下层包含全部向量;查询从最上层的入口开始,每层贪心走向更近的节点,走不动就下降一层,思路类似跳跃表;M、efConstruction、efSearch 在速度、内存和召回率之间权衡。 +2. 把向量组织成多层图,每个向量连接附近的若干向量,层越高向量越少、连线跨度越大,最下层包含全部向量;查询从最上层的入口开始,上面各层只保留一个最近节点,贪心地走向查询,走不动就下降一层,最下层保留 efSearch 个候选扩展邻居,从中取前 K 个,思路类似跳跃表;上层的长连线让查询几步就到目标附近,12.4 万个向量上每次只算约 1300 次距离(暴力检索的 1.1%);过滤掉大部分向量、大量删除和内存放不下时会变差;M、efConstruction、efSearch 在速度、内存和召回率之间权衡。 3. 逐个比较时,100 万个 1024 维向量每次查询约 10 亿次乘加,数据量和并发大时太慢;ANN 索引用少量精度换速度,可能漏掉个别真正最近的向量。 @@ -419,9 +419,9 @@ Embedding 把文本变成向量,相似度检索靠它完成。向量索引回
参考要点 -1. 向量检索擅长匹配措辞不同的近义内容,但精确匹配不准,E1024 和 E1025 文档的相似度 0.762 与 0.743 几乎分不开;BM25 按词频、逆文档频率和文档长度打分,罕见词 E1024 权重高,两篇得分 1.088 与 0.130;两路同时召回,分数尺度不同,用 RRF 按排名融合。 -2. Embedding 模型分别编码问题和文档,文档向量能提前算好,速度快,但细节的对应关系在压成一个向量时丢失;重排模型(交叉编码器)把问题和文档拼在一起编码,每个词之间都能算注意力,更准,但每一对都要重算;所以先快速召回几十条,再重排选出几条。 -3. HNSW 删除一般只做标记、检索时跳过,之后统一清理,更新等于删除加插入;Milvus 的删除在位图中标记,Compaction 时才真正去掉,所以更新要批量进行;文档修改后按文档 ID 删除全部旧切片再写新切片,按切片 ID 幂等写入,并与关系数据库定期对账。 +1. 向量检索擅长匹配措辞不同的近义内容,但精确匹配不准,E1024 和 E1025 文档的相似度 0.762 与 0.743 几乎分不开;BM25 按词频、逆文档频率和文档长度打分,罕见词 E1024 权重高,两篇得分 1.088 与 0.130;两路同时召回,分数尺度不同,用 RRF 按排名融合;混合不一定比单路好,口语化问题上等权 RRF 的 Recall@3(0.950)低于单独的向量检索(0.975),BM25 的权重要在评测集上确定。 +2. Embedding 模型分别编码问题和文档,文档向量能提前算好,速度快,但细节的对应关系在压成一个向量时丢失;重排模型(交叉编码器)把问题和文档拼在一起编码,每个词之间都能算注意力,更准,但每一对都要重算;所以先快速召回几十条,再重排选出几条;混入 12.5 万条干扰文本时,重排 RRF 的前 50 个候选使 Recall@1 从 0.275 升到 0.700。 +3. HNSW 删除一般只做标记、检索时跳过,之后统一清理,更新等于删除加插入;Milvus 的删除在位图中标记,Compaction 时才真正去掉,所以更新要批量进行;文档修改后按文档 ID 和内容哈希找出变化的文档,删除它的全部旧切片再写新切片,只改权限或版本状态时只更新元数据;按切片 ID 幂等写入,并与关系数据库定期对账;更换 Embedding 模型或切片方式时,在新集合中重建索引并评测,再把别名切过去,查询用的模型同时切换。
@@ -435,7 +435,7 @@ Embedding 把文本变成向量,相似度检索靠它完成。向量索引回 ### 第 12 天:Top-K 与查询改写 -注意区分召回的 K 和放进提示词的 K。查询改写处理用户的提问与文档措辞不一致的情况。 +注意区分召回的 K 和放进提示词的 K。查询改写处理原始问题不适合直接检索的情况,例如省略了上文的追问和只有几个字的问题。 阅读:《大模型应用》从[Top-K 与阈值](大模型应用.md#top-k-与阈值)读到[查询改写](大模型应用.md#查询改写)。 @@ -477,15 +477,15 @@ Embedding 把文本变成向量,相似度检索靠它完成。向量索引回
参考要点 -1. 检索看 Recall@K(相关切片有多少在前 K 个中)、MRR(第一个相关结果排名倒数的平均)和 NDCG(分级相关、按排名打折);生成看忠实度(结论能否在资料中找到依据)和答案相关性(是否回应了问题),通常由模型裁判拆成小步骤打分,两者要一起看。 +1. 检索看 Recall@K(相关切片有多少在前 K 个中)、Precision@K(前 K 个中相关的比例)、MRR(第一个相关结果排名倒数的平均)和 NDCG(分级相关、按排名打折),K 增大时召回率不降、精确率往往下降,放进提示词的切片还要看精确率和端到端正确率;生成看忠实度(结论能否在资料中找到依据)和答案相关性(是否回应了问题),通常由模型裁判拆成小步骤打分,两者要一起看。 2. 按数据流动的顺序从前往后查:解析、切片、检索、重排、生成,前面的错误后面无法弥补;每步分别看解析结果与原文是否一致、答案是否完整在一个切片中、相关切片在两路检索和重排前后的排名、直接给正确资料能否答对;也可以先做最后一步,区分问题在检索还是生成。 -3. 优先从真实用户问题中抽样,不够时用模型生成再人工改写措辞,避免照抄原文高估向量检索;包含没有答案、需要多个切片和新旧版本冲突的问题;标注标准答案和所需的原文片段而不是切片 ID,线上的错误回答持续补充进来。 +3. 优先从真实用户问题中抽样,不够时用模型生成再人工改写措辞,避免照抄原文高估向量检索;包含没有答案、需要多个切片和新旧版本冲突的问题,没有答案的问题回答不知道算对、编出答案算错;标注标准答案和所需的原文片段而不是切片 ID,线上的错误回答持续补充进来。
动手:为 10 个问题标注相关的文档,用自己的检索结果计算 Recall@5 和 MRR,对照[检索指标](大模型应用.md#1-检索指标)一节核对公式。 -预期:Recall@5 为相关文档出现在前 5 个结果中的问题比例,MRR 为第一个相关结果排名倒数的平均;用笔记的例子(排名 1、3、未出现)核对,应得到 Recall@5 = 2/3、MRR = 0.44。 +预期:Recall@5 为每个问题前 5 个结果中的相关文档数除以它的相关文档总数,再对问题取平均(每题只有一个相关文档时就是找到的问题所占的比例),MRR 为第一个相关结果排名倒数的平均;用笔记的例子(3 个问题各 1 个相关切片,排名 1、3、未出现)核对,应得到 Recall@5 = 2/3、MRR = 0.44。 算法(二叉树,中等):[236. 二叉树的最近公共祖先](https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree/),题解见[二叉树的最近公共祖先](Leetcode%20题解%20-%20树.md#5-二叉树的最近公共祖先)。 @@ -522,8 +522,8 @@ Embedding 把文本变成向量,相似度检索靠它完成。向量索引回 参考要点 1. 模型负责理解任务、决定下一步;工具用于获取信息和执行操作,记忆保存对话历史和用户偏好,规划把复杂任务拆成步骤;控制循环是应用代码中反复调用模型、执行工具的循环,并负责限制步数、校验参数和权限;模型只输出文本,执行都由应用完成。 -2. 应用在请求中附上工具的名称、用途和参数 JSON Schema,推理服务按对话模板拼进提示词;模型需要时生成特定格式的文本(如 中的 JSON),服务解析成 tool_calls 返回;应用校验后执行,用 tool 消息和 tool_call_id 发回结果;本质仍是生成文本,必须先校验再执行。 -3. 工作流的步骤和顺序由代码事先写好,模型只做其中某些步骤,可预测、成本可控,适合步骤固定的业务;Agent 由模型决定下一步,适合无法事先确定步骤的开放任务,但成本高、错误会累积(每步 95% 时连续 10 步约 60%);实际常把两者组合,退款这类固定流程走工作流,商品咨询交给 Agent。 +2. 应用在请求中附上工具的名称、用途和参数 JSON Schema,推理服务按对话模板拼进提示词;模型需要时生成特定格式的文本(如 Qwen2.5 包在 tool_call 标签里的 JSON),服务解析成 tool_calls 返回;应用校验后执行,用 tool 消息和 tool_call_id 发回结果;本质仍是生成文本,模型可能调用不存在的工具、写错参数或编造订单号,严格模式只保证参数符合 Schema,所以必须先校验再执行。 +3. 工作流的步骤和顺序由代码事先写好,模型只做其中某些步骤,可预测、成本可控,适合步骤固定的业务;Agent 由模型决定下一步,适合无法事先确定步骤的开放任务,但成本高、错误会累积(每步 95% 时连续 10 步约 60%),所以先尝试单次调用或工作流;判断看步骤和步骤之间的转移规则能否事先写清,写不全才交给 Agent;实际常把两者组合,退款这类固定流程走工作流,商品咨询交给 Agent。 @@ -543,7 +543,7 @@ Embedding 把文本变成向量,相似度检索靠它完成。向量索引回 自测: -1. ReAct 是什么?为什么用它?(见[ReAct](大模型应用.md#2-react)) +1. ReAct 是什么?为什么用它?(见[思维链](大模型应用.md#1-思维链)、[ReAct](大模型应用.md#2-react)) 2. 先规划后执行(Plan-and-Execute)和 ReAct 有什么区别?(见[先规划后执行](大模型应用.md#3-先规划后执行)) 3. 怎样保证意图识别和路由准确?(见[怎样保证路由准确](大模型应用.md#2-怎样保证路由准确)) @@ -552,7 +552,7 @@ Embedding 把文本变成向量,相似度检索靠它完成。向量索引回 1. ReAct 让推理和行动交替:先思考,再调用工具,把真实结果作为观察放回上下文再思考;与思维链相比,事实来自外部而不是模型的记忆,HotpotQA 的分析中思维链失败案例 56% 是编造事实,ReAct 为 0%;适合下一步取决于上一步结果、步数不多的任务,缺点是只能串行、长任务容易偏离目标。 2. 先规划后执行先一次生成带依赖的步骤列表,按依赖执行、无依赖的步骤并行,失败或结果不符时重规划(次数设上限),进度容易展示和恢复,但计划可能与实际不符;ReAct 每步根据中间结果调整,但每步都要调用一次模型,长任务容易偏离;实际常结合使用,每个步骤内部用 ReAct。 -3. 类别定义互斥并写明边界,输出限制为枚举值,不在列表中的按“其它”处理;分层:规则只处理“转人工”、带订单号这类精确率高的情况,其余交给模型;置信度低时反问澄清或转人工,多轮对话结合最近几轮;用评测集和混淆矩阵衡量,修改后回归。 +3. 类别定义互斥并写明边界,输出限制为枚举值,不在列表中的按“其它”处理;分层:规则只处理“转人工”、带订单号这类精确率高的情况,其余交给模型;置信度低时反问澄清或转人工,阈值在验证集上扫一遍再定,分错代价高的类别(如退款)单独设更高的阈值;多轮对话结合最近几轮;用评测集按类别看精确率、召回率和混淆矩阵,修改后回归。 @@ -566,7 +566,7 @@ Embedding 把文本变成向量,相似度检索靠它完成。向量索引回 ### 第 16 天:记忆与多轮对话 -短期记忆就是放进上下文的对话历史,长期记忆要解决写什么、怎样检索和怎样更新。多轮对话一节处理指代、追问和话题切换。 +先分清两件事:记忆是应用存下来的数据,上下文是某一次调用实际带上的内容。短期记忆管当前会话的消息、摘要和任务状态,长期记忆要解决写什么、怎样检索和怎样更新。多轮对话一节处理指代、追问和话题切换。 阅读:《大模型应用》从[Agent 的记忆](大模型应用.md#记忆)读到[多轮对话](大模型应用.md#多轮对话)。 @@ -585,7 +585,7 @@ Embedding 把文本变成向量,相似度检索靠它完成。向量索引回 -动手:按[附录 A5](大模型应用.md#a5-长期记忆的提取与更新)的方法,让模型从对话中提取用户偏好写入长期记忆,用户改口后再更新这条记忆。 +动手:按[附录 A5](大模型应用.md#a5-长期记忆的提取与更新)的方法,让模型从对话中提取收货地址这类长期有效的用户信息写入长期记忆,用户换了地址后再更新这条记忆。 预期:提取出新地址后,模型对已有的地址记忆选择 UPDATE 而不是重复新增(附录中 m1 更新为江南大道 588 号),订单、物流这类信息不被提取;记忆中的日期由代码填写,不采用模型写的日期。 @@ -612,9 +612,9 @@ MCP 规定应用怎样接入外部的工具和数据,Skills 规定怎样按需 -动手:按[附录 A24](大模型应用.md#a24-mcp-服务端的最小实现)写一个提供 query_order 工具的 MCP 服务端并调用它;再写一个 SKILL.md,描述“按模板写周报”的步骤。 +动手:按[附录 A24](大模型应用.md#a24-mcp-服务端的最小实现)写一个提供 get_order 工具的 MCP 服务端并调用它;再写一个 SKILL.md,描述“按模板写周报”的步骤。 -预期:tools/list 返回 query_order 的名称、描述和由类型注解生成的参数 Schema;查询 1024 返回模拟的物流信息、isError 为 false,查询不存在的订单返回错误信息、isError 为 true;SKILL.md 开头有 name(小写字母、数字、连字符)和写清做什么、何时使用的 description。 +预期:tools/list 返回 get_order 的名称、描述和由类型注解生成的参数 Schema;查询 1024 返回订单状态和运单号、isError 为 false,查询不存在的订单返回错误信息、isError 为 true;SKILL.md 开头有 name(小写字母、数字、连字符)和写清做什么、何时使用的 description。 算法(动态规划,简单):[70. 爬楼梯](https://leetcode.cn/problems/climbing-stairs/),题解见[爬楼梯](Leetcode%20题解%20-%20动态规划.md#1-爬楼梯)。 @@ -622,20 +622,20 @@ MCP 规定应用怎样接入外部的工具和数据,Skills 规定怎样按需 ### 第 18 天:多 Agent 与 Harness -多 Agent 一节说明什么时候值得拆成多个 Agent。AI 编程助手和 Harness 讲的是怎样让 Agent 可靠地完成长任务。 +多 Agent 一节说明什么时候值得拆成多个 Agent,以及几种协作方式的区别。AI 编程助手一节以 Claude Code 为例讲编程 Agent 怎样工作、怎样用好;Harness 一节讲模型之外的代码怎样通过引导、反馈和交接,让 Agent 可靠地完成长任务。 阅读:《大模型应用》从[多 Agent](大模型应用.md#多-agent)读到[Harness](大模型应用.md#harness)。 自测: -1. 什么时候需要多个 Agent?有哪些协作方式?(见[为什么要多个 Agent](大模型应用.md#1-为什么要多个-agent)、[协作方式](大模型应用.md#2-协作方式)) +1. 什么时候需要多个 Agent?有哪些协作方式?(见[为什么要多个 Agent](大模型应用.md#1-为什么要多个-agent)、[协作方式](大模型应用.md#2-协作方式)、[适用场景](大模型应用.md#3-适用场景)) 2. 什么是 Agent Harness?由哪些部分组成?(见[Harness](大模型应用.md#harness)) 3. 长任务怎样在多次会话之间交接?(见[长任务的交接](大模型应用.md#3-长任务的交接))
参考要点 -1. 子任务互相独立、需要读大量资料或反复试错时值得拆,好处是隔离上下文,子 Agent 只返回精简的结论;代价是 Token 约为普通对话的 15 倍,只传摘要会丢失细节;协作方式有主管分派(子 Agent 包装成工具、可并行)、流水线(固定顺序)和讨论(互看答案后投票或裁决)。 +1. 子任务互相独立、需要读大量资料或反复试错时值得拆,需要隔离权限时也可以拆,好处是隔离上下文,子 Agent 只返回精简的结论;代价是 Token 消耗成倍增加(Anthropic 的数据中多 Agent 系统约为普通对话的 15 倍),只传摘要会丢失细节;依赖紧密的任务和对延迟、成本敏感的在线请求用单个 Agent;协作方式有主管分派(子 Agent 包装成工具、可并行)、流水线(固定顺序)、讨论(互看答案后投票或裁决)和转交(把控制权和上下文交给另一个 Agent,由它直接回复用户,处理完不自动返回)。 2. Harness 指模型之外的所有代码、配置和执行逻辑;组成包括 Agent 循环与停止条件、上下文组装与压缩、工具与权限、记忆与状态交接、子 Agent、钩子与校验、评测与可观测,MCP 和 Skill 也属于它;核心是动手前的引导(规范、文档、Skill)和动手后的反馈(编译、测试、lint、模型审查)。 3. 第一次会话只做准备:把需求拆成带测试步骤和 passes 字段的 JSON 功能清单,写好启动脚本并提交到 git;之后每次会话先读进度文件和 git log、做冒烟测试,只实现一个未通过的功能,端到端测试通过才把 passes 改为 true,再提交并更新进度;只允许修改 passes,防止 Agent 删掉测试来“完成”任务。 @@ -665,7 +665,7 @@ MCP 规定应用怎样接入外部的工具和数据,Skills 规定怎样按需 参考要点 1. LangChain 提供模型、工具、检索器等组件和现成的 Agent,早期核心是按固定顺序串起来的链;LangGraph 是更底层的编排运行时,用共享状态、节点和条件边组成状态图,LangChain 1.0 的 create_agent 就运行在它之上;Agent 和业务流程需要循环、分支、暂停等人工确认和从中间恢复,用链表达很别扭,图加 checkpoint 可以直接表达。 -2. 执行前先按 Schema 校验参数,再做业务校验;超时、限流、5xx 由代码按指数退避重试 2~3 次,不交给模型(实测把超时回传给 7B 模型,10 次都没有重新调用);参数错误把错在哪、正确格式是什么回传给模型修正;仍失败就如实告知或转人工,同时限制步数、检测重复调用,有副作用的操作要幂等、人工确认。 +2. 执行前先按 Schema 校验参数,再做业务校验;超时、限流、5xx 由代码按指数退避重试 2~3 次,不交给模型(实测把超时回传给 7B 模型,10 次都没有重新调用),接口持续失败时熔断;参数错误把错在哪、正确格式是什么回传给模型修正;仍失败就如实回传,由模型换办法或告知用户、转人工,不能编造结果;同时限制步数和预算、检测有没有进展(比较工具名、参数和结果,而不只数调用次数),有副作用的操作要幂等,只对涉及资金、无法撤销或对外可见的操作人工确认(确认太频繁,人会不看内容就点同意)。 3. 主要检查结果(例如数据库中是否真有一条退款记录),轨迹只检查必须满足的约束,优先用代码检查,开放内容才用模型裁判;指标有任务成功率、工具调用正确率和效率,用 pass^k 衡量稳定性;裁判有位置偏差、长度偏差和自我偏好,缓解靠交换顺序评两次、给出参考、拆成逐项判断的问题、与人工标注核对一致率。
@@ -695,7 +695,7 @@ MCP 规定应用怎样接入外部的工具和数据,Skills 规定怎样按需 ### 第 20 天:流式输出、成本与部署 -流式输出决定用户多快看到第一个字。延迟与成本一节估算了一次 Agent 任务的费用;推理服务部署讲批处理、PagedAttention 和前缀缓存怎样提高吞吐。 +流式输出决定用户多快看到第一个字。延迟与成本一节估算了一次 Agent 任务的费用;推理服务部署讲批处理和 PagedAttention 怎样提高吞吐、前缀缓存怎样省掉重复的预填充,投机解码和张量并行可以略读。 阅读:《大模型应用》从[流式输出](大模型应用.md#流式输出)读到[推理服务部署](大模型应用.md#推理服务部署)。 @@ -709,14 +709,14 @@ MCP 规定应用怎样接入外部的工具和数据,Skills 规定怎样按需 参考要点 1. 接口用 SSE:响应类型为 text/event-stream,连接保持打开,每生成一段内容写一条事件;事件由若干行“字段: 值”组成、以空行结束,data 是内容、id 是编号、event 是类型,冒号开头的行是注释(常作心跳);OpenAI 兼容接口以 data: [DONE] 结束,断线后 EventSource 带着 Last-Event-ID 重连。 -2. 让前缀缓存命中:不变的系统提示词和工具定义放最前、工具顺序固定、历史原样追加,例子中费用从 0.296 元降到 0.053 元;工具先返回片段,需要时再读全文;设置 max_tokens,输出单价是未命中缓存输入的 4 倍;简单问题交给小模型,及时压缩历史、避免重复调用。 -3. 早期系统按最大长度为每个请求预留连续的显存,真正存放 KV Cache 的只有 20.4%~38.2%;PagedAttention 借鉴操作系统的分页,把 KV Cache 切成固定大小的块(vLLM 默认 16 个 Token)按需分配,用块表记录位置,只浪费最后一块的空余;同样 7 GB 显存可服务的请求从 16 个增至 64 个,吞吐是 FasterTransformer、Orca 的 2~4 倍。 +2. 前缀缓存降低的是单价:不变的系统提示词和工具定义放最前、工具顺序固定、历史原样追加;减少 Token 的数量:工具先返回摘要或片段,需要时再读全文;设置 max_tokens,输出单价是未命中缓存输入的 4 倍;简单问题交给小模型;历史过长时压缩,但压缩会改变前缀,不宜过于频繁;避免模型反复调用同一个工具。 +3. 早期系统按最大长度为每个请求预留连续的显存,真正存放 KV Cache 的只有 20.4%~38.2%;PagedAttention 借鉴操作系统的分页,把 KV Cache 切成固定大小的块(vLLM 默认 16 个 Token)按需分配,用块表记录位置,只浪费最后一块的空余;同样 7 GB 显存按 8K 预留只能服务 16 个请求,请求平均只用到 2K Token 时按块分配可服务 64 个;延迟相近时吞吐是 FasterTransformer、Orca 的 2~4 倍。 -动手:用 curl -N 调用模型服务的流式接口,观察 data: 行的格式和最后的 [DONE],再用代码逐行读取并拼接出完整回答。 +动手:用 curl -N 调用模型服务的对话接口(请求体中设置 `"stream": true`),观察 data: 行的格式和最后的 [DONE],再用代码逐行读取并拼接出完整回答。 -预期:终端中陆续出现以 data: 开头、以空行分隔的事件,每条 JSON 中带一小段增量文字,最后一条是 data: [DONE];代码跳过空行和注释、读到 [DONE] 停止,按顺序拼接各段得到完整回答。 +预期:终端中陆续出现以 data: 开头、以空行分隔的事件,文字增量在 JSON 的 choices[0].delta.content 中,第一条(只有角色)和带 finish_reason 的最后一条可能没有文字,最后是 data: [DONE];代码跳过空行和注释,只拼接非空的 content,读到 [DONE] 停止,得到完整回答。 算法(动态规划,中等):[300. 最长递增子序列](https://leetcode.cn/problems/longest-increasing-subsequence/),题解见[最长递增子序列](Leetcode%20题解%20-%20动态规划.md#1-最长递增子序列)。 @@ -724,7 +724,7 @@ MCP 规定应用怎样接入外部的工具和数据,Skills 规定怎样按需 ### 第 21 天:稳定性与安全 -稳定性一节把超时、重试、限流和熔断用到模型调用上,做法与后端服务一致。安全一节的重点是限制模型能造成的后果。 +稳定性一节把超时、重试、限流、降级和熔断用到模型调用上,重点是模型调用与普通接口的不同:生成慢,超时要按输出长度估算,流式输出还可能中途断开。安全一节先解释为什么靠提示词挡不住注入,再讲怎样限制模型被诱导后能造成的后果。 阅读:《大模型应用》从[稳定性](大模型应用.md#稳定性)读到[大模型应用的安全](大模型应用.md#安全)。 @@ -732,20 +732,24 @@ MCP 规定应用怎样接入外部的工具和数据,Skills 规定怎样按需 1. 调用模型接口时怎样设置超时和重试?(见[超时](大模型应用.md#1-超时)、[重试与指数退避](大模型应用.md#2-重试与指数退避)) 2. 流式输出中途断开怎么办?(见[流式输出中途断开](大模型应用.md#4-流式输出中途断开)) -3. 怎样防御提示词注入?(见[大模型应用的安全](大模型应用.md#安全)) +3. 怎样防御提示词注入?(见[限制模型能造成的后果](大模型应用.md#2-限制模型能造成的后果))
参考要点 1. 非流式请求的总超时要大于 TTFT + 最大输出 Token 数 × TPOT,例如 1000 个 Token、30 毫秒时要 30 多秒;流式请求分别设首 Token 超时、间隔超时和总时长上限,心跳不算内容;429、5xx、超时可以重试,400、401 直接失败,按指数退避加随机抖动、遵守 Retry-After,次数设上限且只在一层重试。 2. 还没输出任何内容时直接重试,用户感知不到;已输出部分文字时,把已输出的部分作为 assistant 消息的开头请求续写(如 DeepSeek 的对话前缀续写),不支持就丢弃重新生成并通知前端清空;工具调用的参数只输出了一半时不能执行,丢弃后重新请求。 -3. 提示词注入指通过输入的内容改变模型原本的指令,指令也可能藏在网页、文档或工具结果中(间接注入);模型无法可靠区分指令和数据,提示词只能降低风险,重点是限制后果;外部内容标注为不可信,工具按最小权限提供、在代码中按当前用户校验,高风险操作人工确认;输出转义、查询参数化,提示词中不放密钥,记录审计日志。 +3. 提示词注入指通过输入的内容改变模型原本的指令,指令也可能藏在网页、文档或工具结果中(间接注入);指令和资料最终拼成同一个 Token 序列,模型无法可靠区分,提示词只能降低风险,重点是限制后果;外部内容标注为不可信,工具按最小权限提供、在代码中按当前用户校验,高风险操作人工确认;读过不可信内容的任务不给对外发送的工具,前端不自动加载输出中的外部图片,防止数据外泄;输出转义、查询参数化,提示词中不放密钥,记录审计日志。
+动手:参照[重试与指数退避](大模型应用.md#2-重试与指数退避)一节的代码,用 Python 写一个最多尝试 3 次的重试函数,用模拟接口测试:前两次返回 429、第三次返回结果时,打印每次等待的时间;再让模拟接口返回 400,确认没有重试。 + +预期:两次 429 后分别等待 0.25~0.5 秒和 0.5~1 秒(基准间隔 0.5 秒、1 秒,随机抖动取它的 0.5~1 倍),第 3 次拿到结果;返回 400 时只调用 1 次就抛出异常。 + 算法(链表,困难):[25. K 个一组翻转链表](https://leetcode.cn/problems/reverse-nodes-in-k-group/),题解见[K 个一组翻转链表](Leetcode%20题解%20-%20链表.md#11-k-个一组翻转链表)。 -综合题:设计一个企业内部的智能客服:用户的问题怎样分流到知识库问答和工具调用?怎样评测效果?怎样控制延迟和成本?出现提示词注入时怎样限制损失?(见[意图识别与路由](大模型应用.md#意图识别与路由)、[评测与优化](大模型应用.md#评测与优化)、[延迟与成本](大模型应用.md#延迟与成本)、[安全](大模型应用.md#安全)) +综合题:设计一个企业内部的智能客服:用户的问题怎样分流到知识库问答和工具调用?怎样评测效果?怎样控制延迟和成本?出现提示词注入时怎样限制损失?(见[意图识别与路由](大模型应用.md#意图识别与路由)、[RAG 的评测](大模型应用.md#评测与优化)、[Agent 的评测](大模型应用.md#2-评测)、[延迟与成本](大模型应用.md#延迟与成本)、[安全](大模型应用.md#安全))
答题思路