大模型应用开发模式:从 Prompt 到 Agent
大模型应用开发并非只有一条路:从最简单的直接调用,到精心设计的提示工程,再到检索增强(RAG)和自主规划的 Agent,每一层都是前一层的自然延伸。读完本文,你将清楚每种模式的适用边界,以及让它在生产环境跑稳的工程化要点。
四种模式演进
模式一:直接调用
最小化路径——把用户输入直接发给模型,拿回输出。
# OpenAI 兼容写法(适用大多数国内外提供商)
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": user_input}]
)
适用场景:原型验证、一次性脚本、内部小工具,需求清晰且输出格式要求低。
局限:对话语境不连贯、模型能力全靠默认行为、没有领域知识注入。
这段代码看着简单,但线上跑起来第一个坑往往不是模型不听话,而是这几个具体报错。你多半会在日志里见到:
- 401 Unauthorized:不是 key 写错了这么简单,更常见的是 key 有效但没开通对应模型的权限,或者渠道方把这个 key 限定在了某个 IP 白名单。排查顺序:先拿同一个 key 在官方控制台的调试面板发一次同样的请求,能通就说明是你这边环境变量传错了(最常见:本地
.env生效,线上容器没挂载)。 - 429 Too Many Requests:分两种,一种是 QPS 超限(短时间并发太高),一种是当月配额用完。响应头里通常带
retry-after,别自己瞎猜等待时间,直接读这个字段。 - 超时(504 / 连接被重置):直接调用模式下最容易忽略的是”模型在思考,但你的 HTTP 客户端等不及了”。默认的
requests库超时是不设上限的,但很多网关或反向代理会在 30 秒左右主动切断连接——这不是模型的问题,是链路中间的某一跳。定位方法:把请求超时显式设到 90 秒以上,如果还超时再看是不是该换流式输出(见下文工程化要点第 1 条)。 - 编码问题:中文输入偶发乱码,十有八九是请求体没有显式指定
Content-Type: application/json; charset=utf-8,或者你在 Windows 环境下用了 GBK 默认编码读文件。养成习惯,所有和大模型交互的文件 IO 都显式encoding="utf-8"。
这几类报错记熟了,能省下你后面无数次”是不是模型抽风了”的排查时间——十次里九次不是模型的锅。
模式二:提示工程
在直接调用基础上,精心设计 system prompt 和 few-shot 示例,把业务规则、输出格式、语气风格”烤”进请求里。
system: |
你是一名客服助理,只回答订单相关问题。
输出必须是 JSON: {"answer": "...", "confidence": 0.0~1.0}
若无法回答,返回 {"answer": null, "confidence": 0}
适用场景:输出格式标准化、角色限定、减少幻觉、多语言适配。
局限:上下文窗口有限,塞不进所有知识;动态数据无法实时更新。
有个细节很多人踩过坑:few-shot 示例的顺序和数量会实实在在影响输出质量,不是摆设。模型对 prompt 里最后出现的示例权重更高(近因效应),所以如果你的示例里有难易区分,一定把最贴近真实场景、最典型的那个放在最后一条,而不是按时间顺序或字母顺序随便排。示例数量也不是越多越好——超过 58 条之后,边际收益迅速下降,反而会挤占本该留给用户输入的上下文空间,还会拉高每次调用的 token 成本。实践下来,35 条精心挑选、覆盖不同边界情况的示例,效果通常好于 10 条同质化的示例。
另一个容易被忽略的取舍:system prompt 该写多长?写得太短,模型容易”自由发挥”跑出你不想要的格式;写得太长(比如塞进几百字的业务规则),会稀释模型对当前用户问题的注意力,实测中常见的现象是模型开始”背规则”而不是”解决问题”。一个可落地的经验值是:system prompt 控制在 200~400 字之间,规则用编号列表而不是大段散文,格式要求单独成段并加粗标出,这样模型解析起来命中率明显更高。
详见 提示工程实用技巧。
模式三:RAG(检索增强生成)
把”外部知识库”变成模型的动态上下文:先把问题转成向量,检索最相关的文档片段,再拼进 prompt 让模型”看着资料”回答。
用户问题 → embedding → 向量检索 → Top-K 文档 → 拼上下文 → LLM 生成
适用场景:企业知识库问答、文档搜索、长尾知识覆盖、需要引用来源。
局限:检索质量决定生成质量;需要维护向量数据库和嵌入索引。
RAG 落地时最容易卡壳的两个参数是 chunk 大小和 Top-K 取值,这两个数字没有放之四海而皆准的答案,得按场景权衡:
| 场景 | chunk 建议 | Top-K 建议 | 理由 |
|---|---|---|---|
| 法律/合同条款 | 小(200~400 字) | 较大(8~10) | 条款粒度细,切太大会把不相关条款混进同一片段 |
| 产品说明文档 | 中(500~800 字) | 中(3~5) | 段落本身是语义单元,切太碎会丢失上下文 |
| 长篇技术手册 | 大(800~1200 字)+ 重叠 100 字 | 中(3~5) | 需要保留跨段落的推理链条,重叠可以缓解切断问题 |
这里的重叠(overlap)经常被新手忽略:如果 chunk 之间完全不重叠,恰好卡在句子中间切断的内容,检索时两边都拿不全。一般建议重叠区间取 chunk 长度的 10%~15%。
另一个真实会遇到的现象是”检索到了但没用上”——你把 Top-5 文档片段都拼进了 prompt,但模型的回答完全没有引用这些内容,或者答非所问。这通常不是模型的问题,而是检索排序不对:语义相似度最高的片段未必是回答问题最需要的片段。这时候可以在向量检索后面加一层重排序(rerank),用专门的重排模型对候选片段按”与问题的相关性”重新打分,往往能明显改善这个问题。
详见 RAG 怎么做:架构与落地。
模式四:Agent
给模型配备工具(搜索、代码执行、API 调用),让它自主规划多步任务,通过 ReAct(Reasoning + Acting)循环完成目标。
任务 → 思考(Thought)→ 行动(Action: 调用工具)→ 观察(Observation)→ 思考…→ 最终回答
适用场景:复杂多步任务、需要访问实时数据、自动化工作流、跨系统操作。
局限:延迟高、成本高、调试难;需要精心设计工具描述和错误恢复机制。
Agent 上线前一定要自己动手跑几十轮,你会发现 ReAct 循环最常见的三种翻车方式:
- 工具描述写得太模糊:比如把一个查天气的工具描述成”获取相关信息”,模型很可能在该调用它的时候不调用,或者在不该调用的时候瞎调用。工具描述要像写 API 文档一样精确——参数含义、返回格式、什么情况下会报错,都要写清楚,模型是根据这段描述”猜”什么时候该用它。
- 无限循环:模型反复思考、反复调用同一个工具却拿不到有效结果,陷入死循环。必须设置最大步数上限(比如 8~10 步),超过就强制终止并返回”任务未完成,原因是……”,而不是让它无休止地烧 token。
- 观察结果塞得太满:工具返回的原始数据(比如一整页 API 响应 JSON)不做裁剪直接塞回上下文,几轮循环下来上下文就爆了,触发 context 超限报错。做法是只把工具返回结果里模型真正需要的字段摘出来再拼回去。
调试 Agent 最有效的手段不是盯着最终答案看,而是把完整的思考-行动-观察轨迹打印出来逐步复盘,问题基本都出在中间某一步的工具调用参数或者描述上,而不是模型”变笨了”。
详见 AI Agent 开发实战。
模式选型对比
| 维度 | 直接调用 | 提示工程 | RAG | Agent |
|---|---|---|---|---|
| 实现复杂度 | 低 | 低~中 | 中 | 高 |
| 延迟 | 低 | 低 | 中 | 高 |
| 知识时效性 | 模型截止日 | 模型截止日 | 实时 | 实时 |
| 适合数据量 | 无需外部数据 | 少量(塞进 prompt) | 大规模文档库 | 动态多源 |
| 可解释性 | 低 | 中 | 高(有来源) | 中(有轨迹) |
| 推荐起点 | MVP 验证 | 产品初版 | 知识密集型产品 | 自动化任务 |
工程化要点
无论选哪种模式,生产环境都绕不开以下四个工程层。
1. 流式输出(Streaming)
对话类产品首字延迟超过 2 秒用户会流失,流式是必选项。
stream = client.chat.completions.create(
model="gpt-4o-mini",
messages=messages,
stream=True
)
for chunk in stream:
delta = chunk.choices[0].delta.content or ""
print(delta, end="", flush=True)
注意:流式场景下需要在前端做 SSE 或 WebSocket 接收,并处理中断重连。
2. 兜底与重试
模型 API 不保证 100% 可用,特别是高并发时。建议:
- 自动重试:指数退避,最多 3 次,区分可重试错误(429/503)和不可重试错误(400)。
- 降级模型:主模型失败时切换到更小、更稳定的备用模型。
- 超时保护:设定单次请求超时(建议 30~60 秒),防止长尾请求拖垮服务。
import tenacity
@tenacity.retry(
wait=tenacity.wait_exponential(min=1, max=10),
stop=tenacity.stop_after_attempt(3),
retry=tenacity.retry_if_exception_type(openai.RateLimitError)
)
def call_llm(messages):
return client.chat.completions.create(model="gpt-4o-mini", messages=messages)
3. 语义缓存
相同或高度相似的问题重复调用模型是资源浪费。可以用:
- 精确缓存:对 prompt hash 做 KV 缓存,命中时直接返回。
- 语义缓存:将问题向量化,相似度超过阈值时复用缓存答案(适合 FAQ 场景)。
语义缓存可降低 30%~60% 的 API 调用量,成本收益显著。
4. 评测体系
“感觉还不错”不是生产标准,需要可量化的评测:
| 评测维度 | 常用方法 |
|---|---|
| 回答正确性 | 黄金答案对比(人工标注集) |
| 幻觉率 | LLM-as-Judge(用强模型判断) |
| 检索召回率 | RAG 专用:Hit Rate / MRR |
| 延迟与成本 | 日志统计 P50/P95/P99 |
| 用户满意度 | 点赞点踩、人工抽查 |
建议从小规模人工评测开始,逐步建立自动化 CI 评测管线。
常见问题
从哪个模式开始比较合适? 先用提示工程跑通最小可用产品(MVP),验证用户价值后,若遇到知识覆盖不足就引入 RAG,若遇到多步任务需求就引入 Agent。避免一开始就过度设计。
RAG 和微调(Fine-tuning)怎么选? RAG 适合知识频繁更新、数据量大、需要引用来源的场景;微调适合固定风格/格式、推理模式定制。二者可以组合:先 RAG,对齐输出风格再微调。
Agent 延迟太高怎么优化? 拆解任务步骤,能并行的工具调用并行执行;对高频子任务做结果缓存;对低延迟要求的环节换用小模型;设计合理的任务中止条件,避免无限循环。
如何管理多模型供应商的接入成本? 统一用 OpenAI 兼容接口抽象,通过聚合 API 层(如 力达云 /waitlist/)统一调度,自动路由到性价比最优的模型,降低供应商锁定风险。
← 进入 应用模式专题 查看全部文章
相关阅读:RAG 怎么做:架构与落地 · AI Agent 开发实战 · 提示工程实用技巧