GPT-6 Luna 的上下文长度和超时阈值没有一组通用最优值,能设多大取决于你的输入规模、并发数,以及服务端当时的排队与限流情况。可操作的路子是:先把这两个参数从调用代码里搬到外部配置,再用同一提示词、长度递增的一小批请求打过去,看哪一档开始明显变慢或开始报错,然后把结论写回配置并留档。
先外置配置、再小批量压测,是判断上下文长度与超时阈值最省事的一条路。适用场景是批量调用还没定型、参数仍在试的阶段。操作上,配置里只放客户端一侧的约束,模型实际可用上限以官方文档为准;压测时锁死提示词、输出长度上限和并发数,只改输入长度。验证方式看成功率、耗时分布、错误类型这三样。风险边界是:单次小批量结果只代表那一档并发与那一刻的服务端状态,不能直接当成容量结论。
把上下文长度与超时写成外部配置
把参数写死在调用代码里,每调一次就要重新发版、重跑一遍回归,试参数的成本太高。建议至少把下面几项提到配置文件,让调参变成改文件加重启。
luna:
base_url: your-endpoint.example
model: gpt-6-luna
max_context_tokens: 32000 # 客户端预设的输入上限,实际可用上限以官方文档为准
max_output_tokens: 1024
request_timeout_s: 60 # 单次请求的整体超时
connect_timeout_s: 5 # 建连超时,单独设,便于区分网络问题
concurrency: 4
retry:
max_attempts: 4
base_delay_s: 1
max_delay_s: 30
- max_context_tokens:客户端主动截断的输入上限,超了就在本地拒绝,不必等服务端返回错误。
- request_timeout_s 与 connect_timeout_s:拆成两个,超时日志里能直接看出是连不上还是等太久。
- concurrency:本地并发闸门,压测时靠它控制变量,也避免自己把自己打成限流。
- retry 段:退避参数,第四节会用到。
要留意配置文件里的值只是客户端一侧的约束。模型实际支持的上下文窗口、单次请求的排队与超时策略仍受服务端限制,具体数值需要回官方文档确认,不要直接照抄别人的配置。
构造一批长度递增的测试输入
目标是找到自己场景下开始变慢或失败的输入规模,所以只允许一个变量变化:输入长度。提示词模板、输出长度上限、并发数、重试策略都要锁死。
生成方式建议把一段固定的中性文本重复拼接,而不是灌随机字符——随机字符容易命中不同的分词结果,长度不好对齐。档位不必很密,先铺开几档看趋势:
import json
FILLER = '这是一段用于填充的固定文本,内容不参与业务判断。' * 50
def build_cases(lengths, prompt):
cases = []
for i, approx_tokens in enumerate(lengths):
# 按经验比例粗略换算成字符数;有 tokenizer 就用 tokenizer 精确切
chars = int(approx_tokens * 1.6)
text = (FILLER * (chars // len(FILLER) + 1))[:chars]
cases.append({
'case_id': f'len-{approx_tokens}-{i}',
'input_tokens': approx_tokens,
'messages': [{'role': 'user', 'content': prompt + text}],
})
return cases
cases = build_cases([1000, 2000, 4000, 8000, 16000, 32000], '按以下材料回答一个问题:材料要点是什么?')
json.dump(cases, open('cases.jsonl', 'w'), ensure_ascii=False)
每个长度档不要只跑一次,同一档跑几次才知道耗时抖动是常态还是异常。建议逐档跑完再加大并发,别一上来就全档位混跑。
跑一轮小批量并发并记录指标
脚本骨架就是遍历用例、线程池并发、计时、落盘。用线程池比手写协程更好排查,每条记录自带时间戳,出问题能和日志里的时间线对上。
from concurrent.futures import ThreadPoolExecutor
import json, time
def call_luna(payload, cfg):
start = time.time()
rec = {'timestamp': time.strftime('%Y-%m-%dT%H:%M:%S'),
'case_id': payload['case_id'],
'input_tokens': payload['input_tokens'],
'http_status': None, 'error_type': None,
'elapsed_ms': None, 'retry_count': 0}
try:
resp = client.chat(payload, timeout=cfg['request_timeout_s'])
rec['http_status'] = resp.status_code
if resp.status_code != 200:
rec['error_type'] = classify(resp)
except TimeoutError:
rec['error_type'] = 'client_timeout'
except Exception as exc:
rec['error_type'] = type(exc).__name__
rec['elapsed_ms'] = int((time.time() - start) * 1000)
return rec
with open('records.jsonl', 'a') as fout:
with ThreadPoolExecutor(max_workers=cfg['concurrency']) as pool:
for rec in pool.map(lambda c: call_luna(c, cfg), cases):
print(json.dumps(rec, ensure_ascii=False), file=fout)
必须落盘的字段:时间戳、case_id、input_tokens、耗时(毫秒)、HTTP 状态码、错误类型、重试次数。成功的请求也要记,否则没有耗时分布可比。跑完按 input_tokens 分组,看耗时的中位数和高分位——如果高分位比中位数大出一截,通常是部分请求在排队,而不是参数设错了。
按错误类型决定调参还是退避
看到失败先别急着改参数,先分清是参数不合理还是服务端限制。前者重试再多次也没用,后者重试是有意义的。
def classify(resp):
code = resp.status_code
if code == 429:
return 'rate_limit' # 退避重试
if code // 100 == 5:
return 'server_error' # 退避重试
if code == 413:
return 'payload_too_large' # 降输入长度,不重试
if code // 100 == 4:
return 'client_error' # 查模型名、路径、鉴权、上下文上限
return 'unknown'
- 400、413 一类:多半是上下文超限、字段拼错或模型名不对,改配置,不要重试。
- 401、403:鉴权或配额问题,检查凭证与项目归属,与超时阈值无关。
- 429 和 5xx:属于排队或服务端波动,用退避重试,同时别把并发调大。
- 客户端超时:先判断是阈值设得偏小,还是服务端确实处理不过来。同一长度档多跑几次,如果耗时集中在阈值附近,优先调阈值。
退避写法给一个通用版本,关键是加抖动,避免所有并发请求在同一时刻一起重试:
import random
def next_delay(attempt, base=1.0, cap=30.0):
raw = min(cap, base * (2 ** attempt))
return raw * (0.8 + 0.4 * random.random())
for attempt in range(cfg['retry']['max_attempts']):
rec = call_luna(payload, cfg)
if rec['error_type'] in ('rate_limit', 'server_error', 'client_timeout'):
time.sleep(next_delay(attempt))
continue
break
重试要在记录里体现,retry_count 字段就是为这件事留的。如果一批记录里大量请求都靠重试才成功,说明并发或超时阈值需要调整,而不是靠重试硬扛。
把有效参数写回配置并留记录
压测得出的结论必须落回配置并留下变更记录,否则下次改参数又变成凭感觉。建议一行一次变更,表头固定成下面几列;表格里填的是模板示意,数值和现象按你自己的记录写。
| 字段 | 改前值 | 改后值 | 观察到的现象 | 验证方式 |
|---|---|---|---|---|
| max_context_tokens | 原值 | 新值 | 例:某一长度档出现 413 或客户端超时 | 重跑同一批 cases,对比该档成功率与耗时 |
| request_timeout_s | 原值 | 新值 | 例:某档耗时集中在原阈值附近,错误多为 client_timeout | 同档位重跑三次,比较耗时分布 |
| concurrency | 原值 | 新值 | 例:提高并发后 429 增多 | 降并发重跑,看 429 是否消失 |
表里只写日志和页面行为能验证的内容:状态码、错误信息、耗时分布。验证方式统一是重跑同一批 cases——现象变了才算调整有效,没变就回滚,别把参数一层层往上堆。顺手记一下调整日期,方便日后回看当时的服务端状态。