把大模型“搬进”公司:我们的研发部,正在被 LLM 重新定义
去年年底,我们研发部做了一次“豪赌”——把大模型(LLM)真正接到自己的业务线里来,而不是继续当一个只会聊天的玩具。从前端的代码补全,到后端的 Bug 定位,再到技术文档的自动生成,可以说,现在整个部门的日常流程里,LLM 的影子已经渗进了每一个环节。这篇文章就是一次复盘记录,把我们从选型、部署、微调到踩坑的全过程,原原本本拆给你看。如果你也正准备在公司内部给 LLM 找一个真正的落脚点,建议耐心读完。
我们不是算法团队,也没有专门的大模型研究员背景,就是一群做 Java、Python、前端出身的中后台研发,硬着头皮把这套东西啃了下来。所以这里不会堆一堆听不懂的公式,更多是决策层面的考量和工程上的取舍。这篇文章适合所有想在公司内部私有化部署大模型、准备用 LLM 改造研发流程,但又不希望被云厂商绑定的团队参考。
1. 内容整体设计与思路拆解
1.1 到底是自建还是调 API
先想清楚一件事:为什么我们不直接用现成的云端 API,非要折腾私有化?原因很现实——公司的代码仓库、内部文档、架构设计资料都属于敏感资产,不可能直接丢给外部接口。而且研发部用 LLM 的频率极高,要是按 token 计费,一个月下来这笔账也挺不好看。
所以我们的目标很明确:在公司内部搭建一套大模型服务,模型参数不需要太大,但响应速度要够快、可控性要够强。毕竟研发场景更多是代码补全、短文本分析、接口文档整理,而不是需要超长上下文的复杂推理。
考虑到部署成本和硬件限制,我们把目光锁定在 7B 到 14B 量级的开源模型上。这类模型可以用单张消费级显卡跑起来,也能通过 vLLM 这类推理加速框架做到很高的并发吞吐。至于 70B 级别的大模型,一是显卡资源确实紧张,二是很多内部场景根本用不满那个智力水平。
提示:如果你的团队没有 GPU 资源,最现实的路径还是先买云 API 跑通流程,验证场景确实有价值后,再考虑自建。千万别一上来就搞基建,否则很容易在运维泥潭里陷进去。
1.2 三个关键问题:数据安全、响应速度、可控性
把 LLM 搬进公司的本质,是要解决三个核心痛点。第一个是数据安全,所有请求必须留在内网,这决定了我们不可能走 SaaS 路线。第二个是响应速度,研发工具链里的代码补全如果等七八秒才出结果,程序员早就切换回肌肉记忆了。第三个是可控性,我们要能精细调控模型的行为边界,比如哪些代码可以生成、哪些敏感词需要屏蔽,这些东西靠黑盒 API 是无法做到的。
围绕这三个痛点,我们的整体架构思路分成了三层:
- 基础设施层:GPU 服务器 + vLLM 推理引擎,提供标准 OpenAI 风格接口
- 中间服务层:统一做 Prompt 编排、权限控制、日志审计、敏感信息过滤
- 业务应用层:IDE 插件、内部问答机器人、代码评审助手、文档生成工具
这样一来,模型和业务解耦,如果后面换更好的模型,中间层不用动,所有业务方拿到的接口协议保持一致。
1.3 一个容易被忽略的环节:Prompt 和模型能力边界
很多人以为把模型部署完就万事大吉了,实际上只走了一半。LLM 是个“上限很高、下限很低”的东西,同样的模型,遇到会写 Prompt 的人和一个纯小白,产出的效果天差地别。我们的做法是把高频场景的 Prompt 模板化,沉淀成一套公司内部的“技能库”,比如“代码评审助手”就是一套固定的前置指令,业务方要使用直接调用,不用自己琢磨怎么问。
这里还要强调一个观念:不是所有问题都该丢给大模型。像字符串处理、正则匹配、简单的数据清洗,用传统代码就能搞定,别让 LLM 干这种笨活,既慢又容易出错。我们的中间服务层加了一层路由逻辑,判断请求是否真的需要走 LLM,从源头节省算力。
2. 核心细节解析与实操要点
2.1 部署选型:vLLM 让我们省下了一整周的调优时间
模型服务的承载能力直接决定了 LLM 能不能真正融入研发流程。我们对比过 HuggingFace 原生的 transformers 接口、FastAPI 自建服务,还有专门做推理加速的 vLLM。先说结论:vLLM 是目前私有化部署的最优解,原因是它在吞吐性能上做了大量优化,尤其是对连续批处理和 PagedAttention 的支持。
原生 transformers 方案适合做实验验证,一次处理一个请求,简单但慢。如果要对外提供服务,必须上 vLLM 或 TGI(Text Generation Inference)这类推理框架。我们在单卡 A100 上部署了一个 13B 参数的模型,用 vLLM 的 continuous batching 特性,实测单机可以稳定支撑 50 个并发请求,每 token 生成速度在 60 到 80 左右,完全够内部几十名研发同时使用。
部署命令很简洁,核心就是把模型路径传给 vLLM:
python -m vllm.entrypoints.openai.api_server \ --model /data/models/Qwen2.5-14B-Instruct \ --served-model-name internal-llm \ --tensor-parallel-size 1 \ --max-model-len 8192 \ --port 8000这里有几个关键参数值得解释一下。tensor-parallel-size表示用几张卡并行推理,我们的场景单张 A100 显存 80G,足够跑 14B 模型,所以设成 1。max-model-len是最大上下文长度,设太大显卡内存不够,设太小又浪费模型能力,8192 对我们当前所有任务都是够用的。启动之后,服务会暴露一个/v1/chat/completions接口,和 OpenAI 的格式完全一致,业务侧接入几乎零成本。
注意:上线前一定要做并发压测。我们刚开始只测了单请求的响应时间,感觉很满意,结果一上生产发现并发一高,部分请求直接超时。后来通过调节 vLLM 的
--max-num-seqs参数,限制同时处理的序列数,才解决了问题。
2.2 硬件配置的底线:显存决定模型上限
聊到大模型部署,硬件是绕不过去的话题。很多团队迟迟不敢动手,就是被硬件门槛吓到了。我想给大家一个相对清晰的参考——显存大小直接决定了你能跑多大的模型。
以目前主流的 7B 模型为例,如果用 FP16 精度,权重文件大约占用 14G 显存,再加上 KV Cache 和推理过程中的中间变量,单张 24G 显存的 3090/4090 就能跑起来。14B 模型权重约 28G,推荐用 40G 以上的 A100 或两张 3090 并行跑。如果只有 8G 到 12G 显存的显卡,也不是完全没戏,可以考虑用 4bit 量化后的模型,虽然效果有一点损失,但至少能跑起来做验证。
我们在实际部署时采用了 4bit 量化加 vLLM 的组合。毕竟研发过程中的代码补全和问答场景,对模型的精度要求不像学术评测那么苛刻,量化带来的轻微损失完全在可接受范围内。这个思路帮我们省下了近一半的显存开销,也让模型可以在更小的卡上部署。
2.3 理解 token、embedding 和 attention 这几个基础概念
在推进项目的过程中,我发现团队里很多研发第一次接触 LLM 时,会被一大堆概念绕晕。这里挑三个最容易混淆的,用大白话解释一遍。
Token 是模型理解文本的最小单位,可以粗略理解成“词的碎片”。中文里一个汉字可能对应一个或多个 token,代码里一个变量名也可能被拆成好几段。所以“部署大模型”这五个字,在模型眼里其实是几个 token 的序列。而这个项目的标题里要频繁提及的 LLM 大模型,本质上就是一个在不断预测“下一个 token 是什么”的超大函数。
Embedding 是把文本转成向量,代表语义上的坐标。它解决的是“如何让计算机理解文本相似性”的问题,比如“怎么部署大模型”和“大模型部署方法”这两句话,字面上完全不同,但 embedding 出来后的向量距离很近。这个能力在 RAG 知识库检索中非常关键。
Attention 机制则是大模型的“注意力焦点”。它让模型在生成每一个词时,不是平等看待前面的所有词,而是根据相关性分配权重。你可以理解成人在读代码时,眼睛会重点盯住变量名、方法签名,而不是每个字符都一样关注。 Attention 机制正是 Transformers 架构的核心,也是 GPT 这类模型能够理解长文本依赖的基石。
在给团队做内部培训时,我建议把这三个概念放在一起讲,因为它们串起了大模型的完整工作链路:文本切成 token → embedding 编码 → attention 加权计算 → 生成下一个 token。
2.4 RAG 与微调,两条路线如何选
刚接触 LLM 应用时,很多人会被“RAG”和“微调”这两个词搞糊涂。简单说:RAG 是给模型配一个实时更新的知识库,每次问答先去检索相关片段,再交给模型组织答案;微调是直接改变模型内部的权重,让它掌握某种固定的行为模式或特定领域的表达风格。
我们公司的内部知识库用了 RAG。原因很直接——知识库里的内容每周都在更新,如果走微调路线,意味着每次更新都要重新训练一次模型,成本太高了。RAG 的方案则是把公司文档、API 说明、历史代码片段提前切成块向量化,存入向量数据库,用户提问时先检索出最相关的内容,再让大模型基于检索结果作答。这样知识库的更新只需要重新跑一遍向量化流程,模型本身不用动。
至于微调,我们仅在两个场景下使用:一是让模型学会识别公司内部的代码规范,比如把所有的 logger 调用统一格式;二是针对特定的代码转换需求。前期我们完全用 RAG,先把业务跑通再考虑微调,这样风险更小、迭代更快。
2.5 微调框架怎么选:llama factory 的实战体验
当我们确实需要微调时,选了 llama factory 作为主要工具,它把数据处理、训练、推理封装成了一条完整的流水线。最友好的是,它支持 LoRA 这类高效微调方案,只用训练一小部分参数,显存需求大大降低。
LoRA 的原理可以这样理解:预训练好的模型权重保持不变,在旁边加一个小型可训练模块,训练时只调整这个小模块。这就像在一本出版好的字典上贴便利贴做批注,字典本体不重印,但查起来就有个人化注释了。这样微调的成本极低,14B 模型用单张 24G 显卡也能跑起来。
实操中,我们整理了一批公司内部的代码数据,格式是常见的指令-输入-输出结构。用 llama factory 的命令行工具跑 LoRA 训练,大约三个小时就完成了一个基础的代码规范对齐任务。如果团队连数据标注都还没准备好,我不建议急着微调,先用 RAG 和精心设计的 Prompt 顶上,效果不会差太多。
3. 实操过程与核心环节实现
3.1 从零搭建一条可用的 LLM 服务链路
下面是一条完整的从零搭建流程,已经在我们公司验证过多次,可以直接照抄:
第一,准备服务器。我们用的是一台带有单张 A100 80G 的 GPU 服务器,操作系统 Ubuntu 22.04,显卡驱动和 CUDA 环境需要提前装好。没有 GPU 服务器也没关系,目前主流的云厂商都有按小时计费的 GPU 实例,先用几天把链路跑通再决定是否长期租用。
第二,搭建 Python 环境。强烈建议用 conda 管理环境,避免依赖冲突。关键依赖包括 PyTorch、transformers、vLLM、accelerate。这里有一个常见的坑:transformers 和 vLLM 的版本需要匹配,版本相差太大会直接报错。
第三,下载模型权重。从 HuggingFace 仓库把模型文件拉到本地。这块不多展开,就是标准的模型下载流程。
第四,启动推理服务。用前面给过的 vLLM 命令,模型启动后,会在本机的 8000 端口暴露 OpenAI 风格接口。此时就可以进行简单的接口验证了。
第五,封装为企业内部 API 网关。由于 vLLM 原生接口缺少鉴权和审计能力,我们在前面加了一层网关,用来做身份校验、请求转发、敏感词过滤和日志记录。这样业务方拿到的是一个干净的接口,底下怎么部署的,他们完全不用关心。
第六,开发内部工具接入。第一个接入的是 IDE 插件,实现代码补全和解释;第二个是内部问答机器人,对接 RAG 知识库。从部署到真正产生生产力,我们整个流程只用了两周。
3.2 打造企业知识库问答:RAG 全流程实现
企业内部知识库问答,是我们目前使用频率最高的 LLM 应用场景。很多研发在踩坑之后问我们怎么做到的,这里把核心流程拆开讲。
整体链路分五步:文档加载和清洗、文本切块、Embedding 向量化、向量检索、LLM 总结回答。前两步很容易被低估,很多团队以为把所有 PDF 和 Word 一股脑切了扔进去就行,结果出来的回答质量惨不忍睹。关键在于文档清洗这一步,要把页眉页脚、目录、无意义符号全部去掉;切块大小也要控制,我们一般是 500 到 800 个字符一块,重叠 50 个字符,这样既能保证上下文完整性,又不会让检索结果太碎片化。
Embedding 模型我们选了国产的开源模型,中文效果非常出色,而且对代码文本也有不错的理解力。向量数据库用的开源方案,支持本地部署。检索时通过余弦相似度找出最相关的 4 到 6 个片段,然后拼接到 Prompt 里,让模型基于这些上下文给出答案。最后在回答底部附上来源片段,方便研发追溯原始文档。
这个流程跑通之后,我们内部的知识查找效率提升了非常多。以前找个老项目配置说明,要翻半天文档库;现在直接问机器人,几秒钟就能得到带出处的答案。这也让我们更加坚定了一个判断:大模型落地的第一站,不一定是炫酷的 Agent,先把自己内部的信息孤岛打通,就已经能创造巨大价值了。
3.3 代码评审助手:让 LLM 成为研发流程里的一员
代码评审是 LLM 在研发部最立竿见影的场景。以前,代码评审靠人肉盯,架构师和资深工程师的时间非常有限,很多代码只是走个过场。现在我们的流程是:程序员提交 Merge Request 后,自动触发 LLM 代码评审,输出潜在问题清单,人工再针对性的看一遍。
具体实现上,我们写了一个脚本,监听代码仓库的合并请求事件,提取变更的代码片段,组装成评审提示词,发给部署好的大模型接口。提示词里明确规定:检查代码风格、潜在空指针、SQL 注入、资源未关闭等问题,每个问题必须标注文件位置和行号区间。输出格式用 JSON 结构化返回,方便自动化处理。
用了一段时间后,我们总结出一个经验:LLM 评审不能替代人,但能把人从低水平问题中解放出来。现在人肉 Reviewer 主要关注架构合理性、业务逻辑正确性,代码规范类的问题全部交给 LLM 把关。实测下来,合并请求的平均评审周期从原来的两天缩短到半天,低级 Bug 的逃逸率也有显著下降。
3.4 代码补全和生成实践
代码补全是研发部几乎人人都要用的功能,也是最能“感知”到大模型存在感的应用。我们的做法是给 IDE 接入一个自建的代码补全插件,它会将当前光标前的代码上下文发送给本地部署的 LLM,让模型预测后续代码。
但这里有个现实问题,通用模型直接用于代码补全,效果不够理想,经常出现格式不对、自动补全了错误 API 的情况。我们的解决方案是组合拳:在 Prompt 中强调“只补全代码,不做解释”,并且把项目的语言类型、相关的接口签名拼进去。实践中,对于 Java 项目的模板代码、单元测试生成、SQL 编写这些场景,生成质量已经达到可用水平。
坦白说,代码补全如果想要达到商用效果,最优解是专门训练过的代码模型,这是目前开源生态里已经具备的,比如 CodeLlama 和 DeepSeek-Coder 系列。如果大家想在企业内部做代码补全,我建议先去下载一个代码专用模型跑跑看,再对比通用模型的效果,差异还是很明显的。
3.5 多模态模型:内部图表文档处理的新思路
我们当时只做了文本模型还不够,研发部有大量架构图、流程图、截图形式的报错信息,这类内容光靠文本模型处理不了。所以后续又扩了一条多模态的线,把视觉语言模型一起部署上了。
多模态模型能直接看图理解内容,比如你给它一张报错日志截图,它能帮你提取关键报错信息,甚至指出可能的原因。对于架构图,它可以按照图里的模块关系生成说明性的 Markdown 文档。这在写技术方案、做项目交接的时候非常有用,省掉了很多“看图说话”的苦力活。
多模态模型的部署成本和文本模型类似,主要看视觉编码器和语言部分的参数规模。我们的经验是,公司内部用多模态模型不需要追求极致理解能力,能看懂结构图、表格和截图就够了。这种模型可以单独开一个服务端口,和文本模型隔离,避免相互影响性能。
4. 常见问题与排查技巧实录
4.1 响应太慢,GPU 利用率上不去
在我们刚上线时,用户反馈最大宗的抱怨就是“响应慢”。第一反应是模型太大,显卡跑不动,但查了 GPU 利用率发现不到 30%。后来排查发现,瓶颈根本不在 GPU,而在 CPU 的 Token 预处理和 Python 进程切换开销上。
用 vLLM 部署时,如果发现 GPU 利用率上不去,优先看两个地方:一是--max-num-seqs是否限制了并发数;二是输入序列过短导致批处理效率低。我们的解决办法是提高并发度,同时把--max-model-len适当改小,减少显存中 KV Cache 的浪费。另外,切换到异步处理模式后,整体吞吐提升非常明显。
排查技巧:用
nvidia-smi看显存和利用率,用top看 CPU 进程,如果 CPU 跑满而 GPU 空闲,问题十有八九在数据预处理或线程调度上;如果 GPU 显存占满但利用率低,则可能是模型太大、batch 太小。
4.2 重复输出同一个词,模型死循环了
这是 LLM 部署中经典问题:回答到一半开始无限重复同一个标点或同一个词语。遇到这种情况,十有八九是因为采样参数中的repetition_penalty没设置,或者temperature设置得过高。
我们内部把temperature设为 0.7 到 0.8,repetition_penalty设为 1.1 到 1.2,基本告别了死循环问题。另外,如果接入的是代码场景,可以把top_p略微调低到 0.85,这样生成的代码更稳定,不会冒出一堆奇怪的变体。
这属于推理层的参数调优,很多人只关注模型选型,忽略了这些推理参数也能决定用户体验。我们把这些参数固化在网关层,业务调用方不用自己传,也避免了有人乱设参数导致线上翻车。
4.3 输出格式总是不听话,JSON 解析老是失败
很多研发接 LLM 接口时,最头疼的就是让模型稳定输出 JSON 格式。有时候多加一句解释,有时候少个括号,反反复复折腾人。我们的经验是两个手段配合使用:Prompt 强约束加解析容错。
Prompt 里的强约束写法包括:只输出 JSON 对象、不要 Markdown 代码块、不要添加说明性文字。但即使这样,模型偶尔还是会犯傻。所以网关层我们加了智能修复逻辑:如果解析失败,尝试截取大括号内的内容再解析,如果还是失败,就自动重试一次并加强约束。
这种方法不能保证 100% 成功,但能把失败率从 10% 压到 1% 以下。如果你们对稳定性要求更高,建议考虑用专门的结构化生成方案,或者在后端做更严格的 Schema 校验和字段规整。总之任何把 LLM 输出当“函数返回值”用的团队,都要做好容错的那一层。
4.4 大模型部署的五大常见坑
把项目踩过的坑统一整理成一张速查表,方便后来者对照:
| 坑点 | 表现 | 解决方案 |
|---|---|---|
| 模型下载失败 | 网络中断、磁盘空间不足 | 提前规划磁盘空间,至少要留模型体积的 2 倍 |
| CUDA 版本不匹配 | 服务启动报错 | 严格参考框架文档匹配 CUDA、PyTorch 版本 |
| GPU 显存不足 | 启动后 OOM | 改用量化模型,或减少最大上下文长度 |
| 并发请求雪崩 | 请求排队,响应超时 | 设置硬性并发上限,引入排队机制和熔断降级 |
| Prompt 注入 | 用户通过恶意输入让模型执行不当指令 | 网关层隔离系统提示词和用户输入,增加关键词过滤 |
4.5 模型权重的管理:不该被忽视的基建问题
大模型部署不只是技术问题,还有工程管理问题。模型文件动辄几十 GB,管理不善会引发混乱。我们内部用专门的文件服务管理模型权重,每个版本都有清晰的命名规范,类似Qwen2.5-14B-v1.2这样的格式。
为什么要这么在意这件事?因为模型会迭代,回滚是常态。比如某次微调后模型效果反而变差了,我们需要能快速切回之前的版本。如果模型文件管理混乱,线上部署出错后连回滚都做不了,那才是真正的灾难。服务端我们把模型路径做成可配置的,切换版本只需重启服务并修改配置,整个过程不用改业务代码。
经验:模型权重文件一定要和代码分开存储,用独立的目录或对象存储服务管理。千万别把模型文件提交进 Git 仓库,那会把仓库体积撑爆,而且下载也慢。
后记:LLM 进研发部不是终点,而是起点
把大模型搬进公司这件事,回过头来看,真正困难的地方其实不在工程实现,而在我们要不断“校正对 LLM 的预期”。它既不是魔法,也不是玩具,而是一个需要精心设计交互方式、持续维护知识库、反复调整推理参数的严肃工具。
我在这个项目里最大的体会是:先从小场景切入,快速跑通,用真实业务数据检验效果,再逐步扩大覆盖范围。不要想着一口气把所有环节全上大模型,那一定会被各种问题淹没。我们目前正在做的是把 Agent 能力引入自动化测试场景,让 LLM 自己生成测试用例并执行验证,这个过程还在打磨。
最后再分享一个小技巧:一定要让团队记录每一次的 Prompt 版本和对应效果,哪怕是只改了一个字。大模型的输出充满不确定性,你以为是玄学,其实大部分时候还是有迹可循的。有了记录,你才能在持续迭代中找到真正稳定的优化路径。LLM 重新定义研发部的过程刚刚开始,希望我们的经验能帮你少踩几个坑。