ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

从Demo到生产:企业AI知识助手的架构选型与部署实战

从Demo到生产:企业AI知识助手的架构选型与部署实战 先交代一下背景。最近团队在做一个企业内部的 AI 知识助手从最初技术验证用的 Demo到后来真正部署到生产环境供业务部门使用中间遇到了不少架构选型和部署上的问题。整个过程走完以后最大的感受是Demo 只需要证明“能跑”生产要考虑的则是“能稳定、安全、可维护地一直跑”。这两者之间有时候隔着的不只是代码量的差距而是整个架构思维和工程规范的落差。这篇文章会以这次实战为主线完整复盘我们在企业 AI 架构选择与部署过程中的关键决策、踩坑记录和最终落地形态。内容包括架构选型对比、Demo 阶段设计、生产环境改造、部署实施步骤、常见问题排查以及工程化建议。适合正在做企业级 AI 应用落地的后端开发、架构师、运维同学参考如果你现在还停留在跑通 Demo 的阶段也可以提前了解后面会踩到哪些坑。1. 需求场景与核心问题先明确一下我们要做的业务企业内部的 AI 知识助手。核心能力是通过自然语言提问让系统从企业内部文档库、知识库中检索相关内容再由大语言模型生成回答。听起来不复杂但实际落地时问题主要集中在几个方面数据安全企业内部文档不能随意发给外部大模型 API数据必须留在内部。知识时效性模型训练数据是过去的企业知识库是持续更新的需要做检索增强。部署成本生产环境 GPU 资源有限不可能每个业务都单独跑一套大模型。稳定性生产环境不能因为并发请求、模型推理慢、外部依赖抖动而影响业务。可观测性与运维Demo 阶段不需要看日志、指标生产环境必须能监控、告警、排查链路。整个项目从需求确认到最终上线大概经历了三个阶段第一阶段用开源模型 快速脚本搭建 Demo验证“基于企业知识库做问答”这件事是否可行。第二阶段梳理生产环境约束确定 AI 架构选型。第三阶段完成生产部署、优化、上线与排障。接下来按照这个时间线逐个复盘每一阶段的关键决策。2. Demo 阶段的快速验证很多 AI 项目都是从 Demo 开始的我们也不例外。市面上大模型部署方案很多但在 Demo 阶段不需要过度纠结重点是快速验证两条链路模型推理链路本地部署的大模型能否按预期生成稳定的回答。知识检索链路企业文档经过切分、向量化之后能否检索出相关内容。2.1 技术选型当时我们对比了几类方案最终选择的是以开源模型 本地向量库为主模型推理使用 Ollama 做本地模型部署加载开源大模型。向量化使用文本嵌入模型对知识库文档做向量化。向量存储与检索使用轻量级向量数据库存储向量做相似度检索。应用框架初期直接使用 Python 脚本串联“检索 生成”流程。选择这些技术的原因很简单它们能最快打通从文档到问答的完整链路而且不需要申请外部 API 权限数据也不需要出内网。2.2 Demo 的完整流程Demo 的整体流程如下把企业文档Word、PDF、Markdown批量读取为纯文本。按一定规则切分文档为文本块。对每个文本块调用嵌入模型生成向量。将向量和原文存入向量数据库。用户提问时将问题向量化。在向量数据库中检索相似度最高的文本块。将文本块作为上下文连同用户问题一起拼接到 Prompt 中。调用本地大模型生成最终回答。核心代码逻辑如下from langchain_community.embeddings import OllamaEmbeddings from langchain_community.vectorstores import Chroma from langchain_community.llms import Ollama from langchain.text_splitter import RecursiveCharacterTextSplitter # 1. 初始化 embedding 与 LLM embeddings OllamaEmbeddings(modelbge-m3) llm Ollama(modelqwen2.5:14b, temperature0.3) # 2. 切分文档 text_splitter RecursiveCharacterTextSplitter( chunk_size500, chunk_overlap50 ) chunks text_splitter.split_text(original_text) # 3. 存储向量 vectorstore Chroma.from_texts( textschunks, embeddingembeddings, persist_directory./chroma_db ) # 4. 检索 retriever vectorstore.as_retriever(search_kwargs{k: 5}) docs retriever.get_relevant_documents(user_question) context \n\n.join([doc.page_content for doc in docs]) # 5. 拼接 Prompt 并生成回答 prompt f请基于以下知识库内容回答用户问题。 如果知识库内容不足以回答请明确说明。 知识库内容 {context} 用户问题 {user_question} response llm.invoke(prompt) print(response)这段代码在 Demo 阶段完全没有问题它把“文档进来 - 知识检索 - 答案生成”的闭环跑通了。但如果你把它直接放到生产环境会遇到一系列问题。2.3 Demo 阶段的明显短板跑通 Demo 之后我们梳理了它不适合直接上生产的几个原因Demo 阶段做法生产存在的问题单机运行 Python 脚本无法提供稳定服务无法水平扩展每次启动重新加载文档文档更新、向量增量入库都没有管理直接调用本地模型服务无鉴权、无限流、无并发控制日志打印在控制台无法追踪问题无法定位是哪一段链路失败单点部署模型服务或应用服务宕机业务直接中断参数写在代码里不同环境无法隔离配置更别提灰度发布所以进入生产阶段之前我们重新梳理了架构选型。3. 生产环境 AI 架构选型3.1 自建大模型服务还是调用外部 API第一个要决策的问题是模型能力从哪里来。调用外部大模型 API 的优点是开发效率高、模型能力强、不需要自己维护 GPU 服务但对很多企业来说数据出境、隐私合规、数据安全是不可接受的硬约束。尤其知识库内容涉及企业内部资料直接发给外部 API 在合规层面风险很大。自建大模型服务的优点是数据完全在内部掌握可控性强缺点是需要 GPU 资源、需要运维模型服务、模型能力相对商业 API 会弱一些。我们最终选择了自建这条路线同时为了降低部署和运维成本使用了 Ollama 作为模型推理服务。选择 Ollama 而不是直接用 vLLM、TensorRT-LLM 这类推理框架原因是在我们的场景下并发量不是极端高Ollama 的部署简单、模型管理方便、API 兼容 OpenAI 格式后续替换模型也比较容易。如果你们的生产环境并发量很高或者对推理延迟有严格的要求建议调研 vLLM 等专用推理框架如果团队运维能力有限Ollama 或同类轻量方案也可以作为起点但要注意压测。3.2 整体架构分层生产环境架构我们在 Demo 的单机脚本上做了分层设计整体架构如下用户 → 统一 API 网关 → AI 应用服务 → 检索服务 → 向量数据库 ↓ 大模型推理服务各层职责如下API 网关负责统一的入口、鉴权、限流、请求日志。AI 应用服务负责编排“检索 生成”流程接收请求、调用下游服务、组织返回。检索服务对知识库内容做向量化、切分、检索数据更新也由这一层管理。向量数据库存储文档向量提供相似度检索能力。大模型推理服务部署开源大模型对外提供 OpenAI 兼容的推理接口。应用服务我们选择了 Java Spring Boot 体系主要考虑到团队技术栈和后续维护成本检索服务和向量化部分保留了 Python因为生态最成熟方便调试。跨语言之间通过 HTTP 接口通信。如果你不想维护两套语言体系也可以全部使用 Java 生态比如 Spring AI 中已经封装了 ChatModel、EmbeddingModel、VectorStore 等抽象可以直接对接 Ollama、Chroma 等组件。两种方案没有绝对优劣核心是团队能不能长期维护。3.3 模型部署方式选择本地模型部署是这次架构选型的另一个重点。我们对比了三种方案方案优势劣势适用场景Ollama安装简单模型管理方便API 兼容 OpenAI高并发性能一般中小并发、快速交付vLLM高吞吐高并发支持连续批处理部署复杂度高显存要求高高并发场景调用外部 API模型能力强免运维数据出网合规风险非敏感数据场景最终选型为 Ollama 部署模型原因是我们的并发规模可控且希望在保证数据安全的前提下缩短交付周期。这里补充一个重要经验不要一上来就追求最大规模的模型。先明确业务能接受的回答质量底线和推理延迟上限再选择模型大小。我们实际测试过 7B、14B、32B 级别的模型最终选了 14B 级别因为 7B 在专业知识问答上准确率不够32B 对 GPU 资源要求高延迟也大。生产环境要在质量、成本、延迟之间找平衡。3.4 向量数据库选型向量数据库也做了对比。Chroma开发体验好适合本地跑 Demo但生产环境的分布式和高可用能力较弱。Milvus / 开源版功能强支持分布式但部署和运维成本较高。其他方案如果团队已重度使用 Elasticsearch也可以用 ES 的向量检索能力减少引入新组件。我们考虑到当前知识库数据量还在可控范围内先用的是轻量方案后续数据量增长再迁移至专业向量数据库。这里的重点是向量数据库的选型要和知识库的数据量、更新频率、检索性能要求绑定不要盲目引入重组件。4. 生产环境部署实施4.1 整体服务拆分生产环境最终拆成了以下几类服务ai-gateway # 统一入口鉴权、限流、路由 ai-app-server # AI 应用编排服务Java Spring Boot ai-retrieval-server # 检索服务Python FastAPI ai-knowledge-api # 知识库管理接口文档上传、切片、向量化 vector-db # 向量数据库 ollama-server # 大模型推理服务服务之间通过内网 HTTP 通信不直接暴露端口到公网。4.2 模型推理服务部署Ollama 在 Linux 服务器上安装之后默认监听 11434 端口。生产环境我们建议通过 systemd 管理并设置环境变量来控制模型加载方式。安装命令curl -fsSL https://ollama.com/install.sh | sh启动服务systemctl start ollama systemctl enable ollama拉取模型ollama pull qwen2.5:14b生产环境建议通过 systemd 环境变量配置 Ollama 的并发参数默认并发不一定适合你的场景[Service] EnvironmentOLLAMA_NUM_PARALLEL2 EnvironmentOLLAMA_MAX_LOADED_MODELS1 EnvironmentOLLAMA_KEEP_ALIVE5m关于这几个参数再解释一下OLLAMA_NUM_PARALLEL表示同一个模型同时处理多少个请求。值设太高如果显存不够推理会变慢甚至出错设太低时并发上来后会排队。OLLAMA_MAX_LOADED_MODELS同时常驻显存的模型数量。如果只有一个模型设置为 1 即可避免多个模型切换导致显存反复加载。OLLAMA_KEEP_ALIVE模型在显存中保持加载的时间。太短会导致频繁冷加载响应变慢太长会持续占显存。按实际调用频率调整。修改环境变量后需要重启服务systemctl daemon-reload systemctl restart ollama4.3 应用服务 Spring Boot 接入大模型Java 应用服务我们使用 Spring Boot 3 Spring AI 来编排调用流程。以接入 Ollama 为例spring: ai: ollama: base-url: http://ollama-server:11434 chat: model: qwen2.5:14b options: temperature: 0.3Java 代码中调用模型import org.springframework.ai.chat.ChatClient; import org.springframework.ai.chat.messages.UserMessage; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.stereotype.Service; Service public class AiChatService { private final ChatClient chatClient; public AiChatService(ChatClient chatClient) { this.chatClient chatClient; } public String chat(String userQuestion, String context) { String promptContent 请基于以下知识库内容回答用户问题。 如果知识库内容不足以回答请明确说明。 知识库内容 %s 用户问题 %s .formatted(context, userQuestion); return chatClient.call(new Prompt(new UserMessage(promptContent))) .getResult() .getOutput() .getContent(); } }如果你无法确定所使用的 Spring AI 版本是否包含上述 API请先参考对应版本官方文档确认接口名。Spring AI 迭代速度较快不同版本之间 API 差异较大尤其是ChatClient的包路径和调用方式在新版本中有过调整。4.4 检索服务部署检索服务我们使用 FastAPI 封装了一组接口包含文档向量化和相似度检索。服务内部仍然使用 Ollama 的 embedding 模型做向量化。from fastapi import FastAPI from pydantic import BaseModel from langchain_community.embeddings import OllamaEmbeddings from langchain_community.vectorstores import Chroma app FastAPI() embeddings OllamaEmbeddings(modelbge-m3) vectorstore Chroma( persist_directory/data/vector_store, embedding_functionembeddings ) class SearchRequest(BaseModel): question: str k: int 5 class SearchResult(BaseModel): content: str score: float app.post(/search, response_modellist[SearchResult]) def search(request: SearchRequest): docs vectorstore.similarity_search_with_score( request.question, krequest.k ) return [ SearchResult(contentdoc.page_content, scorescore) for doc, score in docs ]启动服务时使用 Gunicorn Uvicorn 多进程方式避免单进程处理不了并发请求。gunicorn main:app -w 2 -k uvicorn.workers.UvicornWorker -b 0.0.0.0:8000这里需要根据服务器 CPU 核数和请求量调整-w参数。进程数通常设为 CPU 核数的 1 到 2 倍即可不是越大越好。4.5 Docker Compose 一键编排为了让整个环境可以快速复制部署我们用 Docker Compose 把应用服务、检索服务、向量数据库编排到一起。Ollama 是否容器化可以根据实际情况而定如果宿主机显存资源有限也可以直接在宿主机安装宿主环境的管理更直接一些。一个参考的docker-compose.yml如下version: 3.8 services: ai-app-server: image: registry.internal.example.com/ai-app-server:1.0.0 ports: - 8080:8080 environment: SPRING_AI_OLLAMA_BASE_URL: http://ollama-server:11434 RETRIEVAL_SERVICE_URL: http://ai-retrieval-server:8000 depends_on: - ai-retrieval-server ai-retrieval-server: image: registry.internal.example.com/ai-retrieval-server:1.0.0 volumes: - /data/vector_store:/data/vector_store environment: OLLAMA_BASE_URL: http://ollama-server:11434 depends_on: - ollama-server ollama-server: image: ollama/ollama:latest ports: - 11434:11434 volumes: - /data/ollama:/root/.ollama environment: OLLAMA_NUM_PARALLEL: 2 OLLAMA_KEEP_ALIVE: 5m注意镜像地址需要替换成你们自己的私有镜像仓库地址我这里只是一个示例。生产环境不建议从公网 Docker Hub 直接拉取业务镜像。容器启动后docker compose up -d进入 Ollama 容器拉取模型docker exec -it ollama-server ollama pull qwen2.5:14b docker exec -it ollama-server ollama pull bge-m34.6 知识库初始化首次落地时我们编写了一个初始化脚本把历史文档批量导入python scripts/init_knowledge_base.py \ --source-dir /data/docs \ --vector-dir /data/vector_store \ --chunk-size 500 \ --chunk-overlap 50脚本核心逻辑import os import glob from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain_community.document_loaders import TextLoader from langchain_community.embeddings import OllamaEmbeddings from langchain_community.vectorstores import Chroma def load_and_split(source_dir: str, chunk_size: int, chunk_overlap: int): text_splitter RecursiveCharacterTextSplitter( chunk_sizechunk_size, chunk_overlapchunk_overlap ) docs [] for file_path in glob.glob(os.path.join(source_dir, **/*.md), recursiveTrue): loader TextLoader(file_path, encodingutf-8) docs.extend(loader.load_and_split(text_splitter)) return docs def build_vector_store(docs, vector_dir: str, model: str): embeddings OllamaEmbeddings(modelmodel) vectorstore Chroma.from_documents( documentsdocs, embeddingembeddings, persist_directoryvector_dir ) return vectorstore if __name__ __main__: docs load_and_split(/data/docs, 500, 50) build_vector_store(docs, /data/vector_store, bge-m3) print(f共导入文档块: {len(docs)})在企业真实场景中文档格式不只 Markdown还有 PDF、Word 等需要根据实际情况开发对应的文档解析器。切分的 chunk_size 也需要根据文档类型调整不要所有文档都用同一套参数。5. 生产环境优化关键点5.1 Prompt 与上下文管理Demo 阶段的 Prompt 比较简单生产环境则要更严格地控制 Prompt。以下是我们线上使用的版本结构系统角色你是企业内部知识助手回答必须基于提供的知识库内容。 约束条件 1. 如果知识库内容不包含答案请如实说明“未在知识库中找到相关内容”不要编造。 2. 回答保持简洁、准确。 3. 禁止输出与问题无关的内容。 知识库内容 {context} 用户问题 {question}上下文控制上需要注意两个问题。第一检索到的文本块不要无脑拼接超出模型上下文窗口会导致请求失败或回答质量下降。需要对检索结果做截断或过滤。第二如果企业文档中存在相互矛盾的内容Prompt 中应要求模型指出矛盾而不是强行给出统一答案。这在多版本制度文档场景中很常见。5.2 缓存设计相同或相似的问题如果每次都重新走一遍检索 推理成本和延迟都很高。我们引入了一层结果缓存Service public class AnswerCacheService { private final CacheString, String answerCache Caffeine.newBuilder() .maximumSize(10000) .expireAfterWrite(Duration.ofHours(1)) .build(); public String getIfPresent(String question) { return answerCache.getIfPresent(question); } public void put(String question, String answer) { answerCache.put(question, answer); } }这里有一个关键点如何判断两个问题是否相同。我们采用了“先向量化再计算相似度”的语义缓存而不是简单的字符串匹配。当新问题与缓存中的问题相似度超过 0.95 时直接返回缓存结果。缓存的核心目的是降本效果非常明显。5.3 限流与降级生产环境必须考虑恶意请求和突发流量。我们在 API 网关层做了限流基于令牌桶算法实现。spring: cloud: gateway: routes: - id: ai-app uri: http://ai-app-server:8080 predicates: - Path/api/ai/** filters: - name: RequestRateLimiter args: redis-rate-limiter.replenishRate: 10 redis-rate-limiter.burstCapacity: 20降级策略方面当大模型推理服务的响应时间超过阈值时应用服务应快速失败而不是让请求长时间挂起。同时要设计好兜底文案不能直接把模型内部异常抛给用户。5.4 可观测性建设Demo 阶段不需要监控生产环境必须有完整的观测体系日志应用日志统一 JSON 格式输出包含 traceId。指标请求量、P95/P99 延迟、模型推理耗时、检索耗时、错误率。链路追踪跨服务调用需要 traceId 贯穿网关到检索到模型推理。在 Spring Boot 中我们通过过滤器为每个请求生成 traceIdimport jakarta.servlet.Filter; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletRequest; import jakarta.servlet.ServletResponse; import jakarta.servlet.http.HttpServletRequest; import org.slf4j.MDC; import org.springframework.stereotype.Component; import java.util.UUID; Component public class TraceIdFilter implements Filter { Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) { try { String traceId UUID.randomUUID().toString().replace(-, ); MDC.put(traceId, traceId); chain.doFilter(request, response); } catch (Exception e) { throw new RuntimeException(e); } finally { MDC.remove(traceId); } } }日志配置中加入 traceId 字段pattern%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - [%X{traceId}] - %msg%n/pattern没有可观测性生产环境排查问题就像盲人摸象这个环节不能省。6. 常见问题与排查思路这次部署过程中我们积累了不少排障经验下面按问题类型整理。6.1 显存不足导致模型加载失败问题现象常见原因解决思路Ollama 报错no space left on device或模型加载失败显存不足模型参数过大换用更小模型或降低并发参数推理时 OOM并发线程数过高调低OLLAMA_NUM_PARALLEL模型加载很慢KEEP_ALIVE设置太短调大OLLAMA_KEEP_ALIVE这里最直接的排查命令nvidia-smi确认 GPU 显存占用率。如果模型本身大小接近显存上限说明该模型不适合当前环境。6.2 检索结果相关性差问题现象常见原因解决思路回答完全没用到知识库内容Prompt 中知识库内容未正确传入检查检索服务返回的数据是否为空检索到的文本与问题无关chunk_size 过大或过小调整切分参数专业术语检索不到embedding 模型对领域词汇理解不足更换效果更好的 embedding 模型多个文档内容冲突未做内容质量过滤从知识库源头清洗文档实际调优时可以从单条样本开始逐步检查检索结果。如果检索出来的文本块本身就不相关再优化 Prompt 也没用。6.3 服务间调用超时问题现象常见原因解决思路应用服务请求检索服务超时检索服务单进程处理不过来增加 Gunicorn worker 数请求 Ollama 超时模型推理排队调大OLLAMA_NUM_PARALLEL或并发过高时限流接口整体响应慢检索 推理串行耗时太长对相似问题做缓存排查时先把一次完整请求拆成多段计时定位耗时集中在哪个环节再针对性处理。6.4 文档更新后检索结果没变化问题现象常见原因解决思路新文档上传后问答结果没有变化向量库没有增量更新实现增量入库逻辑删除了旧文档回答仍引用旧内容旧向量未被删除入库时保存文档 ID更新时先删后插向量库持久化目录被重新创建容器重启后挂载路径配置错误检查 volume 挂载如果向量库和原始文档之间没有建立 ID 映射生产环境做增量更新会非常痛苦。建议文件名或文档 ID 作为元数据写入向量库。7. 从 Demo 到生产的关键差异复盘最后想把这次从 Demo 到生产的完整过程做一个横向总结这部分也是我认为最值得反复看的。维度Demo 阶段生产环境目标验证可行性稳定支撑业务数据安全不关注必须合规数据不出内网架构单脚本网关 应用服务 检索服务 推理服务并发无必须压测限流模型本地或 API 都行根据质量、成本、延迟选型知识库一次性导入增量更新ID 映射清洗可观测性控制台打印日志、指标、链路追踪容错无降级、兜底、快速失败部署本地运行容器化环境隔离配置管理安全无鉴权网关鉴权、内网隔离、最小权限关于“AI 架构选择”我的核心观点是不要为了追求新技术而引入复杂组件也不要因为团队熟悉某套技术栈就盲目套用。架构选型的本质是在约束条件下做取舍。对于大多数企业内部 AI 应用优先考虑数据安全、可维护性和成本可控其次才是模型能力的极致表现。模型大小选择上建议按这个步骤来先收集一批企业真实知识问答作为评测样本。用不同规模的模型分别跑一遍。从回答准确率、延迟、显存占用三个维度打分。选一个综合分最高的方案而不是直接上最大模型。部署方式上如果团队运维能力有限Docker Compose 已经能覆盖中小规模场景如果后续并发增长明显再逐步迁移到 Kubernetes 并把大模型推理层独立出来使用 vLLM 等高性能推理框架。8. 一些可以复用的工程建议结合这次实战整理一份我们团队后续在 AI 项目中固定使用的工程化清单。如果你即将把一个 AI Demo 推向生产建议逐条对应检查。第一配置管理从第一天就要做。不同环境开发、测试、生产的模型地址、数据库地址、密钥都不一样。不要把配置写死在代码里。使用 Spring 的application-{profile}.yml或配置中心都可以关键是环境隔离要明确。第二所有依赖外部服务的调用都必须有超时和重试策略。这里的“外部服务”包括 Ollama、向量数据库、检索服务。任何一个下游服务慢都可能拖垮整个应用。第三知识库数据要进行版本管理。Demo 阶段可以随便导入文档生产环境一旦知识库内容更新出错会影响所有用户。这里建议至少做到文档入库前有审核流程、入库时记录版本号、必要时支持回滚。第四模型服务和业务服务要分开部署。把模型推理和业务逻辑放在同一台机器同一个进程里只适合验证阶段。模型推理依赖 GPU 资源而业务服务可能随时扩容缩容混部会影响稳定性。第五压测一定要做而且要在接近真实的数据集上做。我们当时用 200 道真实业务问题做并发压测时发现了检索服务在并发 10 以上就开始超时的问题。如果压测数据只用简单问答很多问题测不出来。第六正式上线前准备一份应急预案。如果大模型服务挂了怎么办如果知识库向量库损坏怎么办如果某个文档的内容是错误信息被大量用户检索到怎么办每一条都要有明确的响应动作。9. 下一步可以继续深入的方向如果这篇文章的读者也希望在企业 AI 方向持续深入我觉得可以从以下几个方面继续学习大模型推理框架深入了解 vLLM、TensorRT-LLM 的原理和使用方式适合高并发场景。检索增强生成RAG包括查询改写、重排序Rerank、混合检索关键词 向量等进阶方向。Agent 架构如果你希望 AI 应用不只是“问答机器人”还要具备工具调用、多步任务规划能力可以研究 Agent 架构设计。AI 应用的可观测性标准比如如何评估生成内容的质量如何追踪模型幻觉事件这些在生产环境一定会遇到。多模态如果后续文档中包含图片、扫描件需要多模态模型参与解析和生成。本文记录的就是一次相对完整的企业 AI 落地过程。不同团队的技术栈、资源规模、业务约束都不一样具体方案输出了差异但思考问题的框架——从 Demo 到生产的差距在哪里、每一步决策的取舍依据是什么——是共通的。希望这篇复盘能帮正在做类似项目的你少踩一些坑。
返回列表