AI全栈开发实战:四层架构、RAG与模型网关的最佳实践

发布时间:2026/9/7 22:34:23
AI全栈开发实战:四层架构、RAG与模型网关的最佳实践 1. 从 Vibe Coding 到 Harness × SDDAI 全栈开发变了什么这两年“AI 全栈开发”几乎成了行业里最热的词但说实话大部分人讨论的其实不是一回事。有人理解成“用 AI 辅助写代码”也就是所谓的 AI Coding有人理解成“开发一个调用大模型的应用”也就是 LLM App 开发还有人在做 AI Agent、RAG 管道、模型网关、AI Infra本质上也是全栈工程的一部分。我个人的判断是今天的 AI 全栈开发已经从传统意义上的“前端 后端 数据库”扩展成了四条线并行——一条是应用功能线负责传统 Web 产品的正常运转一条是模型集成线负责接大模型 API、处理流式输出、管控 token 成本和延迟一条是数据管道线围绕 RAG、向量检索、上下文管理等做数据工程还有一条是体验与安全线涉及流式 UI、人机交互、内容审核和权限设计。Vibe Coding 这个词最近很火本质上是在说“顺着感觉写代码”的开发方式——你给 AI 一个意图AI 给你生成一段代码你不太需要逐行理解只要整体感觉对就继续往下走。这种模式确实极大拉低了全栈开发的门槛但问题也很明显当项目规模变大、依赖变多、出现故障时光靠感觉是兜不住的。这也是为什么现在社区里更流行另一个提法——Harness × SDD 全栈开发实战。Harness 代表“把 AI 能力约束在可控的框架里”SDDSpecification-Driven Development规格驱动开发代表“先有规格再让 AI 按规格产出最后用规格验收”。这一套组合做下来AI 全栈开发才真正从“玩具”走向了“生产力工具”。这篇文章我打算把我自己实际搭建 AI 全栈项目时的技术选型、架构设计、实操流程和踩坑经历整理成一份可复用的最佳实践。无论你是打算从传统全栈转向 AI 应用开发还是已经在做 AI 产品但觉得工程质量上不去这篇文章都值得花十分钟认真读一遍。2. 整体设计拆解为什么用“应用 模型 数据 体验”四层模型来规划项目2.1 传统全栈思路在 AI 项目里的三个短板先说说为什么传统的全栈开发思路放到 AI 场景会失灵。第一传统后端对“流式”的支持是后补的。普通 Web 接口返回一个 JSON 就行但大模型生成内容是逐 token 吐出来的动辄几十秒。如果还用传统的 request-response 模式用户的体验就是“转圈圈转到天荒地老”。你需要从架构层面就规划好 SSEServer-Sent Events、WebSocket 甚至流式分块转发这直接改变了接口设计的思路。第二传统数据库范式跟向量检索不兼容。早期做 AI 应用很多人以为就是把用户问题拼接成 prompt 发给大模型就行。后来发现效果不稳定才认识到 RAG检索增强生成的重要性。RAG 需要你把文档切片、embedding 成向量再用向量数据库做相似度检索。这个链路在传统全栈里根本不存在它需要你同时懂文本处理、向量化、检索排序和 prompt 组织。第三传统测试体系无法覆盖 AI 输出的不确定性。传统后端接口只要参数合法、逻辑正确输出就是可预期的。但大模型的输出天然带有随机性同样的 prompt 可能今天和明天回答不一样甚至模型版本升级后行为完全变了。如果你的项目没有设计评估Evaluation环节你根本没法判断一次改动是变好了还是变坏了。我自己第一次做 AI 全栈项目时就是按传统后端的方式直接调用 OpenAI API然后拼了一个前端聊天框。结果上线后一堆问题响应慢、上下文一长就丢记忆、用户提问稍偏一点就答非所问。后来我重新梳理架构把所有环节拆成独立的模块问题才一个一个被解决掉。2.2 四层模型的职责划分与依赖关系我现在的做法是把任何 AI 全栈项目都按照四层模型来组织哪怕是最小的 MVP 也保持这个分层的骨架层级核心职责常用技术典型问题应用层用户认证、订单、内容管理等传统业务Next.js / Spring Boot / FastAPI业务逻辑与AI逻辑耦合模型层模型接入、多模型路由、API密钥管理LiteLLM Proxy / OpenAI SDK / Spring AI模型供应商锁定、成本失控数据层文档处理、向量化、检索、短期记忆管理LangChain / LlamaIndex / pgvector / Redis切片策略不当、检索质量差体验层流式交互、意图理解、内容安全过滤、调试追踪Vercel AI SDK / LangSmith / 自建监控流式中断、token输出安全应用层和模型层之间我强烈建议加一层网关这是我在实践里最受益的一个决定。LiteLLM Proxy 是目前社区口碑很好的一个模型网关方案它让你用一套统一的接口格式对接 OpenAI、Claude、Gemini 以及各类国内大模型还自带成本统计和限流功能。有了这层以后你的业务代码里就不需要直接依赖任何一家模型供应商的 SDK换模型只是改一行配置的事。数据层最容易被低估。很多人以为 RAG 就是把文档扔进向量库就完事实际效果往往很拉胯。后来我意识到RAG 的瓶颈通常不在模型而在召回质量。文档切分、Embedding 模型选择、检索时的重排Rerank每一环都影响最终效果。数据层必须作为独立的服务去设计否则后期优化无从下手。体验层是 AI 全栈里最容易出彩也最容易翻车的一层。传统 UI 是用户点击后等待结果AI 应用里用户要的是“边生成边看”而且生成过程中还可能要求中断、重新生成、引用来源。这套交互范式跟传统表单提交完全不一样需要在前端状态管理、后端流式推送、错误恢复机制上都提前设计好。2.3 为什么我不用“All in one”框架市面上有很多 All in one 的 AI 开发框架号称一个框架搞定前后端和模型调用。我试过几个最后都撤了。原因很简单框架的抽象层次越高你越难做性能调优和问题排查。当你的应用只需要一个聊天机器人时All in one 框架很爽当你要做复杂的 Agent 多步推理、精细化的权限控制、细粒度的 token 成本分摊时框架反而成了束缚。我现在更倾向于“轻量组合”的思路——每一层选最成熟、最专注的工具层与层之间用标准接口通信。应用层就老老实实写业务逻辑模型层交给网关去管数据层用专门的编排框架体验层自己做流式封装。这样做的代价是初期开发量略大但项目的稳定性和可维护性会好很多。3. 技术选型解析LiteLLM Proxy、Spring AI、LangChain 到底怎么选3.1 模型网关LiteLLM Proxy 的真实价值与配置要点先说 LiteLLM Proxy这是我目前模型层里最推荐的一个基础设施。LiteLLM Proxy 的核心能力就一句话把 100 多种模型供应商的 API 统一成 OpenAI 格式。你的业务代码只需要学会调用一个 OpenAI 兼容接口至于后面接的是 GPT-4o、Claude Sonnet、Gemini 还是国产开源模型全在配置里切换。我最早没有用 LiteLLM Proxy业务代码里直接硬编码了 OpenAI SDK。后来有一次供应商 API 升级整个服务重构了一遍。从那以后我下定决心引入代理层。LiteLLM Proxy 的最佳实践我总结了三点第一通过配置路由规则实现模型优先级和故障转移。比如主模型用 A超时或报错时自动切换到 B这样能极大提升服务的可用性。配置里可以给同一类任务定义多个模型按照优先级顺序调用。第二开启成本追踪和速率限制。LiteLLM Proxy 自带按 key 维度的 token 统计你可以给不同的项目、不同的用户分配不同的 API key然后按 key 设置日限额和并发数。这个功能在多人协作时尤其有用可以防止某个测试脚本把预算烧光。第三统一拦截和合规过滤。通过 Proxy 的中间件机制可以在请求进入模型之前做一次内容安全检测在响应返回之前再做一次输出过滤。这一点做 To B 项目时几乎是刚需。下面是一个 LiteLLM Proxy 的简化配置示例model_list: - model_name: gpt-4o litellm_params: model: openai/gpt-4o api_key: sk-xxx - model_name: gpt-4o litellm_params: model: azure/gpt-4o api_key: azure-xxx api_base: https://xxx.openai.azure.com/ api_version: 2024-02-15-preview # 故障转移当上面的 openai 路由失败时自动切换到这里 - model_name: claude-sonnet litellm_params: model: anthropic/claude-sonnet-4-20250514 api_key: sk-ant-xxx router_settings: routing_strategy: usage-based-routing-v2 fallbacks: [{ gpt-4o: [claude-sonnet] }] general_settings: master_key: sk-master-123 database_url: postgresql://user:passlocalhost:5432/litellm你的业务代码不用改任何模型相关的逻辑只需要记住 model_name 叫 gpt-4o 还是 claude-sonnet请求格式统一是 OpenAI 风格。这样后续升级模型、换供应商都只动配置文件不动代码。3.2 编排层LangChain、LlamaIndex 与 Spring AI 的取舍接下来说编排层。LangChain、LlamaIndex、Spring AI 是现在最主流的三套框架选型时很多人纠结我直接说结论。如果你的技术栈是 Java/Spring 体系尤其是做企业级应用Spring AI值得优先考虑。它最大的优势是和 Spring Boot 生态天然融合依赖注入、配置管理、事务控制这些能力直接复用团队上手成本低。而且 Spring AI 对 RAG、Agent、结构化输出都有专门的抽象文档也更新得比较快。如果你的技术栈是 Python那看你的核心诉求。LlamaIndex在文档处理、RAG 管道、数据索引方面的深度是最强的适合做知识密集型应用比如企业知识库、法律文书分析这类对召回质量要求极高的场景。LangChain的优势在于 Agent 生态成熟链式调用、工具调用、记忆管理的抽象非常完整适合做多步骤推理和工具调用的 AI Agent。我自己有个经验第一版项目尽量少用框架的高级抽象多用最简单的 prompt 拼接和 API 调用。等跑通了再逐步引入框架来管理复杂性。因为框架的抽象是有学习成本的如果你还没理解 RAG 的基本原理就直接用 LangChain 的 QAChain出了问题你根本不知道在哪一环出错。3.3 AI Infra 思维把成本、延迟、可观测性做成内建能力AI 全栈开发和传统开发的另一个显著区别就是AI Infra 必须是一等公民不能等到项目上线后再补。成本管控从第一天就要做。大模型的调用成本跟传统服务器成本完全不同——它是按 token 计费的而且没有明显的峰值预警。我见过不止一个项目上线测试时所有人高频调用一个月烧掉几万块都没察觉。解决办法就是在模型网关层做按 key 的配额限制和成本告警LiteLLM Proxy 配合 Prometheus Grafana 可以很方便地做到。延迟问题也一样。大模型响应动辄几秒到几十秒这跟传统接口50ms的延迟不是一个量级。你需要从第一版就设计流式输出否则后续再怎么优化都救不了体验。前端要支持增量渲染后端要做流式转发网关层要做缓冲和超时处理整条链路都得为“长任务”设计。可观测性是最容易被忽略的。传统开发你只需要记录接口耗时和错误率AI 应用里你需要追踪每一次 prompt 的内容、使用的模型、token 消耗、延迟分布、以及用户的反馈数据。这些数据是后续优化 prompt、调整参数、评估模型效果的依据。工具上可以用 LangSmith、Langfuse、Helicone 这类专门给 LLM 应用设计的可观测平台也可以自建一套轻量方案——把请求日志、token 统计、生成结果都持久化到数据库配合后台管理页面查看。4. 实操过程从 0 到 1 搭建一个可复用的 AI 全栈项目4.1 MVP 需求定义与架构蓝图为了让你更直观地理解上面的分层设计我拿一个实际项目做例子——做一个“企业知识库问答系统”用户上传文档AI 基于文档内容回答问题并且能标注引用来源。这个项目麻雀虽小但五脏俱全涉及文件上传与解析、长文本切片与向量化、RAG 检索、大模型问答、流式前端、用户权限管理、后台数据统计。我定义 MVP 版的核心流程如下用户上传 PDF → 解析为纯文本 → 按语义切片 → 生成向量 → 存入向量库 用户提问 → 检索 Top-K 相关片段 → 组装 prompt → 调用大模型 → 流式返回答案引用来源对应到技术选型前端Next.js Tailwind CSS流式交互用 Vercel AI SDK后端FastAPI提供 REST 接口和 SSE 流式接口模型网关LiteLLM Proxy统一管理模型和密钥编排LlamaIndex负责文档解析、切片、向量化和检索向量库pgvector直接复用 PostgreSQL避免多引入一套运维组件数据存储PostgreSQL用于用户、文档元数据、问答日志这个组合的优点是每一层都尽量简单出了问题好定位。4.2 文档切片的两个坑固定窗口 vs 语义切分整个项目里我花时间最多的不是写代码而是调文档切片策略。第一次我是按固定字符数切片的每 500 字符一片。结果问答效果很差很多回答前言不搭后语。原因是固定窗口会把完整的语义单元拦腰截断——比如一个条款的前半部分在上一片后半部分在下一片检索时只召回其中一片模型自然看不懂。后来我换成了语义切分先按段落结构拆再结合句号、问号等自然边界做二次合并保证每片在 200~500 token 之间。同时让相邻切片有 10%~15% 的重叠避免边界信息丢失。这样改造之后回答的完整性有明显提升。如果你用的是 LlamaIndex可以直接用SentenceSplitter这类内置切分器也可以基于文档自身的结构Markdown 标题、PDF 章节、HTML 标签做定制化切分。我的建议是结构优先长度兜底。先利用文档原有的层级结构切分再控制每片的最大长度不超限。每篇文档向量化的同时把切片后的文本原文也存到数据库里。这样检索到某一片时可以直接拿到原始文本去拼 prompt而不需要反解向量。4.3 Agent 编排与工具调用的实现要点如果只是简单的单轮问答LangChain 或者 LlamaIndex 的 QA 接口就够了。但真实场景里用户的问题往往需要多步处理。比如“对比一下文档 A 和文档 B 中关于报销流程的差异”如果只做一次检索召回的内容可能不够完整。这种场景就需要 Agent 的介入。Agent 的核心是把大模型当作决策者让它决定调用哪些工具、以什么顺序调用。在我的项目里我注册了三个工具search_documents(query, top_k)在知识库中检索相关片段get_document_summary(doc_id)获取某篇文档的摘要list_documents()列出当前用户有权限访问的文档列表大模型拿到用户问题后先调用search_documents检索如果发现检索结果分散在多篇文档再调用get_document_summary分别获取摘要最后综合信息生成答案。这里有一个非常关键的实操经验工具描述一定要写得极其清楚。大模型是根据工具描述来决定要不要调用工具的描述写得模糊它可能该调的时候不调不该调的时候乱调。比如search_documents的描述我写的是当用户的问题涉及文档中的具体内容、条款、数据时调用此工具在知识库中检索最相关的片段。参数 query 为用户的自然语言问题top_k 为返回的片段数量默认 4最大 10。一句话把“什么时候用、参数怎么传、默认值多少”都说清楚了模型在绝大多数情况下都能做出正确判断。还有一个坑是Agent 的循环上限。如果 Agent 的推理走入死循环——不停地调用工具但始终不给出最终答案你的 token 成本会飞速上涨。我在代码里硬性设置了最大轮次为 6 次超过就强制返回当前已收集的信息并提示用户扩大问题范围或缩小知识库范围。4.4 前端流式交互与后端 SSE 的实现细节流式交互是 AI 全栈和传统全栈最直观的区别。我用的方案是后端 FastAPI 提供 SSEServer-Sent Events接口前端用 Vercel AI SDK 的useChat钩子来消费流。后端的关键代码逻辑如下from fastapi import FastAPI from fastapi.responses import StreamingResponse import json app FastAPI() app.post(/api/chat) async def chat(request: dict): messages request[messages] top_k request.get(top_k, 4) # 1. 向量检索 query messages[-1][content] retrieved_chunks retrieve_chunks(query, top_k) # 2. 组装 prompt system_prompt build_system_prompt(retrieved_chunks) # 3. 通过 LiteLLM Proxy 调用模型流式返回 async def generate(): # 先返回引用来源 yield fdata: {json.dumps({type: sources, data: retrieved_chunks})}\n\n # 再流式返回回答 async for chunk in llm_stream(system_prompt, messages): yield fdata: {json.dumps({type: token, data: chunk})}\n\n yield data: [DONE]\n\n return StreamingResponse(generate(), media_typetext/event-stream)前端用 Vercel AI SDK 时只需要在请求体中带上消息历史它会自动解析 SSE 流并增量渲染到 UIimport { useChat } from ai/react; export default function Chat() { const { messages, input, handleInputChange, handleSubmit } useChat({ api: /api/chat, // 自定义解析因为我们的流里除了 token 还有 sources 事件 onResponse: (response) { // 可选处理额外的 sources 数据 }, }); return ( div {messages.map((m) ( div key{m.id}{m.role}: {m.content}/div ))} form onSubmit{handleSubmit} input value{input} onChange{handleInputChange} / button typesubmit发送/button /form /div ); }流式设计里有两个细节必须注意。第一后端要设置合理的超时时间。大模型生成时间可能长达几十秒如果前端或者反向代理层的超时时间设成 30 秒用户会看到“连接中断”。我在 Nginx 层把proxy_read_timeout调到 300 秒后端 FastAPI 也把超时限制放宽避免中间任何一环掐断流。第二SSE 连接要处理断线重连。用户网络不稳定时流可能中途断开。前端需要在组件卸载时主动中止请求避免内存泄漏同时在初始化时传入onError回调让用户在断线时看到提示而不是干等。5. 常见问题与排查技巧实录5.1 上下文一长就“失忆”到底怎么回事这是 AI 应用里最典型的坑。现象是用户跟 AI 聊了十几轮后AI 突然忘了之前说过什么或者答非所问。原因有两种。一种是上下文超过窗口长度被截断——模型对 token 数量有限制超出部分会被粗暴丢弃。另一种是前端没有把对话历史完整传给后端——你的代码里可能只传了最近几轮消息但实现得不对。排查方法在后端日志里打印每次请求的 messages 数组看历史消息是否完整、顺序是否正确。如果历史消息没问题再检查 token 数是否超出模型窗口。解决方案有三个层面前端只传必要的消息但必须完整。把 system prompt、工具返回结果等非用户消息单独管理不混在对话历史里。后端做上下文压缩。当消息超过阈值时用一个小模型对早期对话做摘要把摘要作为新消息放进上下文。这样既保留关键信息又不超窗。重新设计记忆机制。短期记忆用 Redis 存最近 N 轮长期记忆写到数据库按用户 ID 和会话 ID 关联。我自己的项目里用的是第二种方案当消息 token 数超过 3000 时触发一次摘要压缩把最旧的 10 轮对话浓缩成 150 token 的摘要替换掉原来的消息。实测下来对话轮数从十几轮扩展到四五十轮记忆基本不丢。5.2 API 超时与流式传输中断的排查清单AI 应用经常出现“转圈很久然后报错”的问题我把常见原因整理成了一个速查表现象可能原因排查步骤解决方案请求发出后长时间无响应模型供应商 API 超时检查 LiteLLM Proxy 日志看请求是否到达模型层配置模型级超时设置后端重试机制流式输出中途断掉反向代理超时查看 Nginx/网关的 timeout 配置调大 proxy_read_timeout前端收到部分内容后报错SSE 解析异常检查流中是否混入非 SSE 格式数据确保每条事件按data:格式输出结尾加空行用户多点几次导致并发过高缺少限流看网关层的速率限制日志按用户/按 key 设置并发上限还有一个我自己踩过的坑LiteLLM Proxy 默认对接某些模型时流式输出需要在请求体里显式声明stream: true否则代理可能会缓存完整响应再一次性返回前端等了半天才看到结果体验极差。遇到这种情况先检查流式标志是否正确传递再检查代理层是否开启了缓冲。5.3 幻觉与数据权限AI 全栈最容易翻车的两个软问题幻觉问题在知识库问答场景里尤其严重。模型的通病是明明知识库里没有相关信息它也会“编”一个看起来合理的答案。解决幻觉的常规手段是强制模型基于检索内容回答检索不到就明确说不知道。这个约束要在 system prompt 里反复强调并且在请求参数里降低 temperature。我当时用的 prompt 是你是一个知识库问答助手。你必须严格依据以下检索到的文档片段回答问题。如果片段中没有足够信息请明确回答“根据现有资料无法回答”。严禁编造不存在的条款、数据或结论。除了 prompt 约束还可以在代码层面做一层校验——让一个廉价的分类模型判断“回答是否基于给定片段”。如果判定为无依据就不展示给用户而是返回预设的兜底话术。这种方法能显著降低幻觉漏出的概率。数据权限是另一个容易忽略的致命问题。知识库问答系统如果接入企业内部文档必须确保用户只能检索到他有权限访问的内容。最简单的方式是在数据库里给每篇文档打上权限标签检索时把权限作为过滤条件直接加到向量检索的 SQL 查询里。千万不能等到检索结果出来后再在应用层做过滤——因为你不希望在服务端日志里暴露用户无权访问的内容。6. AI 全栈开发的长期主义给正在转型的开发者几句真心话聊到最后我想分享一些项目之外的体会。AI 全栈开发这个方向现在缺的不是“会用某个框架的人”而是能理解模型能力的边界、能把 AI 能力嵌入到真实业务链路、能对最终产品的质量和成本负责的人。技术框架会不断更迭今天流行的 LangChain明天可能就被新工具取代但底层的工程思维是稳定的——分层设计、可观测性、成本管控、安全合规这些在任何时代都是硬通货。如果你现在刚开始转型我建议不要一上来就追最新的 Agent 框架。先把 RAG 原理吃透亲手实现一遍文档切分、向量化、检索、重排的完整链路再研究一下 LiteLLM Proxy 这类基础设施是如何解决多模型管理问题的然后选一个真实的业务场景从 MVP 做到可上线。这个过程走下来你收获的会远超任何教程。最后送大家一个实操小技巧做 AI 全栈项目一定要从一开始就把对话日志、token 消耗、用户反馈记录下来。几个月后你会发现这些数据是优化产品效果最宝贵的资产比任何“最佳实践”的模板都值钱。