AI应用开发不能只追模型,工程闭环才是落地关键
在 AI 应用开发的热潮里,很多团队把大量时间花在“追模型”上:某个新模型跑分更高,立刻切换;某个榜单刷新,立刻重测;某个参数更大,立刻认为效果更好。但真实业务里的问题往往不是模型不够强,而是工程链路太脆弱:数据没有处理好,检索召回质量差,接口没有超时控制,Agent 调用工具失败后没有人知道,效果评估靠人工翻聊天记录。这篇文章围绕一个核心观点展开:AI 应用开发最重要的不是追赶最强模型,而是把业务闭环跑通。文章会从模型选型、RAG 问答、Agent 设计、部署服务化、效果评估和问题排查几个环节,给出一个可以落地的工程路径。
1. 为什么 AI 项目容易卡在“模型不够强”之外的地方
1.1 模型能力和业务能力之间存在明显落差
模型能力通常指语言理解、指令跟随、推理、代码生成、多模态理解等通用能力。业务能力则是指在具体场景中稳定地解决一个问题,并且能长期维护。两者之间的落差经常被低估。
举例来说,一个客服问答系统要求回答准确、有依据、不能乱编。单纯把一个高跑分模型接进去,并不能保证它能找到公司内部文档里的答案,因为模型没有经过检索增强时,只能依赖训练阶段学到的知识。训练知识有截止时间,也覆盖不到企业内部的私有数据。换一个更强的模型可以改善回答的通顺度和推理能力,但解决不了“文档没有入库”“检索不到正确片段”“引用来源缺失”这类工程问题。
在实际项目中,模型能力只是最终效果的一部分。完整链路包括:
- 数据清洗和格式转换。
- 文档切分和向量化。
- 检索策略和相关性排序。
- 上下文组装和提示词设计。
- 模型输出解析和异常校验。
- 用户反馈收集和持续迭代。
模型只是这条链路里的一个环节。链路里任何一个环节出问题,都会拉低最终的业务效果。
1.2 典型失败链路:从 Demo 到生产之间的断点
很多 AI 项目在 Demo 阶段表现良好,进入生产环境后却快速恶化。常见的原因是 Demo 阶段只验证了模型,没有验证数据、接口、并发和监控。
一条典型的失败链路是这样的:
- 选型阶段只看跑分,没有用真实业务数据做评测。
- 接入阶段只调用一个模型接口,没有写参数校验和异常处理。
- 数据阶段没有清洗文档,把 PDF 里的大段目录、页眉页脚都切成了向量。
- 检索阶段没有测试召回质量,只凭肉眼看了几条结果。
- 部署阶段没有设置超时和重试,模型接口偶尔慢一次,整个请求就失败。
- 上线阶段没有做灰度,也没有采集用户反馈,问题发生几天后才发现。
每个断点单独看都不难解决,但如果没有工程闭环,这些断点会叠加成不可维护的系统。
1.3 从“追最强”转向“追闭环”
把 AI 应用当作普通软件工程来做,意味着先定义输入、输出和验收指标,再选择模型和框架。一个 AI 系统是否合格,最终看它能否在给定成本、延迟和数据安全约束下,稳定完成业务目标。
一个可用的判断标准是:离线评测能说明模型有没有变好,线上反馈才能说明系统有没有变好用。团队应该在早期就建立评测数据集、线上埋点和回归机制,而不是等到上线后再补。
2. 模型选型:按业务需求而不是排名做决策
2.1 先把任务分成四类
不同业务场景对模型能力的要求完全不同。实际选型时,建议先按任务类型分类,再评估常用模型。
| 任务类型 | 典型场景 | 优先关注的能力 | 评测重点 |
|---|---|---|---|
| 文本生成 | 营销文案、报告、邮件 | 内容相关性、格式一致、语气控制 | 可读性、业务规则符合度 |
| 信息抽取 | 合同字段、简历信息、日志结构化 | 字段识别准确率、格式稳定 | 精确率、召回率、字段解析成功率 |
| 对话问答 | 客服、知识库问答、助手 | 指令跟随、上下文理解、防幻觉 | 答案准确率、引用来源有效 |
| 工具调用与 Agent | 查询工单、天气、订单、操作流程 | 工具选择准确性、参数提取正确 | 任务完成率、平均调用步数、故障率 |
同一个模型在不同任务上的表现差异可能很大。某个模型文本生成流畅,但工具调用时经常把参数格式传错;某个模型推理能力强,但回答长度不可控。选型时不要只看总分,而是用目标任务的数据集分别测。
2.2 模型选型参数对照表
选型时通常要评估以下参数:
| 选型参数 | 含义 | 选型建议 |
|---|---|---|
| 上下文长度 | 模型一次能输入的 token 数量 | 长文档场景至少 32K,普通问答 8K 到 16K 足够 |
| 推理速度 | 每秒生成 token 数 | 实时对话需要优先考虑,离线任务可放宽 |
| 成本 | 按 token 计费或按 GPU 资源计费 | 高频场景要提前估算单次请求成本 |
| 部署方式 | API 调用或本地私有化部署 | 数据合规要求高时选本地部署 |
| 微调能力 | 是否允许在业务数据上继续训练 | 需要学习业务术语时优先考虑 |
| 生态兼容 | 是否支持 OpenAI 协议、主流框架 | 减少改造成本,便于替换 |
| 数据安全 | 数据是否离开企业环境 | 严格场景必须本地推理 |
其中上下文长度不能只看模型能力,还要看实际工程中是否真的把长文送给了模型。把所有检索文档都塞进提示词,往往会导致成本上升、延迟变高,还容易让模型抓不住重点。
2.3 API 调用和本地部署如何取舍
API 调用的优势是接入快、运维简单、模型通常更强;劣势是数据出域、单次请求成本高、网络依赖强。本地部署的优势是数据可控、可按需定制、长期成本可能更低;劣势是需要 GPU 资源、推理引擎维护和模型版本管理。
如果原始材料没有给出明确版本,落地前需要先确认依赖版本。这个原则同样适用于模型选型:不要因为某篇文章推荐某个模型就直接替换,先看自己的数据格式、调用协议和评测集是否兼容。
2.4 一个选型决策示例
假设要做企业内部知识库问答,数据包含财务制度和员工手册,场景要求回答必须来自官方文档,同时数据不能出内网。
此时可以按以下顺序决策:
- 确认数据必须内网处理,排除外部 API。
- 选择可以直接私有化部署的开源模型。
- 确认 GPU 资源足够支撑目标并发。
- 用 100 条真实业务问题做离线评测,分别测试检索模型和生成模型。
- 根据模型输出结果的准确率和格式稳定性,决定是否做提示词优化或微调。
这个决策过程的核心不是选一个“最强”模型,而是在数据安全、成本、延迟和效果之间找到平衡。
3. 搭建最小 AI 应用:企业内部知识库问答 Agent
3.1 场景和需求拆解
用一个可以落地的例子说明 AI 应用如何跑通工程闭环。场景是企业内部知识库问答,目标是让员工用自然语言提问,系统从文档库中检索相关资料,再交给大模型生成有依据的回答。
需求拆解如下:
- 输入:用户问题,例如“年假 15 天需要满足什么条件”。
- 处理:文档加载、切片、向量化、检索、上下文组装、模型调用。
- 输出:答案文本和引用来源,方便用户验证。
- 非目标:不处理身份认证、权限分级和实时自动化操作。
这个例子适合放在学习环境快速跑通,后续再扩展生产化能力。
3.2 技术栈和依赖
示例使用以下技术栈:
- Python 3.10+
- FastAPI 提供 HTTP 接口。
- Chroma 作为本地向量库。
- 开源 Embedding 模型生成向量,例如
BAAI/bge-small-zh-v1.5。 - 大模型通过 OpenAI 兼容协议调用,本地模型或外部 API 均可。
如果使用 OpenAI 协议,不同模型的接入方式可以统一。关键代码只依赖 openai SDK 的 base_url 参数,切换模型时不需要改业务逻辑。
安装依赖的命令如下:
3.3 项目结构
建议按职责拆分文件,避免把数据加载、检索和 API 层混在一起。
这个结构在刚开始可能显得多余,但进入生产环境后,每个文件都会有对应的问题出现,独立文件更容易定位。
3.4 实现文档加载与切片
文档加载环节要处理 PDF、Word、Markdown 等格式。为了保持示例简单,这里读取 PDF 文件并使用字符切片。
切片时长文档中容易被忽略的问题是:切片大小和重叠会影响检索质量。过长的片段会包含无关内容,过短的片段容易切断语义。建议先按段落结构切片,再按固定长度控制最大尺寸。
代码里把 chunk_size 设为 500,overlap 设为 50,能让相邻片段保留一定关联。实际项目需要根据文档结构和问题长度调整。
3.5 实现向量库初始化和检索
向量库负责把文本片段转换成向量并存储。检索时先计算问题向量,再返回最相似的片段。
这里把向量库持久化到 data/chroma_db 目录,重启服务后不需要重新建立索引。
3.6 实现大模型调用封装
大模型调用层要统一处理请求参数、超时和异常。如果后续要切换模型,只需要改配置项。
本地推理服务通常会提供一个 OpenAI 兼容地址。换成外部 API 时,把 base_url 和相关密钥放入环境变量即可。不要把密钥写死在代码中,建议使用环境变量或配置文件。
3.7 组合检索与生成
FastAPI 接口的职责是接收用户问题、调用检索、组装提示词、返回结果。
这个示例中的检索结果直接作为上下文传给模型。生产环境还需要处理“没有检索到相关内容”的情况,避免模型在无资料时强行回答。
启动服务后,通过请求验证接口是否正常:
预期返回结果中包含 answer 和来源列表。如果结果为空或来源异常,先检查文档切片和向量库填充逻辑。
4. 生产化改造:把函数调用升级成可观测服务
4.1 API 接口层设计
在 Demo 阶段,接口只要能返回结果即可。生产环境需要定义清晰的请求和响应结构,包括错误码、时间戳和链路追踪 ID。
建议统一响应格式:
失败场景返回非零 code,例如参数错误返回 40001,模型超时返回 50002,内部异常返回 50000。不要让前端只能用 HTTP 状态码判断问题。
4.2 并发、超时与重试
大模型接口不是越快越好,而是需要在超时、并发和成本之间平衡。常见的做法是:
- 设置连接超时为 3 到 5 秒,读超时为 30 到 60 秒,按模型速度和上下文长度调整。
- 原生命令失败的请求需要重试,例如网络抖动、临时 5xx。
- 业务侧等不起的请求返回“稍后重试”,不要无限阻塞。
- 对高成本模型接口做并发限流,防止一个用户的重试打满资源。
这段代码用指数退避减少重试对模型服务的压力。重试不是越多越好,生产环境要记录每次重试的原因和次数。
4.3 缓存策略
很多用户的问题是重复或高度相似的。完全相同的请求可以使用精确缓存,键为问题文本和模型参数的哈希值。更进一步的优化是语义缓存,通过向量相似度判断两个问题是否等价。
语义缓存的实现思路是:
- 将用户问题向量化。
- 在缓存向量库中检索相似度大于阈值的历史问题。
- 如果命中,直接返回历史答案。
- 如果未命中,调用模型并把结果写入缓存。
缓存能明显降低成本和延迟,但要注意数据时效性。如果资料库每天更新,缓存需要设置过期时间,或者在知识索引重建时清理缓存。
4.4 日志与链路追踪
AI 应用的日志比普通接口更复杂,因为一次请求涉及多个环节:检索、提示词组装、模型调用、结果解析。建议记录以下信息:
- trace_id:一次请求全链路共享。
- 问题原文。
- 检索到的文档列表和相似度评分。
- 发送给模型的 prompt 摘要,避免记录大量文本。
- 模型返回的原始结果。
- token 消耗、模型延迟、总耗时。
- 异常信息。
链路追踪可以先用成熟方案,例如 OpenTelemetry,先把 trace_id 串联到日志中。没有链路追踪时,至少保证日志中能通过 trace_id 查全某一次请求。
4.5 学习环境与生产环境差异
| 维度 | 学习环境 | 生产环境 |
|---|---|---|
| 配置 | 配置写在代码里 | 配置外置化到环境变量或配置中心 |
| 数据 | 少量文档 | 全量文档,按来源和权限管理 |
| 模型 | 一个固定模型 | 支持多版本灰度 |
| 接口 | 直接函数调用 | HTTP 服务、限流、鉴权 |
| 日志 | 打印到终端 | 结构化日志、集中采集、告警 |
| 错误 | 抛异常即可 | 定义错误码、友好提示、兜底策略 |
| 评估 | 肉眼判断 | 离线评测集和线上指标对比 |
| 更新 | 重启生效 | 版本化发布、灰度、回滚 |
5. Agent 开发不是模型能力的堆砌,是流程控制
5.1 Agent 的关键组件
Agent 可以理解为让模型根据目标自主决策并调用工具的执行器。实际开发中,Agent 不只是把模型接口包一层,而是要把规划、记忆、工具和流程控制结合起来。
关键组件如下:
- 规划:模型分析当前用户的意图,拆解成步骤。
- 工具:外部能力,例如查天气、查订单、调业务系统。
- 记忆:短期记忆保存当前对话历史,长期记忆保存用户偏好和业务上下文。
- 执行:调用工具,把结果返回给模型,循环直到完成目标。
很多人把 Agent 做成了“模型反复调工具”,但没有设置最大步数和终止条件,导致请求陷入循环。这属于流程控制问题,不完全是模型能力问题。
5.2 用 Spring AI 实现一个简易 Agent
如果项目技术栈是 Java,可以使用 Spring AI 快速实现带工具调用的 Agent。
示例场景是查询天气和计算行程时间。先定义工具:
然后在服务中注入模型和工具:
Spring AI 会在模型需要工具调用时自动获取工具描述并返回结构化参数。这个示例能跑通的最小闭环是:用户问“北京明天适合户外活动吗”,Agent 调用天气工具,把天气信息返回给模型,模型再组织回答。
工具代码如下所示,核心目的是让模型能执行外部操作并获取最新的数据。
5.3 工具调用的容错设计
工具调用最常见的错误有三种:
- 工具本身异常,例如数据库连接失败。
- 模型提取参数错误,例如把“北京”提取成“Beijing”,但业务系统只接受中文城市名。
- 工具返回数据格式不符合提示词要求,模型无法理解。
建议对所有工具调用做异常捕获,并让模型感知到“工具调用失败”这个结果。例如:
这样模型拿到失败原因后,可以决定是否需要向用户解释,或者换一种方式查询。而不是直接让整个 Agent 报错。
5.4 防止 Agent 陷入循环
Agent 系统最容易出现的问题是循环调用。模型在完成目标后,仍然反复调用工具,或者调用同一个工具多次,浪费 token 和响应时间。
通常可以从三个层面控制:
- 限定最大迭代次数,例如最多 5 步。
- 限定单次请求的模型调用超时时间。
- 在系统提示词中明确退出条件,例如“当用户的问题已经得到完整回答时,不需要继续调用工具”。
工程侧还可以监控工具调用次数和每个任务的平均步数。如果某个场景平均步数过高,说明工具描述或提示词不够清晰,需要优化。
6. 效果评估:没有评测体系,优化就是凭感觉
6.1 离线评测指标
AI 应用开发不能只靠人工看几个回答就判断效果。离线评测是指在固定的测试集上批量运行待评测模型或流程,用指标衡量结果。
常用离线指标包括:
| 指标 | 含义 | 计算方式 |
|---|---|---|
| 准确率 | 回答内容是否正确 | 正确回答数 / 总问题数,需要人工或大模型标注 |
| 召回率 | 检索到的文档是否包含关键答案 | 能回答问题的文档被召回的比率 |
| 答案可接受率 | 回答是否满足业务接受标准 | 人工可接受数 / 总数 |
| 引用有效率 | 回答内容是否能在引用来源中找到依据 | 验证引用与答案一致性 |
| 成功率 | 接口是否完整返回可用结果 | 成功响应数 / 总请求数 |
其中最难建设的是标注数据。建议从真实用户问题中抽样,先标注 100 到 200 条,形成基线测试集。
6.2 线上反馈指标的埋点
离线评测不能覆盖所有真实分布,线上反馈是关键补充。线上至少应该埋点以下信息:
- 用户提问后是否得到有效回答。
- 用户是否对回答点赞或点踩。
- 用户是否继续追问。
- 用户是否放弃会话。
- 回答平均延迟和 token 消耗。
- 请求失败率和超时率。
客服类场景可以把“是否转人工”作为重要指标。知识库类场景可以把“引用点击率”作为指标。
6.3 回归测试集的建设
每次修改提示词、替换模型或调整切片策略时,都应该跑一遍回归测试集。测试集需要覆盖以下类型:
- 常见问题。
- 边界问题,例如空问题、超长问题。
- 容易混淆的问题,例如“年假和婚假有什么区别”。
- 需要多步推理的问题。
- 模型容易答错的问题。
- 用户反馈过的问题。
离线评测发现效果下降时,不要立即改代码,先生成一份对比报告,说明是模型回复变化还是检索结果变化导致的。
6.4 多版本灰度对比
生产环境不能所有流量直接切换到新模型。建议通过灰度发布对比模型版本,至少观察 3 到 5 天。
灰度方式可以选择按用户比例划分流量,或者按问题类型划分。例如内部知识库场景,先让 10% 的查询进入新模型,对比线上指标后再放大比例。
灰度期间需要记录以下数据:
- 新模型版本。
- 检索策略版本。
- 提示词版本。
- 回答分布。
- 线上反馈。
AI 系统经常会面临模型不变、数据变了的情况,所以每一次发布都必须明确版本号。
7. 常见问题排查:从现象到根因
7.1 问题排查速查表
| 问题现象 | 常见原因 | 检查方式 | 处理建议 |
|---|---|---|---|
| 回答内容不准确 | 检索召回不到正确文档 | 查看检索结果和相似度评分 | 优化切片、增加召回数量、调整检索策略 |
| 回答乱编 | 模型被要求回答但资料不足 | 检查提示词和上下文 | 增加“无法回答时明确说明”的约束 |
| 请求超时 | 模型推理慢或上下文过长 | 查看模型延迟和 prompt 长度 | 减少上下文、开启流式、调大超时 |
| 接口报错 | 参数格式错误或服务异常 | 查看错误日志和 trace_id | 按错误码逐项排查 |
| Agent 反复调用工具 | 缺少终止条件或工具描述不清 | 查看工具调用日志和步数 | 增加最大步数、优化退出条件 |
| 成本快速上升 | 上下文过长或检索文档太多 | 查看 token 消耗统计 | 精简检索片段、启用语义缓存 |
| 隐私数据泄漏 | 日志或提示词记录了敏感信息 | 检查日志脱敏规则 | 日志脱敏、过滤敏感字段 |
7.2 常见坑一:上下文塞得越多,回答反而越差
很多人认为把越多资料传给模型,回答就越准确。实际项目中,资料太多会让模型分不清主次,还可能超出上下文窗口,导致接口报错或成本飙升。
正确处理方式是在检索阶段控制召回数量。先把相关文档通过向量检索筛选到 3 到 5 个片段,再按相关度排序。如果信息确实很多,可以先让模型做一个“资料摘要”,再基于摘要回答。
7.3 常见坑二:模型返回格式不稳定
在信息抽取或工具调用场景中,模型返回的 JSON 可能包含多余文字、换行符或字段缺失。不要直接执行 JSON 解析,要先做格式清洗。
建议在提示词中明确要求“只输出 JSON,不解释”,但在代码中仍然要兜底。解析失败时记录原始输出,方便定位是模型问题还是提示词问题。强格式要求场景可以使用结构化的工具调用协议,而不是让模型直接生成 JSON 文本。
7.4 常见坑三:向量库切换后没有重新构建索引
多语言模型、向量维度、距离函数都会影响检索结果。如果从本地模型切换到 API Embedding 模型,向量维度可能不同,旧索引无法使用。这个问题经常发生在环境迁移时。
切换模型后,必须重新生成所有文档的向量,并用真实问题验证检索质量。不要只验证接口能返回结果,要确认返回结果的语义相关性。
7.5 排查顺序建议
遇到线上问题时,按以下顺序排查:
- 用户输入是否合法。
- 请求是否到达服务,trace_id 是否生成。
- 检索结果是否包含正确资料。
- 提示词组装是否正确。
- 模型接口是否成功返回。
- 返回内容解析是否成功。
- 是模型能力问题还是工程链路问题。
这个顺序可以帮助团队快速缩小范围,避免一上来就怀疑模型不够好。
8. 把 AI 工程能力沉淀成可复用清单
8.1 模型选型检查清单
选型不是一次性的工作,每次更换模型或版本前都可以按以下清单确认:
- 是否使用真实业务数据做了离线评测。
- 是否确认了上下文长度、成本、延迟满足业务要求。
- 是否确认了数据安全边界和部署方式。
- 是否验证了 OpenAI 协议兼容性。
- 是否准备了回滚方案。
- 是否定义了线上对比指标。
8.2 发布前检查清单
从开发到上线,至少检查以下内容:
- 配置全部外置化,没有硬编码密钥。
- 接口定义了错误码和统一的响应结构。
- 设置了超时和重试策略。
- 日志中包含 trace_id 和关键环节耗时。
- 对敏感信息做了脱敏。
- 检索和模型调用有兜底逻辑。
- 有回归测试集和线上指标埋点。
- 保留了旧模型版本,支持一键回滚。
8.3 后续扩展方向
工程闭环跑通后,可以继续扩展:
- 检索优化:混合检索、重排序、递归检索。
- 私有化部署:量化模型、推理加速、模型版本管理。
- Agent 编排:多 Agent 协作、权限控制、任务队列。
- 数据沉淀:用户反馈自动入库,持续更新知识库。
- 多模态:图片、语音、视频内容纳入数据链路。
- 评测平台:把离线评测、线上指标和回归对比统一管理。
AI 应用开发真正的竞争力不在某个模型参数有多大,而在于团队能否用工程方法持续迭代数据、提示词、检索策略和模型流程。能稳定解决业务问题、能快速定位问题、能平滑升级版本,这样的系统比单次最强模型更有长期价值。