Llama 3 在通用对话和日常写作上通常够用:指令跟随、改写、摘要、邮件与文案这类任务,多数团队接上推理服务就能跑起来。但「够用」只覆盖短输入、低并发的场景。长文档输入会碰到上下文截断,多并发会暴露排队和显存压力,这两块不能靠感觉,得先按自己实际的输入长度和并发量测过,再决定哪些场景直接铺开、哪些留在试点。
判断:短对话与写作可以先小范围铺开,长文档与多并发建议单独立项验收。做法:按输入长度和并发量把需求分三档,用同一批提示词测基础能力,用超长输入定位截断位置,用并发脚本测首字时间与失败率。边界:上下文窗口、量化档位、显存与批处理配置都会改变结论,换模型版本、换机器或改采样参数后需要重测,旧结论不自动沿用。
按场景把需求分成短对话、长文档、多并发三类
分类不能按业务部门名来做,而按两个可量化的轴:单次请求的输入长度,和同时在线的请求数。长度的分界通常与部署时配置的上下文窗口挂钩——建议把「长上下文」定义为单次输入超过窗口的一半,或输入加预期输出的总量贴近窗口上限。具体窗口以你启动推理服务时设的参数为准,不要拿模型宣传值当验收标准。
| 类型 | 输入长度(相对窗口) | 并发量级 | 典型场景 | 是否需专项测试 |
|---|---|---|---|---|
| 短对话 | 单轮几百到数千 token,远低于窗口 | 单路或少量并行 | 内网问答、术语解释、改写 | 抽样即可 |
| 写作 | 输入短,输出较长 | 少量并行 | 周报、公告、文案初稿 | 关注输出上限 |
| 长文档 | 占窗口一半以上,或超出窗口 | 中低并发 | 合同比对、长论文、日志归因 | 必须测 |
| 多并发 | 视混合负载而定 | 从 2 路起逐级加压 | 全员接入的内网机器人 | 必须测 |
填表时把每行写清「谁在用、一次贴多少内容、同时可能几个人点」,这张表就是后面三轮测试的输入。
用同一批提示词测短对话与写作的可用度
基础能力测试的关键是固定变量:同一批提示词、同一组采样参数、同一个模型版本与量化档位,跑两遍看结果是否稳定。提示词按能力分三批,每批 10 到 20 条,取自你们真实业务而不是网上通用例子。
- 指令遵循批:明确要求「只输出三点」「不要解释」「用第一人称」,看模型是否照做。
- 格式要求批:要求输出 Markdown 表格、JSON 或固定字段,看结构是否可直接解析。
- 多轮改写批:同一对话里连续要求「改短」「换正式语气」「保留原数据」,看上下文是否被记住。
人工打分建议四个维度,每维三档,避免细到无法对齐。指令遵循、事实一致、格式合规、可读性;档位用「可用 / 需小改 / 不可用」。两人独立打分再对差异条目复核,比单人打分更省沟通成本。
| 编号 | 批次 | 提示词摘要 | 参数/量化 | 打分 | 问题备注 |
|---|---|---|---|---|---|
| T-01 | 指令遵循 | 只输出三点 | 温度、量化档位 |
构造长文档输入,观察截断与丢失发生在哪里
不要只丢一篇长文然后说「效果不好」,要把失效位置找出来。做法是逐步加长:拿一篇真实文档,按窗口的 50%、80%、接近 100% 分别构造输入,观察行为在哪一档开始变化。更直接的做法是在文档首、中、尾各插入一句唯一哨兵句,如「编号 A1 的核对句」,然后提问「文档里出现了哪些编号」,通过模型能否复述来判断哪一段被丢。
从输出反查截断位置的几个信号:首尾能答、中间答不出,通常说明输入被截或注意力在中间段衰减;回答里出现明显的句子中断或前后不衔接,说明输出侧被长度限制切断;请求直接报 4xx,说明输入超出服务端允许的长度,这时去查服务日志里的 token 计数,能确认是本地 tokenizer 估算偏差还是服务端上限更低。
分段处理作为替代方案要同时记录代价:一次性输入、先分段摘要再汇总、按段落逐一提问后合并,三种方式各记输入长度、是否丢关键信息、总耗时和人工修补量。分段方案通常更稳,但会丢失跨段关联,需要一个汇总轮次来补。
用并发请求脚本看吞吐与排队情况
并发上限不是猜出来的,是从低到高加压压出来的。骨架用线程池加流式请求即可,endpoint 和 payload 按你们的推理服务替换,先用固定长度的假提示词,避免混入业务变量。
# 通用并发骨架,endpoint 与 payload 按自己的推理服务替换
import time, requests
from concurrent.futures import ThreadPoolExecutor
ENDPOINT = "http://your-inference-host/v1/chat/completions"
CONCURRENCY = 4 # 从 2 路开始,逐级翻倍
ROUNDS = 5
def one_call(_):
t0 = time.time()
first = None
try:
r = requests.post(ENDPOINT, json={...}, stream=True, timeout=60)
for line in r.iter_lines():
if line and first is None:
first = time.time() - t0
return {"ok": True, "ttft": first, "total": time.time() - t0, "code": r.status_code}
except Exception as e:
return {"ok": False, "err": str(e), "total": time.time() - t0}
results = []
with ThreadPoolExecutor(max_workers=CONCURRENCY) as ex:
for _ in range(ROUNDS):
results += list(ex.map(one_call, range(CONCURRENCY)))
# 汇总:成功率、首字时间中位数、单请求总耗时中位数、失败原因分布
要采集的指标至少三个:首字时间、单请求总耗时、失败率(含超时和 5xx,按原因分开记)。判断规则可以这样用:并发升高时,首字时间和总耗时一起上升但失败率为零,说明请求在排队,系统还没到上限;一旦出现超时、连接重置或显存不足报错,当前这一级就是上限,把上一级记为可用并发并留出余量。每次只改一个变量,别同时改并发和输入长度。
把通过验收的场景与参数写成上线检查单
测试结论要变成别人能照着执行的准入条件,否则下一次上线又会重新争论。检查单按下面四项固化,每项都写明验证方式和未通过时的做法。
| 检查项 | 验证方式 | 未通过时的降级方案 |
|---|---|---|
| 上下文长度 | 用自己环境下实测的最大可用输入长度,而不是标称窗口 | 改为分段摘要再汇总,或对超长输入做明确截断提示 |
| 量化档位 | 固定档位复跑短对话批次,对比打分差异 | 换更高精度档位,或缩小到对精度不敏感的场景 |
| 并发上限 | 用并发脚本逐级加压得到的稳定值,另留余量 | 接入限流或排队队列,必要时增加推理实例 |
| 超时设置 | 按长文档最坏耗时设客户端与服务端超时,观察是否被截断 | 调高超时,或把长任务改成异步提交加轮询 |
检查单建议落到版本库里,和模型版本、量化配置一起记录。每次换模型、换量化档位或扩缩容后,重跑短对话批次和并发脚本,把新结果追加在旧记录后面,这样「够用」和「上限」都有据可查,而不是靠印象判断。