把自定义模型接进 WorkBuddy 之后,发一条消息进去,等了十几秒,聊天窗口一点反应都没有。这种情况我遇到太多次了,从身边同事到社区里的提问帖子,几乎每天都能看到同类问题。大多数人第一反应是模型服务挂了,或者 WorkBuddy 本身出了问题,但实际上,把排查链路走一圈之后会发现,真正的原因往往是一些极其“朴素”的配置错误:请求地址拼错了、模型名写错了、超时时间太短,或者返回格式跟 WorkBuddy 的预期不匹配。
这篇文章就专门梳理“接入自定义模型后不回复”这个问题的完整排查思路。我会从接入方式、基础自检、核心配置项、请求链路、模型侧问题这几个维度逐个拆开讲,最后附上几个我实际处理过的案例和一份速查表。不管你是第一次接自定义模型的新手,还是已经在生产环境跑了一阵子的老手,这套排查路径应该都能帮你省下不少时间。
1. 接入方式回顾与基础自检
1.1 先搞清楚你接的到底是哪种“自定义模型”
同样是“不回复”,模型部署在不同的位置,故障原因可以完全不同。我建议大家排查前先花三十秒确认自己的接入类型,因为后续的排查方向完全是三套逻辑。
第一种是本地部署模型。比如你在内网服务器上部署了某个开源模型,通过推理框架暴露一个 HTTP 接口,WorkBuddy 直接请求这个内网地址。这类问题的重点通常在网络连通性、服务端口是否监听、显存是否充足,以及并发上。因为本地服务往往缺少完善的负载均衡和排队机制,一旦请求量上来或模型本身卡住,表现就是“不回复”。
第二种是第三方云模型 API。你买了一家长尾模型服务商的 API,拿了一个 Key,然后填到 WorkBuddy 的自定义模型配置里。这种场景下,问题点更多集中在鉴权失败、模型名与平台不匹配、账户余额不足、配额受限,以及服务端限流。有时候对方平台升级了接口规范,但你还是用旧格式在调用,同样会得不到回复。
第三种是企业内部的统一网关或中间层。公司内部搭建了网关,把多个模型封装成一个统一接口,对外号称“兼容 OpenAI 格式”。这种最容易出问题的地方反而是网关本身:路由规则没覆盖你的新模型、网关超时设置太短、上游模型服务认证过期,等等。网关会把很多错误吞掉,返回一个看起来“正常”但没有内容的结果,你在 WorkBuddy 里看到的就是转圈后无回复。
所以我在排查时习惯先问一句话:这条请求链路里,到底哪一段是自定义的部分?是模型本身,还是接口封装层?这个前提搞不清楚,后面做再多测试都是乱打。
1.2 基础自检清单:五分钟排除常规故障
在深入抓包、看日志之前,先花五分钟把底层配置过一遍。这套基础检查看起来很蠢,但命中率其实非常高,我建议按顺序来:
第一,确认配置真的保存并生效了。很多自定义模型配置界面里,输入完 Base URL、API Key、模型名称之后,还需要点“保存”或者“连接测试”。有时候页面提示保存成功,但实际服务进程还没热加载,必须重启 WorkBuddy 才能让新配置生效。我的习惯是:任何配置改动后,都强制重启一次客户端或服务进程,再做测试。
第二,检查账号权限和配额。这个坑往往是旁观者清。如果你是调用某个平台的 API,打开对方控制台看一眼账户余额、限流状态、模型权限。很多平台对新模型默认不开通权限,或者试用额度已经用完,请求直接返回 401 或 403,而 WorkBuddy 在界面上统一表现为“没有回复”。
第三,做一次网络连通性测试。确认 WorkBuddy 所在的环境能访问到模型服务地址。我见过不少案例,模型服务本身没问题,但部署环境之间隔了防火墙、安全组、白名单,请求根本到不了服务端。用 curl 或 telnet 验证一下端口能不能通,能排除掉一大半网络层问题。注意这里是直接请求目标地址,不涉及任何代理或额外跳转。
第四,确认模型服务本身是健康的。打开模型服务的健康检查接口或者日志面板,看它最近有没有正常响应记录。本地部署的话,看一眼 GPU 利用率、显存占用、进程是否还活着,很多时候模型进程已经 OOM 崩了,但 WorkBuddy 那边的连接池还挂着,表现就是“转圈后无响应”。
这四条基础项都过了,问题还在,再进下一步,开始看具体配置项。说实话,有相当比例的问题在这一步就能定位。
2. 核心配置项逐个排查:地址、鉴权、模型名
2.1 Base URL 和路径拼接:最常见的“隐形杀手”
Base URL 是自定义模型配置里最不起眼、但出错率最高的字段。很多人以为把模型服务的地址填进去就完事了,实际上这里藏着两个高频问题。
第一个问题是路径前缀重复。OpenAI 的接口规范里,完整地址通常是https://服务地址/v1/chat/completions。很多兼容层服务把v1这个前缀内置在了路由里。如果你在 Base URL 里填了https://api.example.com/v1,WorkBuddy 又会自动拼接/v1/chat/completions,最终请求就变成了https://api.example.com/v1/v1/chat/completions,服务端直接返回 404 或者干脆不认这个路径。
我遇到过好几个用户把 Base URL 填成带/v1的完整地址,然后在“路径前缀”栏里又填了/v1。这是个理解偏差的问题。正确的做法是:先弄清楚服务方文档里给的 base_url 到底是什么。如果文档说明“直接在代码里用https://xxx作为 base_url,SDK 会自动拼/chat/completions”,那你就填https://xxx,不要画蛇添足。
第二个问题是路径是否必须包含/openai或/v1。不同兼容层的设计习惯不一样。有些本地推理框架暴露的路径是根路径/v1,有些是/api/v1,还有些要求在 Header 里指定X-Path-Routing。最稳妥的办法是拿 curl 直接打一个最简单的请求,看服务端返回什么,再决定Base URL怎么填。
我给的实操建议是:先用 curl 验证完整请求。比如你配置的是 OpenAI 兼容接口,就按这个格式测:
curl -X POST https://你的服务地址/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer 你的KEY" \ -d '{"model":"你的模型名","messages":[{"role":"user","content":"你好"}],"max_tokens":100}'如果 curl 能正常返回内容,说明地址、鉴权、模型名都没问题,问题大概率在 WorkBuddy 的配置上。如果 curl 也报错,那就逐段拆:先测https://你的服务地址通不通,再测/v1路径通不通,再加 Header,再加 Body。用这种“最小请求”的方式逐层叠加,很快就能锁定到底是哪一段出了问题。
2.2 API Key 与认证方式:一点小细节就能让所有请求失败
鉴权配置也是重灾区。先说最简单也最容易被忽视的:Key 拷贝的时候带了隐藏的回车、换行或空格。比如在网页上复制 Key 时不小心把末尾的换行符也复制进去了,粘贴到配置框里肉眼看不出来,但实际发出的请求 Header 变成了Authorization: Bearer sk-xxx\n,服务端解析就失败了。这类错误排查起来极其折腾,因为日志里看到的 Key 几乎是完整的,只有用十六进制才能看出来多了个换行符。
其次要确认 WorkBuddy 期望的鉴权方式到底是不是Bearer Token。大多数 OpenAI 兼容接口用的是Authorization: Bearer <KEY>,但也有不少模型服务使用自定义 Header,比如X-API-Key: <KEY>,或者Api-Key: <KEY>。WorkBuddy 的自定义模型配置通常假定你走的是标准 Bearer 方式,如果你的模型服务商规定用别的 Header,那就要看 WorkBuddy 支不支持自定义 Header。如果不支持,就需要在模型服务和 WorkBuddy 之间加一层转换,把自定义 Header 翻译成标准 Bearer,或者用反向代理做一层中间适配。
还有一个情况是 API Key 需要定期轮换。很多企业安全策略要求密钥 30 天或 90 天更换一次。如果密钥已经过期,你是不知道的,直到某天突然所有请求都失败。排查时进服务商控制台看一眼密钥状态,能帮你快速排除这个问题。
2.3 模型名称不一致:看似小问题,影响面巨大
模型名称(Model Name)必须与模型服务端实际接受的名称完全一致,包括大小写、连字符、点号。举个例子,服务端注册的是qwen2-72b-instruct,你在 WorkBuddy 里填的是qwen2-72B-instruct,看起来只差一个大小写,但请求发过去服务端返回Model not found,或者是空响应。
很多平台为了兼容旧版本,可能存在“别名机制”,即同一个模型有多个可调用的名字。这种机制不一定公开透明,有时候你填了别名它也接受,有时候必须填规范名。我的建议是:永远以模型服务端日志里实际打印出的模型名称为准,而不是以你记忆里的名称或网页界面显示的标签为准。
如果模型服务端有列表接口,可以先调用列表接口看一下模型全名。没有列表接口的话,就用 curl 故意发一个错误的模型名,观察报错信息里有没有提示可用的模型列表。很多 OpenAI 兼容服务会在错误信息里返回可用的模型列表,这是最省事的调研方式。
另外,模型名超过一定长度或者包含特殊字符时,某些配置界面会自动做截断或转义,导致实际发送的 model 字段与预期不一致。如果你到了日志环节发现 model 字段总是“少了一截”,可以怀疑是配置界面的字符限制问题,换一个更短的模型别名往往就能解决。
3. 请求链路与协议兼容性分析
3.1 怎么确认 WorkBuddy 发出的请求到底长什么样
配置层面检查完还没有思路,就该进入请求链路分析了。核心问题很明确:WorkBuddy 到底有没有把请求发出去?发到了哪里?服务端有没有收到?收到了之后有没有正常处理和返回?
最好的工具是日志。WorkBuddy 如果是桌面客户端,看它的日志目录;如果是自托管的服务端,看标准输出和应用日志。日志里一般会记录请求的完整 URL、HTTP 状态码、响应体内容。很多时候问题在日志里就已经非常清楚了,比如404 Not Found、401 Unauthorized、400 Invalid model,一眼就能定位。
如果 WorkBuddy 本身日志不够详细,可以用抓包工具在链路中间盯着。比如用 tcpdump 或者 Wireshark,看请求实际发往哪个地址、Header 长什么样、响应体是什么。不过抓包在加密传输下看不到内容,只看到连接痕迹,所以更常用的做法是在模型服务端加一层临时的入口日志,打印出每个请求的完整字段。我用过一个更“暴力”但很有效的方法:在模型服务和 WorkBuddy 之间加一个临时转发层,转发层负责打印所有请求和响应内容,再原样转发。这样能精确看到 WorkBuddy 发出的请求头和请求体是什么,以及模型服务返回了什么。
日志里要重点看这几个信息:请求方法是不是POST,路径对不对,Content-Type是不是application/json,Authorization有没有携带正确,body里的model字段和messages格式是否合法。我遇到过的情况是 WorkBuddy 发出的请求里messages带了额外的type字段,某个模型服务不认这个字段,直接拒绝处理,导致无回复。
3.2 响应格式不兼容:符合协议比“能返回内容”更重要
WorkBuddy 作为对话客户端,对模型服务的响应格式是有明确预期的。如果你接的模型服务返回的 JSON 结构不符合 OpenAI 规范,即使模型本身“说了话”,WorkBuddy 也可能解析不出来,界面上表现为没有输出。
标准的非流式 Chat Completions 响应结构大概是这样的:
{ "choices": [ { "message": { "role": "assistant", "content": "你好,有什么可以帮你?" }, "finish_reason": "stop" } ] }WorkBuddy 通常会从这里读取choices[0].message.content来展示回复。如果你的模型服务返回的结构是output、text、data.content之类的自定义字段,WorkBuddy 根本不知道去哪里找回复,自然就显示为空。
另外还有个高频坑:流式响应格式。WorkBuddy 的自定义模型接入可能默认开启流式,也可能默认关闭,不同版本行为不一样。模型服务端如果返回的是流式格式(每一行一个data: {...}),但 WorkBuddy 期待的是完整 JSON,就会发生解析错误,或者只在最后一次渲染时拿到空内容。反过来也一样:WorkBuddy 用流式模式等待数据,模型服务端却迟迟不返回流式格式,界面会一直转圈到最后超时。
判断这个问题的办法很简单:在日志里看模型服务端返回的Content-Type。如果是text/event-stream,说明走的是流式;如果是application/json,说明是非流式。再看 WorkBuddy 的配置里有没有流式开关,两边对齐才能正常显示。
还有一个非常隐蔽的问题:响应中的finish_reason不等于stop。有些模型因为设置了最大 token 数,导致回复被截断,finish_reason变成了length。这种情况下,WorkBuddy 可能只拿到一半甚至零字符。如果你看到日志里finish_reason一直不是stop,就要加大max_tokens或者检查截断逻辑。
3.3 超时、并发与上下文窗口设置
连接通了、格式也对了,仍然可能不回复,这时候要想想时间维度的因素。模型推理是需要时间的,尤其本地跑大模型时,一个长请求可能十几秒甚至几十秒才返回第一个 token。WorkBuddy 如果对自定义模型有内置超时限制,而模型生成速度太慢,客户端就会在模型还没回答完之前主动放弃,表现就是用户在界面里看到转圈,然后突然报错或者恢复空白。
解决办法是找到超时配置项,尽量调大。如果超时时间已经调到很大还是不行,那就得考虑是不是并发请求把模型服务的计算资源占满了。多个用户同时在用同一台模型服务,显存和算力都被抢占,每个请求都被排队,互相拖慢,最终每个人都超时。这种情况下,给模型服务加一个队列调度,或者限制 WorkBuddy 端的并发数,会有立竿见影的效果。
还有上下文窗口溢出。请求里携带的对话历史太长,超过模型服务支持的上下文长度,服务端会拒绝处理,或者只按窗口尾部截断后依然超限,最终返回空结果。排查时可以在日志里关注有没有context length exceeded、maximum context之类的关键字。如果有,把对话历史缩短,或者调整配置让 WorkBuddy 在发送前做截断。
4. 模型侧问题:不要总怪 WorkBuddy
4.1 模型服务本身是否“正在正常思考”
很多看似“不回复”的问题,根源在模型服务端。我见过一个排查了两小时的真实案例:WorkBuddy 发送请求之后,界面一直转圈,确定没有超时,日志里也显示请求已经到达模型服务,但模型服务没有返回任何内容。后来发现是模型服务所在机器的 GPU 已经满了,进程卡在显存申请上,表现为请求进来但不推理,不返回任何东西。
检查模型服务健康状态时看三样东西:进程是否在跑、GPU 利用率是否正常、显存是否有余量。进程在跑但 GPU 利用率低,说明模型可能卡在了 CPU 预处理或数据加载阶段;GPU 利用率高但显存已经占满,说明并发请求太多或者上下文太长。
还有一个更容易忽略的:模型服务的热加载问题。有些模型服务支持热加载多个模型,启动时只加载了一部分参数,或者第一次请求才触发模型加载,导致首个请求特别慢,超过 WorkBuddy 的超时阈值。解决办法是提前做一次预热,用 curl 先发几个短消息,让模型完成加载,再接入 WorkBuddy。
4.2 对话历史太长或采样参数设置不当
对话历史过长是导致模型无响应的另一个高频原因,前面已经提到上下文溢出。补充一个容易混淆的点:模型服务的 max_tokens 参数和 WorkBuddy 发送的请求体里 max_tokens 参数是两个东西。如果 WorkBuddy 在请求体里传了一个特别小的 max_tokens,比如只有 8,模型生成几个 token 就停了,finish_reason是length,界面可能完全不显示内容。调大这个参数通常能立刻解决。
采样参数方面,temperature、top_p设置极端时也会出现问题。比如temperature设为 0 本身不会导致空回复,但如果模型服务端对 0 值做了特殊处理,或者 top_p 设成非常小导致概率分布被截断到几乎为零,模型可能只生成一个空字符串或一个停止符。配置自定义模型时,尽量先保持默认采样参数,确认链路通了之后再慢慢调整。
4.3 内容过滤与安全策略导致的“静默拒绝”
最后说一个容易背锅的环节:模型服务内置的内容安全策略。某些模型服务在检测到输入或输出违反安全规则时,不是返回报错,而是返回一个空的 choices,或者把内容替换成固定短语。从 WorkBuddy 端看,就是模型没有回复。
这种问题的特征很明确:请求状态码是 200,响应结构也都合法,但content是空字符串,或者finish_reason是content_filter。排查日志时如果看到这个字样,说明触发了内容过滤。要和模型服务的运营方确认具体触发规则,调整输入内容或者关闭过滤机制。企业在自建模型服务时也需要注意,部分开源模型内置的话术安全模板会拒绝回答某些类别的敏感问题,这属于模型策略而非故障。
5. 常见问题速查与实战记录
5.1 三个真实案例的排查过程
案例 A:路径前缀重复导致的 404
某开发者把自定义模型配置里的 Base URL 填成了http://模型网关地址/v1,同时又在 WorkBuddy 的路径设置里加了一层/v1前缀,实际请求路径变成/v1/v1/chat/completions。通过 curl 单测时发现服务端直接返回 404,日志里能看到路径带了两个/v1。最后把 Base URL 改成根地址,前缀留空,问题解决。整个过程花了二十分钟,因为一开始没看日志,一直以为是模型加载问题。
案例 B:流式响应与非流式模式不匹配
某同事部署了一个映射模型,服务端默认返回流式格式,但 WorkBuddy 自定义模型配置里的流式开关是关闭状态。请求到达模型服务后,服务端认为客户端能处理流式数据,就按text/event-stream返回;WorkBuddy 则在等待一个完整的 application/json 响应,两边僵住,直到超时。排查时抓包看到Content-Type: text/event-stream后才明白。最后在配置里打开流式开关,立即恢复正常。
案例 C:上下文超限导致空回复
一个做了很久生产环境的用户反馈,短问题能回复,长问题完全不回复。查看日志,模型服务返回了一个 error,内容大意是上下文长度超过了最大限制。用户之前把 WorkBuddy 发来的 messages 原样转发给模型,没有做截断,多次对话之后 messages 累计长度不断膨胀,最终超过模型窗口。解决办法是在网关侧做消息裁剪,只保留最近几轮对话,回复恢复正常。
5.2 常见问题速查表
| 现象 | 可能原因 | 排查动作 |
|---|---|---|
| 日志出现 404 | Base URL 路径拼接错误 | 检查是否重复填了/v1,按文档纠正 |
| 日志出现 401/403 | API Key 错误或过期 | 重新生成 Key,确认无隐藏空格 |
| 日志出现 400 Model not found | 模型名称不匹配 | 调用模型列表接口确认准确名称 |
| 状态码 200 但 content 为空 | 流式模式不匹配 / 内容过滤 / max_tokens 过小 | 检查 Content-Type 和 finish_reason |
| 状态码 200 但一直转圈 | 超时设置太短 / 模型推理太慢 | 调大超时,预热模型 |
| 请求没到模型服务 | 网络不通 / 防火墙拦截 | curl 测试端口,检查安全组 |
| 短对话正常,长对话不回复 | 上下文超限 | 裁剪 messages,缩短对话历史 |
| 某些特定内容不回复 | 模型内容安全策略 | 检查日志里的 content_filter 字样 |
5.3 几点预防建议
这套排查流程走下来,大多数自定义模型不回复的问题都能在半小时内定位。想减少后续的排查成本,我有几条非常实际的建议。
第一,配置自定义模型时,先在模型服务端开一个完整请求日志。哪怕只开一天,也能帮你快速定位大量问题。请求日志里要记录时间、路径、请求头、请求体、响应状态、响应体,缺一不可。没有日志就排查问题,等于闭着眼睛找东西。
第二,把所有自定义模型的配置整理成一份文档,包括 Base URL 的确切值、模型全名、认证方式、超时设置、是否开启流式。团队协作时,这份文档能避免后面接手的同事靠猜来排查问题。
第三,在接入一个新模型之前,先用 curl 把最小请求测试通过,再接入 WorkBuddy。很多问题本质上是模型接口文档没说清楚,或者你的理解有偏差,跟 WorkBuddy 本身没有关系。提前用 curl 打通接口,相当于隔离了变量。
第四,上线前做一次“长对话压测”。连续发多轮消息,观察超过十轮之后是否还能正常回复。这个测试能提前暴露上下文超限、并发排队、超时等问题,避免上线后突然翻车。
最后再说一个我自己的习惯:遇到自定义模型不回复,我会把排查顺序固定为“网络连通性 → 请求日志 → 响应格式 → 模型健康”,不跳跃。这套顺序看着笨,实际效率最高。因为大多数问题都出现在链路的前半段,过早深入模型内部反而浪费时间。希望大家下次遇到 WorkBuddy 接自定义模型不回复时,能少走点弯路。