用 curl 或 SDK 调本地模型时,很容易卡在同一件事上:官方文档里一会儿写 /api/chat,一会儿写 /api/generate,示例参数还不一样,抄谁?抄错了轻则多轮对话丢上下文,重则返回结构对不上、前端解析全崩。这篇不背文档,直接按「你要做什么事」把两个接口的分工摆出来,给一份参数对照表和一段可复用的排查顺序。
用 curl 或 SDK 调本地模型时,很容易卡在同一件事上:文档里一会儿写 /api/chat,一会儿写 /api/generate,示例参数还不一样,抄谁?抄错了轻则多轮对话丢上下文,重则返回结构对不上、前端解析全崩。
这篇不背文档,直接按「你要做什么事」把两个接口的分工摆出来,给一份参数对照表和一段可复用的排查顺序。看完你应该能在几分钟内决定这次该用哪个接口,以及改错的时候先查哪里。
两个接口各自是干什么的
先记住最核心的一条:generate 是单轮补全,你给一段 prompt,它还你一段生成结果,请求体里根本没有角色、消息列表这些概念。chat 是对话补全,你给的是一个 messages 数组,每条消息带 role,模型按数组顺序理解成一段对话,然后接着往下答。
- generate
- 单轮补全,输入一段文本,输出一段文本,没有角色与历史的概念
- chat
- 对话补全,输入一个带 role 的消息数组,服务端按对话来组织上下文
- role
- 消息的角色标记,常见 system / user / assistant,决定模型怎么看待这条内容
- stream
- 流式开关,开启后返回的是一段段增量数据,而不是一次性返回完整结果
两者跑在同一个本地服务的同一个端口上,路径不同而已,但返回体的字段名并不完全一样。最常见的坑就是把一边的解析代码直接套到另一边,结果字段取不到值,页面上一片空白。
- 只需要「输入→输出」跟一次请求:选 generate,请求体小,心智负担低
- 需要角色设定、需要把上一轮答案带回下一轮:选 chat,历史由服务端按数组顺序组织
- 不确定自己这版服务支持哪些字段:先到站内 /ai-dict/category/tech 对照术语说明,再动手改代码
参数对照与容易踩的坑
别把 messages 和 prompt 当成可以互相替换的两个名字。在 generate 里想实现多轮,你得自己把历史拼成一段字符串,怎么拼、拼多长、上一个回答要不要截断,全是你的责任;chat 里这些交给服务端,你只管按顺序把消息排好。
| 关注点 | generate 的做法 | chat 的做法 |
|---|---|---|
| 输入形态 | 一段 prompt 字符串 | messages 数组,每条带 role |
| 多轮历史 | 自己拼接进 prompt,长度自控 | 按数组顺序组织,长度随轮次增长 |
| 系统提示词 | 通常作为 prompt 前缀写 | 单独一条 role=system 的消息 |
| 返回结构 | 文本结果字段 | 消息对象里的内容字段 |
| 结构化输出 | 一般要自己在 prompt 里约束格式 | 走对话路径时格式约束通常更省事 |
| 适用任务 | 批量改写、摘要、翻译、起标题 | 多轮助手、客服机器人、角色设定 |
温度、上下文窗口、停止词、流式开关这些通用参数两边名字大体一致,但默认值和生效位置可能有差别。判断标准很简单:以你本地这版服务实际返回的字段为准,文档写什么只能当参考,拿一条真实请求试出来才算数。
按场景选:什么时候用哪个
选型其实不复杂,把问题换成「这次调用里有没有上下文需要延续」就行。有,就 chat;没有,就 generate。下面按几种典型场景给判断标准,同时说清什么情况下反过来选更合适。
- 多轮场景客服机器人、带系统提示的角色扮演、需要记住上一问的助手,直接用 chat。验证方法:连问两轮,看第二轮有没有用上第一轮的答案。
- 一次性任务批量改写、摘要、翻译、生成标题这类一次输入一次输出,用 generate。验证方法:同一条输入跑两遍,确认不依赖任何历史。
- 已有前端对接先看前端期望的是哪套返回结构,再决定接口,别先写服务端后改协议。验证方法:拿前端实际解析的字段名去比对返回体。
- 大批量任务上千条互不相关的任务里,每条都包一层只有一个元素的消息数组,只是白增体积和解析步骤,这种情况 generate 更干净。
反过来说,如果任务里偶尔需要带上一点上文,但主体还是批处理,别为了省事硬拆成两种接口混用,先把「哪些要历史、哪些不要」分出来,各自用合适的那个。
调不通时的排查顺序
调用失败时最容易犯的错是把几类问题混着查:字段取不到、历史丢了、流式解析报错、服务连不上,这四类原因完全不同。按下面的顺序走,每一步只验证一件事,别跳步。
- 第一步看返回体形状:拿到的是文本字段还是消息对象里的内容字段,字段对不上基本就是接口选错了
- 第二步看历史:从第二轮开始答非所问,多半是单轮那边没把上一轮拼进去,或者对话那边的消息顺序排错了
- 第三步看流式:开了流式却按整段 JSON 解析,会一直报解析错误,先关掉流式确认链路能通
- 第四步量延迟:先到 /tools/speed-test 拿一条自己的基线,再判断是模型本身慢还是调用方式慢
- 第五步才查服务和端口:连不上属于另一类问题,别和接口选型混在一起排查
这中间的延迟数字、模型快慢对比不要凭印象,到站内对应页面看当时的实测结果,比你自己拍脑袋靠谱。这样排查完,你至少能明确是「选错接口」还是「环境问题」。
已有代码要换接口时怎么改
换接口最怕的是改动面失控。稳妥做法是先把请求体和解析层各抽成一个函数,接口名只在一个地方出现,这样换的时候不用全文搜索,也不会漏掉某个角落里的旧调用。
抽完之后保留新旧两条路径的开关,用同一批输入各跑一遍,对比输出语义有没有变。确认没变化再删旧分支。注意对话路径会隐式带上整段历史,消耗随轮次增长;单轮路径要你自己控制拼多长,这决定了成本上限。
也不是所有情况都值得改。如果只是内部一次性脚本、不追求可维护性,硬改接口反而增加出错面,能跑完任务就行。判断标准是:这段代码还要不要被别人接手、还要不要跑很多次。
想进一步看清本地模型和各家官方接口在调用方式、能力边界上的差别,可以顺手把站内资料库过一遍,再决定哪些任务留在本地、哪些走外部接口。
下一步选型定下来之后,动手前先到站内模型资料库和目标服务页对一眼当前支持的字段与能力,避免写完代码才发现少了关键参数。→常见问题
localhost 上调 /api/generate 报 404,是接口没了吗?
先确认服务版本和路径前缀对不对,不同版本挂载的路由可能不一样。用官方仓库当版本文档来核对,或者直接拿一个已知能通的最小请求试。路径拼错(多一层或少一层)比接口被删更常见,先排这个。
chat 接口是不是就比 generate 高级,能全换过去吗?
不是谁替代谁。chat 多的是一层消息结构,适合多轮;纯单次补全任务用它只是把请求包大了一圈。全换过去一般不会出错,但复杂度上去了,收益不明显。按场景选,不要按新旧选。
多轮对话上下文在哪维护?
两个接口都不替你存历史。chat 需要你在客户端把之前的 user/assistant 消息按顺序拼进 messages 再发过去,generate 则需要你自己拼字符串。轮次多了要考虑长度上限和成本,别等报错才想起来裁剪。