LLM API 集成完全指南:从模型选型到流式输出的工程实践

把大模型接进产品,不是调通一个 SDK 就完了。本文从真实工程视角讲清模型选型、请求链路、重试与超时、流式响应、结构化输出、提示模板、观测与降本策略,帮你把 LLM API 集成做成稳定能力。

18 分钟阅读
小明

LLM API 集成完全指南:从模型选型到流式输出的工程实践

很多团队第一次做 AI 功能,路径都差不多:

  1. 申请一个模型 API Key
  2. 跑通一个 demo
  3. 聊天框里成功返回一句话
  4. 兴奋地说:“这不就接上了吗?”

真正上线以后,事情才开始变复杂。

你会很快遇到这些问题:

  • 模型偶尔很聪明,偶尔非常跑偏
  • 响应时延忽高忽低
  • 成本比预期高很多
  • 流式输出在前端体验上很丝滑,但服务端链路并不稳定
  • 同一个提示词,换个模型结果差一截
  • 明明只是“让 AI 帮我总结一下”,结果工程上要补一整套重试、限流、观测、fallback

这时候团队才会意识到:

把 LLM 接进产品,真正难的不是 first call,而是把它做成一个可运营、可观测、可迭代的能力。

这篇文章就从这个角度来讲。

不只是“怎么调用接口”,而是讲清楚:

  1. 模型怎么选,为什么不能只看排行榜
  2. 服务端如何封装统一 LLM Gateway
  3. 流式输出、结构化输出、提示模板该怎么落地
  4. 如何处理超时、重试、fallback、速率限制
  5. 怎样把一次“能跑通”变成“能上线”的工程系统

如果你准备把 AI 做进产品,这篇适合作为第一篇工程底稿。


一、先别急着写代码:你接的是“能力”,不是“模型”

很多团队集成 LLM 时,最先纠结的是:

  • 选 OpenAI 还是国产模型
  • 选大模型还是轻量模型
  • 选通用模型还是推理模型

这些问题都重要,但更本质的一层是:

你到底想把哪种 AI 能力接进产品?

因为“LLM API 集成”不是一个需求,而是一类需求的总称。常见至少有四类:

  1. 聊天对话
  2. 文本生成 / 总结 / 改写
  3. 结构化抽取
  4. Agent / 工具调用

这四类需求,对模型的要求完全不同。

1.1 一个常见误区:直接拿最强模型打所有场景

这会带来三个问题:

  • 成本高
  • 延迟高
  • 稳定性不一定最优

比如:

  • 简单分类和抽取,用轻量模型就够
  • 复杂长上下文推理,才值得上更强模型
  • 实时聊天对延迟敏感,可能优先选响应更快的模型

1.2 先画能力矩阵,再选模型

一个更靠谱的做法是先列矩阵:

场景目标关键指标模型要求
AI 客服初答快速、稳定首 token 延迟、成本速度优先
文档总结准确、结构清晰结果质量、长度控制指令遵循优先
信息抽取稳定 JSON结构正确率结构化能力优先
复杂问答推理完整正确率、上下文能力推理能力优先

先回答“要什么能力”,再谈“用哪个模型”。


二、模型选型:排行榜重要,但不是决策终点

2.1 选型时至少要看五个维度

维度为什么重要例子
质量决定结果是否可用回答准确率、幻觉率
时延决定产品体验首 token 时间、总耗时
成本决定是否能规模化输入输出 token 单价
稳定性决定能否上线限流、超时、成功率
能力特性决定能否满足场景function calling、JSON mode、长上下文

2.2 不同场景适合不同模型层级

很多成熟产品会形成一个模型分层:

  • 默认模型:覆盖 80% 常规请求
  • 高质量模型:用于复杂任务或高价值用户
  • 兜底模型:在主模型异常时保证可用性

这比“All in 一个最强模型”更稳,也更省钱。

2.3 一个简单的选型策略

先定义业务场景
用同一套评测样本比质量
测真实首 token 和总响应时延
估算单位请求成本
再决定默认模型 + fallback 模型

如果没有自己的评测集,只看公开 benchmark,很容易选到“比赛成绩好、实际产品体验一般”的模型。


三、统一 LLM Gateway:不要让业务代码到处直接调模型

这是 AI 集成里非常重要的一步。

如果每个业务团队都直接在代码里写:

  • provider SDK 调用
  • prompt 拼接
  • token 统计
  • 重试和超时
  • 日志埋点

那么三个月后,整个仓库会充满“各自写了一套”的 AI 调用逻辑。

3.1 为什么需要统一网关层

统一 LLM Gateway 可以收口:

  • 模型路由
  • 密钥管理
  • 超时与重试
  • 流式响应封装
  • token 统计
  • 结果审计与观测
  • fallback 策略

3.2 一个简化示例

type LLMRequest = {
  task: 'chat' | 'summary' | 'extract'
  messages: Array<{ role: 'system' | 'user' | 'assistant'; content: string }>
  stream?: boolean
  temperature?: number
  responseFormat?: 'text' | 'json'
}

type LLMResponse = {
  content: string
  model: string
  usage?: {
    promptTokens: number
    completionTokens: number
  }
}

export async function callLLM(input: LLMRequest): Promise<LLMResponse> {
  const provider = routeModel(input)
  const timeoutMs = input.task === 'chat' ? 12_000 : 20_000

  return withRetry(
    () => provider.generate(input, timeoutMs),
    { retries: 2, backoffMs: 500 },
  )
}

这样业务层只需要表达“我要什么能力”,而不需要知道底层到底接的是哪个模型、哪个平台。


四、Prompt 不是字符串,而是产品接口的一部分

很多人写 prompt 的方式很像写注释:想到什么就往里塞一点。

这在 demo 阶段没问题,到产品阶段会出两个严重问题:

  1. prompt 版本不可追踪
  2. 不同团队各自魔改,结果质量不可控

4.1 建议把 prompt 模板显式版本化

export const SUMMARY_PROMPT_V3 = `
你是一个面向普通用户的内容总结助手。
请遵守以下规则:
1. 输出 3 条要点
2. 每条不超过 40 字
3. 不要编造原文没有的信息
4. 最终输出 JSON:{"bullets": string[]}
`

4.2 为什么 prompt 要版本化

因为它已经不是“临时文案”,而是决定结果质量的接口契约。

当你要评估:

  • 为什么今天效果变差了
  • 为什么某个 A/B 桶表现不同
  • 为什么某些用户投诉答案跑偏

没有 prompt 版本和调用记录,你很难定位。

4.3 Prompt 设计的一个务实原则

不要让一个 prompt 同时承担太多目标。

例如:

  • 既要总结
  • 又要风格化
  • 还要抽取结构化字段
  • 顺便再生成标题和摘要

任务越杂,稳定性越差。工程上更稳的方式是拆任务


五、结构化输出:比“写一段漂亮文字”更值钱

对真实产品来说,很多最有商业价值的场景不是聊天,而是:

  • 从工单里抽意图
  • 从简历里抽结构化字段
  • 从用户问题里抽分类和优先级
  • 从长文里抽标题、摘要、标签

这类场景最重要的不是“文字优美”,而是“结果结构稳定”。

5.1 一个 JSON 输出示例

const request = {
  task: 'extract',
  responseFormat: 'json',
  messages: [
    {
      role: 'system',
      content: '你是信息抽取助手,只输出 JSON。',
    },
    {
      role: 'user',
      content: '帮我从这段投诉文本中提取问题类型、紧急程度和是否涉及退款。',
    },
  ],
}

5.2 工程上还要做 schema 校验

不要因为模型说“我会输出 JSON”,就相信它一定稳定。

更稳的做法是:

import { z } from 'zod'

const TicketSchema = z.object({
  issueType: z.string(),
  priority: z.enum(['low', 'medium', 'high']),
  refundRelated: z.boolean(),
})

export function parseTicketResult(raw: string) {
  const parsed = JSON.parse(raw)
  return TicketSchema.parse(parsed)
}

这样做的价值非常大:

  • 能快速识别异常输出
  • 能做 fallback
  • 能做统计,知道结构正确率到底是多少

六、流式响应:体验很香,但链路要先稳

流式输出是很多 AI 产品体验的关键。用户看到文本一边生成,会明显感觉“系统在工作”。

6.1 流式为什么值钱

因为它改善的不是总耗时,而是感知等待时间

一个 8 秒总响应的请求:

  • 如果 8 秒后一次性返回,体验很差
  • 如果 800ms 后开始持续出字,用户容忍度会高很多

6.2 一个 SSE 示例

export async function streamChat(req, res) {
  res.setHeader('Content-Type', 'text/event-stream')
  res.setHeader('Cache-Control', 'no-cache')
  res.setHeader('Connection', 'keep-alive')

  for await (const chunk of llmProvider.stream(req.body.messages)) {
    res.write(`data: ${JSON.stringify({ delta: chunk })}\n\n`)
  }

  res.write('event: done\ndata: {}\n\n')
  res.end()
}

6.3 流式集成的三个真实坑

  1. 中途断流后前端如何恢复状态
  2. 网关、代理、CDN 是否支持长连接流式透传
  3. 如果模型侧超时,用户看到的是“停住了”还是明确失败

所以流式响应不只是前端效果,而是全链路兼容性问题。


七、超时、重试、fallback:AI 不稳定是常态,不是例外

这点必须讲清楚。

LLM API 和传统内部 RPC 最大不同之一,就是:

  • 结果不完全确定
  • 延迟波动更大
  • provider 配额和限流更明显
  • 某些失败并不是代码 bug,而是平台抖动

7.1 重试不能无脑做

如果一个请求:

  • 已经很贵
  • 已经很慢
  • 失败原因是配额或参数问题

无脑重试只会更贵、更慢。

7.2 更合理的策略

场景策略
网络抖动 / 短暂 5xx可有限重试
参数错误 / schema 错误不重试,直接修输入
超时看业务场景,必要时降级
配额限制排队、限流或切换备用模型

7.3 一个 fallback 示例

export async function generateSummary(text: string) {
  try {
    return await callLLM({
      task: 'summary',
      messages: [{ role: 'user', content: text }],
    })
  } catch {
    return await callBackupModel({
      task: 'summary',
      messages: [{ role: 'user', content: text }],
    })
  }
}

fallback 的目标不是保证“完全同质量”,而是保证核心能力不要整体失效。


八、观测体系:如果你看不见 token、时延和失败原因,就不算真正接入完成

很多团队接好后,只有“成功 / 失败”日志。

这远远不够。

8.1 至少应该记录这些指标

指标作用
请求量看使用规模
首 token 延迟看体验
总响应时间看吞吐与稳定性
prompt tokens / completion tokens看成本
结构化输出成功率看结果稳定性
provider 错误码看失败类型
fallback 触发率看主模型健康度

8.2 为什么这组指标很关键

因为 AI 产品优化时,很多问题不能只凭体感判断。

例如:

  • 为什么最近费用变高了
  • 为什么某个功能感觉更慢
  • 为什么结构化结果出错更多
  • 为什么用户抱怨“经常卡住”

这些都需要量化观察。


九、把 LLM 接到生产系统里,还需要哪些工程补丁

9.1 内容审查与安全兜底

即使不做复杂 AI 安全,至少也要:

  • 对输入长度做限制
  • 对输出做基础审查
  • 对敏感业务场景做兜底文案

9.2 会话上下文管理

上下文越长,成本越高,响应越慢。

所以要考虑:

  • 历史消息裁剪
  • 摘要压缩
  • 系统提示与用户消息分离

9.3 可回放的调试能力

遇到线上异常时,你最好能回放:

  • 用了哪个模型
  • 哪个 prompt 版本
  • 输入大概是什么
  • token 用量如何
  • 为什么 fallback 了

没有这些信息,AI 问题会比普通接口问题更难定位。


十、一个团队级的接入顺序建议

第 1 步:先选一个低风险场景上线

比如:

  • 文本总结
  • 标签生成
  • FAQ 初稿

不要一上来就把 LLM 放进最核心、最严格实时的链路。

第 2 步:统一调用层

不要让业务各自直连 provider。

第 3 步:补结构化输出和校验

这一步能把 AI 功能从“看起来能用”升级到“系统能消费”。

第 4 步:补流式体验和 fallback

让体验和稳定性一起提升。

第 5 步:把观测和成本统计纳入日常看板

否则你永远只能靠投诉发现问题。


十一、给团队的 LLM API 集成检查清单

模型与场景层

  • 是否先定义能力场景,再决定模型
  • 是否有默认模型和备用模型
  • 是否用自有样本做过评测

接入层

  • 是否有统一 LLM Gateway
  • 是否统一处理超时、重试、fallback
  • 是否支持流式与非流式两种模式

输出层

  • 是否对结构化输出做 schema 校验
  • 是否对 prompt 版本化管理
  • 是否能追踪模型、prompt、结果与错误

运营层

  • 是否监控 token 成本和时延
  • 是否有限流和配额策略
  • 是否有异常兜底和降级预案

总结

把 LLM API 集成讲透,可以收敛成 5 句话:

  1. 你接入的不是某个模型,而是一种产品能力。
  2. 模型选型要同时看质量、时延、成本和稳定性。
  3. 统一 Gateway 比每个业务自己直连 provider 更重要。
  4. 结构化输出、流式响应、fallback 和观测,决定它能不能上线。
  5. AI 集成的终点不是“能回答”,而是“可控、可测、可迭代”。

如果你只记住一句话,我希望是这一句:

一个真正能落地的 LLM 集成,不是把模型接进代码,而是把不确定性关进系统边界里。

否则 demo 一跑很惊艳,上线之后最先学会的通常不是智能,而是——

超时。