diff --git a/notes/pics/agent-cs-design.png b/notes/pics/agent-cs-design.png new file mode 100644 index 00000000..8916fa97 Binary files /dev/null and b/notes/pics/agent-cs-design.png differ diff --git a/notes/大模型应用.md b/notes/大模型应用.md index 7721fbb8..ae72e83d 100644 --- a/notes/大模型应用.md +++ b/notes/大模型应用.md @@ -53,6 +53,7 @@ * [推理服务部署](#推理服务部署) * [稳定性](#稳定性) * [安全](#安全) + * [设计一个客服 Agent](#设计一个客服-agent) * [附录:实测](#附录实测) * [A1 Embedding 相似度与 BM25](#a1-embedding-相似度与-bm25) * [A2 提示词对工具调用的影响](#a2-提示词对工具调用的影响) @@ -131,7 +132,7 @@ Token 数决定了两件事: 2. 向量依次经过几十个结构相同的层,Qwen2.5-7B 有 28 层。每层先用注意力从前文收集信息,再用前馈网络(Feed-Forward Network, FFN)对每个位置单独加工; 3. 最后一个位置的向量经过线性层,得到词表中每个 Token 的分数(logits),再经过 softmax 转为概率。 -每个子层都带有残差连接和归一化。残差连接把子层的输入直接加到输出上,使几十层的网络也能稳定训练;归一化把每个向量的数值缩放到稳定的范围。最初的 Transformer 在残差相加之后做归一化,目前的大模型大多改为在每个子层之前做(Pre-Norm),残差的主干上不再经过归一化,几十层叠加时训练更稳定,并使用只按均方根缩放、计算更简单的 RMSNorm,Qwen2 系列就是这样。 +每个子层都带有残差连接和归一化。残差连接把子层的输入直接加到输出上,使几十层的网络也能稳定训练;归一化把每个向量的数值缩放到稳定的范围。这里用的是 LayerNorm 一类的方法,只用一个 Token 自己向量的各个维度计算统计量,而不像 BatchNorm 那样依赖同一批中的其它样本,所以不受批大小和序列长度影响,训练和推理时的计算也相同。最初的 Transformer 在残差相加之后做归一化,目前的大模型大多改为在每个子层之前做(Pre-Norm),残差的主干上不再经过归一化,几十层叠加时训练更稳定,并使用只按均方根缩放、计算更简单的 RMSNorm,Qwen2 系列就是这样。 三种结构的注意力有两处不同。编码器中每个 Token 都能看到全部 Token;解码器的自注意力带有因果掩码,只能看到前面的 Token,见下文的注意力机制。编码器-解码器结构的解码器每层还多一个交叉注意力(Cross-Attention):Q 来自解码器,K 和 V 来自编码器最后一层的输出,生成每个词时都可以查阅整句原文。 @@ -225,7 +226,7 @@ Q = x W_Q (n, 3584) 降低这部分开销有两类做法。一类让每个 Token 只看一部分 Token,或者改写 softmax,结果与标准注意力不同:例如 Mistral 7B 的滑动窗口注意力中,每层的每个 Token 只看前 4096 个 Token;线性注意力用核函数代替 softmax,利用矩阵乘法的结合律把复杂度降为 O(n)。另一类结果不变,只减少显存的读写,即 FlashAttention。 -FlashAttention 把计算分块放进 GPU 的片上缓存完成,n × n 的分数矩阵从不写回显存,再用在线 softmax 逐块累积,结果与标准注意力完全相同。它减少的是显存的读写而不是计算量,原理和数值例子见[进阶:计算量与 FlashAttention](大模型应用%20-%20进阶.md#2-计算量与-flashattention)。 +FlashAttention 把计算分块放进 GPU 的片上缓存完成,n × n 的分数矩阵从不写回显存,再用在线 softmax 逐块累积,结果在数学上与标准注意力相同,不是近似。它减少的是显存的读写而不是计算量,原理和数值例子见[进阶:计算量与 FlashAttention](大模型应用%20-%20进阶.md#2-计算量与-flashattention)。 ### 自回归生成与 KV Cache @@ -1800,7 +1801,7 @@ Skill 与系统提示词、Agent 的区别: Skill 中的规范只能引导,不能保证模型一定遵守,必须满足的规则还要用脚本或钩子检查,见 [Harness 的引导与反馈](#2-引导与反馈)。模型也不一定会加载 Skill,描述不够贴切时可能直接动手;部署、提交这类有副作用、必须按流程走的 Skill,可以设为只允许用户用斜杠命令(例如 /deploy)显式调用,Claude Code 中在 frontmatter 写 disable-model-invocation: true,它的描述也不再放进目录。 -Agent 是否使用某个 Skill,完全取决于它的 description,所以要像测试[意图识别与路由](#意图识别与路由)一样测试它: +除了用户用斜杠命令直接调用,模型自动选用 Skill 时,是根据目录中的名称和 description 判断它与当前任务是否相关,所以要像测试[意图识别与路由](#意图识别与路由)一样测试它: - 触发测试:准备约 20 条真实的提问,一半应该触发、一半不应该触发。不应该触发的重点选关键词相近但需求不同的,例如“把周报模板翻译成英文”不应该触发生成周报的 Skill。每条运行 3 次左右计算触发率,并留出一部分提问不参与修改,检查改进是否适用于新的说法; - 效果测试:同一批任务分别在有和没有这个 Skill(或者使用旧版本)的情况下运行,能用代码判断的项由脚本检查,其余由人或模型裁判比较,同时记录 Token 消耗和耗时。 @@ -2537,6 +2538,59 @@ OpenAI 的官方 SDK 默认也是这样处理的:对 408、409、429 和 5xx 每次工具调用都记录审计日志:谁发起的任务、调用了哪些工具、参数和结果是什么、谁确认了操作,出了问题可以追溯。 +### 设计一个客服 Agent + +“设计一个智能客服 Agent”这类题要把前面的机制组合成一个能上线的系统,下面仍以前文的电商客服为例,通用的答题顺序见[系统设计题的思路](系统设计基础.md#十三系统设计题的思路)。 + +#### 1. 需求和约束 + +先和面试官确认范围。假设要做的是电商 App 内的售后客服: + +- 功能:查询订单和物流,回答退换货政策和商品问题,办理退款和改地址,处理不了的创建工单或转人工; +- 规模:平时每天 10 万次咨询,大促期间约为平时的 10 倍(假设); +- 体验:用户发出消息后很快能看到进展,不能对着空白等完多轮调用; +- 安全:用户只能查自己的订单,退款金额不能超过实付金额,资金操作必须由用户确认。 + +按高峰小时占全天流量的 6% 计算,平时高峰约 10 万 × 6% ÷ 3600 ≈ 1.7 次咨询/秒,大促约 17 次/秒。每次咨询按前文的例子调用 3 次模型,假设共约 6 秒,由利特尔法则,大促高峰同时在进行的咨询约 17 × 6 ≈ 100 个。模型服务的并发和 Token 限额要按这个量申请或部署,见[大模型服务的高并发](系统设计基础.md#大模型服务的高并发)。 + +多轮调用让首个字出现得晚,所以要把“正在查询订单”这类进展推给前端,见[推送 Agent 的执行过程](#2-推送-agent-的执行过程)。成本也要在设计时估算:按[一次 Agent 任务的费用](#2-一次-agent-任务的费用)中的例子,每天 10 万次对话约 82~270 元,差别在于前缀缓存是否命中;实际的提示词和工具结果更长,费用会成倍增加。 + +#### 2. 架构 + +