最近一个做企业知识库项目的朋友跟我聊起“大模型应用开发”,他说手底下的人已经会调 API 了,但真正要把大模型接进业务里跑起来,又说不上来到底难在哪。这个问题其实很有代表性。很多人把大模型应用开发理解成“调用 OpenAI 接口 + 写 Prompt”,结果一进真实场景就翻车:线上效果不稳定、成本失控、输出格式一塌糊涂、知识库检索质量忽高忽低……我折腾大模型应用落地也有一年多了,踩过不少坑,今天干脆把整个思路掰开揉碎讲一遍。
这篇内容不是教你跑通一个 Hello World,而是针对“如何基于大模型构建一个真正的应用”这件事,分享一套可以复用的设计思路和实操细节。无论你是在做客服机器人、文档问答、代码助手、智能写作工具,还是内部知识库,基本都逃不开这里面的几个核心环节:路径选型、Prompt 工程、RAG 知识库增强、工程化部署与成本控制。我会把每一步怎么做、为什么这么做、坑在哪都写清楚,尽量让有 Python 基础、对大模型有初步概念的人看完就能上手。
1. 别急着写代码:先想清楚你的应用走哪条技术路线
1.1 API优先还是开源模型私有化,不是一道选择题
很多人一上来就纠结“到底用 ChatGPT 的 API 还是用开源模型私有部署”,这个问题其实没有标准答案,取决于你的业务场景、数据敏感度和成本模型。
如果你是做一个面向公众的通用工具,比如写作助手、文案生成器、代码补全插件,数据不需要保密,那么 API 优先是最省力的方案。API 的模型能力通常最强,迭代也最快,今天别人还在本地调参,你已经接上了更新版本,效果差距一眼就能看出来。
但如果你做的是企业内部系统,尤其涉及客户资料、财务数据、人员信息、内部制度文档,那么数据出不出企业边界就成了一个大问题。我之前接过一个某公司的内部知识库项目,技术方案讨论阶段,对方明确要求所有文本处理必须在内网完成,训练数据和推理数据一律不得外传。这种情况下,即使 API 效果再好,也只能放弃,选择开源模型做私有化部署。
这里有个很简单实用的判断清单:
- 有没有硬性的数据合规要求?有,直接考虑私有化。
- 业务是否依赖实时更新的大模型能力?是,优先 API。
- 团队有没有 GPU 资源和模型运维能力?没有,别选私有化,省的难受。
- 调用量有没有预估?每月超过一定量级,私有化的硬件成本可能反而比 API 划算。
实际项目里,我还见过不少“混搭”的玩法:核心逻辑用开源小模型跑,复杂场景再调用大模型 API 兜底。这个思路适合预算有限但又想保证体验的团队,后面写工程化时我再细讲。
1.2 为什么我劝你别一上来就搞微调
大模型应用开发领域有一个非常常见的歪路——业务方刚提完需求,马上有人跳出来说“这不得微调一下模型?”每次听到这个我都头大。微调不是万能解药,它是成本最高、周期最长、风险最大的技术手段之一。
微调的本质是改变模型的权重,让它在一个特定任务上表现得更好。但大部分业务场景其实不需要改变模型本身的“智商”,只需要控制它的“说话方式和行为边界”,这时候 Prompt 和 RAG 就能解决。举个例子,你想让模型扮演客服,用热情礼貌的口吻回答用户,这不是微调的事,而是 Prompt 设计和示例引导的事。你想让它回答公司制度问题,得把制度文档喂给它去找答案,这是 RAG 的事。只有当你希望模型学会某种知识或某种推理模式,并且这种能力无法通过 Prompt 描述清楚时,才轮到微调登场。
微调还有什么问题?数据准备成本极高。你得整理几百上千条高质量的“输入-输出”对,找人工标注,做质量清洗,这本身就是一个项目级的工程量。而且微调后模型的通用能力可能出现衰退,也就是所谓的“灾难性遗忘”,你需要持续评测验证。所以我的建议是:先做 RAG + Prompt,把流程跑通再做微调,微调是优化手段,不是起步方案。
1.3 用“外包员工”的思维理解大模型集成
我经常给团队讲一个比喻:大模型就像一个每周入职的新员工,能力很强但记性差、情绪不稳定、容易一本正经地胡说八道。你把它接入应用时,最核心的任务不是“培训它”(微调),而是给它配一个足够清晰的“工作手册”(Prompt),外加一个可以随手翻阅的“公司资料库”(RAG)。
这个比喻极其好用。当业务方来跟你提需求时,你一听就知道他想让你“怎么带这个新员工”——是规范行为(Prompt 方向)、补充资料(RAG 方向),还是系统性训练(微调方向)。有了这层判断,后面所有方案都顺了。等你自己动手开发时,也尽量用这种“人岗匹配”的眼光去看待每一次调用,你会发现很多配置细节的选择其实都是有逻辑依据的。
2. 提示词工程:大模型应用的“第一道质量大门”
2.1 先给 Prompt 建立一套可复用的骨架
看过太多把 Prompt 随手写在代码拼串里的项目,效果一崩,谁都讲不清是业务逻辑的问题、数据的问题还是 Prompt 的问题。做过一段时间之后我养成了一个习惯:把每个业务场景的 Prompt 当作独立的模板文件来维护,结构化、参数化、版本化。
一个合格的 Prompt 至少应该包含四个部分:
- 角色定义:你是谁,用什么视角、什么语气回答用户。
- 任务描述:你要做什么,边界在哪里,不要做什么。
- 上下文输入:用户的提问、相关的知识库检索结果、必要时附带的对话历史。
- 输出约束:格式要求、长度要求、语气要求、禁忌事项。
例如我做过一个内部制度问答助手,它的 Prompt 大致是这样的:
你是一位企业内部知识库问答助手,服务对象是普通员工。 你只能根据提供的资料回答问题,资料中找不到答案时, 请直接回复“该问题在公司制度中未找到明确说明”, 禁止编造内容,禁止使用与资料无关的知识,不要在回答中提及参考资料的存在。 回答时使用简洁、准确、友好的中文书面语。这段 Prompt 不长,但几个关键约束都明确了:资料范围、知识边界、幻觉兜底、回答风格。很多效果问题排查到最后,往往就是 Prompt 里少了一句“不许胡编”。
注意,角色设定不是迷信。模型并不真的“理解”角色,它只是通过语言分布更倾向于某种风格。但你却可以使用角色定义来稳定输出语气的变化范围。比如同样问“这个制度什么时候生效”,你定义成“严谨的档案管理员”和“热情的客服专员”,输出的差异肉眼可见。这里没有玄学,就是概率分布的偏移。
2.2 Few-shot示例:让输出格式稳定下来的可靠手段
光在 Prompt 里说“用 JSON 格式回答”,模型很容易在不同的 JSON 结构之间横跳。我最早做数据抽取工具时深有体会:Prompt 里写“输出一个 JSON 对象,包含姓名、工号、部门”,模型有时返回{"姓名":"张三", "工号":"123", "部门":"技术部"},有时返回[{"name":"张三", "emp_id":"123", "dept":"技术部"}],解析代码根本没法写稳。
后来我给每个输出场景都塞了至少两个带正确格式的示例(Few-shot),输出稳定性一下子提升很多。示例的作用不是“教育”模型,而是给它提供一个最接近预期的答案分布中心。模型在生成时本质上是在做“下一个 token 的猜测”,你给它的示例如果格式统一、字段一致,它就会沿着这个轨道走。
一个典型做法是在 Prompt 的末尾追加:
请按以下格式输出: {"name": "张三", "department": "技术部", "hire_date": "2022-03-01"}同时限定:“必须是无修饰的纯 JSON,不要包含 markdown 的代码块标记”。这两条合起来,基本能解决 90% 的输出解析问题。
2.3 给模型“递工具”:使用函数调用和结构化输出
当你的应用不只是让大模型回答问题,而是让它参与一个自动化流程时,比如让模型判断一个订单消息该转给售后还是运营,或者从一段周报里提取关键数据写入系统,那你就需要 Function Calling 或工具调用来完成“大模型 + 后端动作”的闭环。
拿一个典型场景说:我做过一个工单自动分类系统,功能是根据用户描述自动判断工单类型、优先级和负责人。实现思路是大模型不直接输出一堆人话,而是输出一段结构化的调用参数,后端拿到了之后再去执行工单系统的 API。这样做的好处是,模型只负责它最擅长的“理解和抽象”,建立路由、触发任务、回写系统这类确定性逻辑仍然掌握在代码手里。
我当时配置的函数描述大概是这样的:
{ "name": "create_work_order", "description": "根据用户问题创建一条工单记录", "parameters": { "type": "object", "properties": { "category": {"type": "string", "enum": ["网络故障", "账号问题", "权限申请", "其他"]}, "priority": {"type": "string", "enum": ["低", "中", "高"]}, "summary": {"type": "string", "description": "问题概述,不超过20个字"} }, "required": ["category", "priority", "summary"] } }光是把函数定义写得足够细还不够,真正麻烦的是边界场景。比如用户说了“我的账号登不上去了”,模型应该把 category 变成“账号问题”,但很多模型会犹豫是“网络故障”还是“账号问题”,这时候就需要你在函数描述里把每个枚举的边界写清楚,甚至加一个“当拿不准时优先选择‘其他’”的兜底策略。
2.4 对话历史管理和上下文压缩
对话类应用做多了你会发现,上下文窗口不是越大越好。一方面长上下文意味着高成本和高延迟,另一方面模型面对大量历史文本时,注意力会被无关信息稀释,反而抓不住当前最关键的内容。
我处理方案是分级管理:短期记忆(最近几轮对话)全部保留,中期记忆做摘要压缩,长期记忆只保留结构化用户画像。比如一个客服机器人,用户最早聊了十轮关于发票的事情,五天后回来问“之前那个发票申请怎么还没到账”,模型如果只能看到最近两轮对话,它是想不起来上下文的。但如果把十轮对话全部塞进去,又太浪费。我的办法是每轮对话结束后,异步调用模型把关键信息抽成摘要存储在会话记录里,下次需要时把摘要作为上下文注入。
这个方案的工程复杂度不低,但收益非常明显。一个客服系统每天几万轮对话,如果每次请求都把历史上所有消息带上,光是 token 费用就让人头大。做摘要压缩之后,单次请求的上下文可以压缩到原来的十分之一,响应时间也能明显降下来。
3. RAG知识库:给大模型配一个“查得到、拿得准”的资料库
3.1 大模型是健忘的大厨,RAG才是菜谱架
纯靠大模型自身的记忆做知识问答有一个致命问题:它并不知道你的企业制度、产品手册、内部流程。你往里问“咱们公司年假制度是什么”,它能给你编出一堆看似合理但完全不对的内容。这就是大模型的幻觉问题,本质上是因为它是语言模型,不是数据库。
RAG(检索增强生成)的思路是:把知识文档提前切好、向量化、存起来;用户提问时先去知识库里检索相关段落,再让模型基于这些段落“照本宣科”。我不止一次说过,RAG 是当前企业级大模型应用里性价比最高的技术路径,它绕开了微调的高成本,也能让答案来源可追溯。
但不是你把文档往向量数据库里一扔就能万事大吉。RAG 效果的好坏,很大程度取决于前面的“文档处理”和“检索排序”两个环节。很多人栽就栽在“文档不处理直接灌”。
3.2 文档切分:比你想得更讲究,也更容易被忽略
文档切分听起来简单,实际是最容易做出巨大差异的环节。切太小,检索出来的片段内容孤立;切太大,噪音太多,模型抓不住重点。我常用一个办法:先按结构切,再按大小调,最后加重叠。
具体来说,如果一个文档有标题层级,就优先以“二级标题”为界限切开整个区块。不要从文章中间硬切,那是下下策。然后根据模型上下文窗口的预算来评估每个区块的大小。对中文文本,我一般把基础块控制在 300~500 字左右,重叠设为 50~100 字。这样既能保证每个块有足够上下文,又能避免检索时刚好把一个完整语义切断。
这里有一个非常容易踩的坑——表格和排版。直接解析 PDF 拿到的表格,切碎之后完全没法看,甚至会把表头和数据拆到两个块里。我的解决办法是:保留 Markdown 格式,把表格转成 Markdown 表格再切开;如果工具不支持表格转换,干脆把表格单独成块,检索到表格时整体返回。
还有一类很常见的问题是“父子分块”。即父块切得比较大(比如整个章节),子块切得比较小(比如 400 字),检索时用子块去匹配,返回时带上父块的完整内容。这个方案我在实际项目里用下来效果很好,因为有时候用户问的问题,答案可能跨越了子块边界,但光靠小块的向量匹配找不到;带上父块后,模型能看到完整章节,答案质量明显提升。
3.3 Embedding选型:不要迷信“大模型级”的向量模型
Embedding 模型的选择直接决定了检索质量。很多项目组上来就追求又大又新的模型,却忽略了最核心的问题:你的数据和模型训练数据的分布是否一致。
我建议初选时跑一个不超过 20 条真实问题的评测集,人工标注标准答案来自哪一段,然后对比两三个候选 Embedding 模型的命中率。不要只看理论指标,真实业务上的小数据评测远比榜单数据有意义。
另外一个细节是:查询(Query)和文档(Document)是否应该用同一个 Embedding 模型?我的经验是,绝大部分开箱即用的方案里,用同一个模型就好;但如果你发现检索效果不好,可以试试分开处理,有些向量模型专门为 Query 优化过。不过这会增加系统复杂度,不是第一优先级。
3.4 检索结果排序:不要盲信相似度分数
默认的向量检索逻辑是“语义最相似”,但语义相似不等于答案相关。一个特别常见的例子:用户问“年假可以累计到下一年吗”,检索出来的最相似内容是“年假不可以转让给他人”,这句话和问题表面语义很像,但根本回答不了用户的问题。
我会在检索环节加一道重排序步骤。也就是第一轮向量检索先召回 Top50 个候选块,再用一个轻量级重排序模型(或者让大模型对候选块逐个打分)挑出最相关的 Top5 交给最终回答。有了这一层,检索质量的稳定性会有质的提升。
另外建议把“标题、章节名、关键词”一起参与向量检索,不是只对正文向量化。我以前踩过坑,正文太相似但主题完全不是用户问的那个方向。加上标题信息后,模型能够获得更多定位提示。
3.5 混合检索与知识库效果评估
不做不知道,一测吓一跳。混合检索在很多真实场景下能补齐纯向量检索的短板。所谓混合检索就是“向量语义检索 + 关键词检索”结合,然后再汇总排序。中文场景里,企业文档常常包含大量专有名词和编号,比如“文档编号:HR-2024-01”,用户搜索“人力资源管理制度的文档编号”时,纯向量检索很难精确匹配编号,而关键词检索对这种场景几乎是秒级命中。我的标准配置是:关键词检索占比 30%,向量检索占比 70%,这个比例可以根据业务微调。
关于效果评估,我强烈建议每周固定用一套“金标本”做回归测试。我自己的做法是维护一个测试集合,里面包括 50 组问题和对应的标准答案来源,每次改完切分策略、检索策略或 Prompt 之后,都跑一遍看整体效果是变好还是变差。没有这套评估集,你所有优化都会变成“凭感觉调参”,出了问题也不知道是哪一步引入的。
4. 从Demo到上线:大模型应用的工程化才是真正的分水岭
4.1 线下能跑、线上崩:大模型的工程化需要降维思维
很多人把大模型应用开发理解为“接口调通了、Demo 能对话了、项目就算完了”,等到真实上线后才发现一堆工程问题:并发一上来延迟就飙升,流式输出中断,超时引发的错误提示满天飞,模型偶发不按格式输出导致业务流程直接卡死。
我总结过一套工程化清单,线上部署前至少过一遍:
- 所有外部依赖都要设超时时间和重试机制,尤其是大模型服务。
- 异步化:耗时的调用不要卡在同步链路里。
- 模型输出要做格式校验,不是把模型返回直接塞给前端就完事。
- 重要的调用路径上要有兜底逻辑,比如模型超时后降级为人工流程或固定回复。
- 对 token 用量做监控,防止某个用户刷爆你的账单。
拿一个具体例子说,我有个在线写作助手项目,用户点“生成摘要”,模型如果回了一个不完整 JSON,前端就直接白屏。后来我在后端包里加了解析异常捕获和重试逻辑:第一次解析失败就自动追加一条 Prompt “确保输出纯 JSON 格式”再请求一次;连续失败两次则返回固定兜底文案并记录日志。这一条逻辑,把线上异常率从 5% 降到了以下。
4.2 流式输出:体验提升的核心,也是最容易踩坑的环节
流式输出(Streaming)现在几乎是对话类应用的标配。效果就是用户看到字一个一个蹦出来,而不是等十几秒然后整页出现。体验上确实提升明显,但工程上它带来了一堆新问题。
首先是超时问题。流式接口如果前端和后端的超时时间配置得不一致,用户会看到“已断开连接”或长时间无响应。我当时踩的坑是 Nginx 默认 60 秒超时,大模型流式响应有时候超过 60 秒,导致中间断开。解决办法是把 Nginx 的超时时间调大,并让前端一次性拿到全部流式结果后再渲染。
其次是流式中断。模型生成到一半网络断了,前端显示到一半就停了。我的处理方案是后端做一个 buffer,流式内容先落到后端内存,前端断开或者失败时,下次请求可以继续从断开位置接着输出。这个方案稍微复杂一点,但对于体感要求高的产品,值。
4.3 成本控制:让大模型应用的账单活得更久
大模型应用上线后,成本曲线常常是创业团队的意外惊喜(不是好的那种)。一个客服机器人,如果每天处理 1 万轮对话,每轮大约消耗 2000 token,一天就是 2000 万 token,按当前市场价格,这个成本分分钟让人肉疼。所以成本控制不是事后止损,而是架构一开始就要考虑。
我的几个实用技巧:
- 引入模型分级。简单的问题、常见的问题用轻量级小模型回答,只有复杂推理才调用大模型。我现在做的问答系统里,超过 70% 的简单问题都会先走一个小模型,只有小模型置信度低时才转大模型。
- 建语义缓存。用户问“你们年假有几天”和“年假天数是多少”,其实是一个答案。把类似问题的答案缓存住,命中缓存就直接返回,不用再调用模型。这个方案在重复问频繁的客服场景效果拔群。
- 控制输出长度上限。模型生成的 token 数直接跟钱挂钩,Prompt 里明确限制回复长度,加上 max_tokens 参数,经常能让成本降一半而且体验反而更好。
- 定时检查日志中的超长输出和失败重试次数,避免隐性开支。
4.4 可观测性:给大模型应用装上日志和评估系统
大模型应用跟传统应用有一个很大的不同:输出不是确定性的。同一个 Prompt、同一个上下文,模型生成两次,结果可能完全不同。这意味着你无法像排普通 Bug 一样“复现问题”,必须依赖完整的日志记录来做归因分析。
我的日志设计里必含四个维度:
- 输入快照:完整 Prompt、用户问题、检索回来的上下文。
- 模型信息:用了哪个模型、版本、温度参数、max_tokens。
- 输出快照:模型原始输出、后处理后的最终输出。
- 性能指标:首 token 延迟、总耗时、token 消耗、重试次数、缓存命中情况。
有了这四类日志,遇到“用户觉得回答不对”的情况,你至少能回溯到当时模型看到了什么、输出了什么,从而判断是 Prompt 的问题、检索的问题还是模型本身的问题。否则就是在黑暗中改配置,运气好改对了,运气不好越改越乱。
线上运行之外,我还坚持做离线评测集和线上抽检。离线评测集保证每次改动前有一个“安全网”,线上抽检则能发现那些测试集没覆盖到的新问题。定期从生产日志里抽一小部分对话,人工对回答质量打标,把坏case加进测试集,这是我目前觉得性价比最高的迭代闭环。
从路径选型、Prompt 工程、RAG 增强到最后的工程化和成本控制,大模型应用开发的核心就是一件事:用工程手段把不可控的模型输出变成可控的业务价值。我自己一路做下来最大的体会是,这行的门槛不在“会用模型”,在于你是否愿意在数据准备、日志系统、效果评估这些脏活累活上下苦功夫。谁在这些细节上做得多,谁的线上效果就稳,出问题的概率就低。