上一篇 下一篇 分享链接 返回 返回顶部

把 AI 编程助手搬进内网:一套可落地的私有化部署实践(含源码)

发布人:慈云数据-客服中心 发布时间:22小时前 阅读量:4

AI编程 私有化部署方案|附源码

在企业软件研发场景中,AI 编程助手已经从“尝鲜工具”逐渐变成提升研发效率的重要基础设施。无论是代码补全、单元测试生成、接口文档编写,还是代码审查、遗留系统理解,AI 都能显著降低重复劳动成本。

但与此同时,很多企业并不能直接使用公网 AI 编程产品,原因包括:

  • 源代码不能上传到第三方平台;
  • 内部业务逻辑、数据库结构、接口协议涉及商业机密;
  • 行业合规要求较高,例如金融、政务、医疗、工业软件等;
  • 研发环境部署在内网,无法访问公网服务;
  • 希望统一接入权限、审计日志、模型管理和成本控制。

因此,AI 编程私有化部署成为越来越多团队的选择。本文将给出一套可落地的私有化部署方案,并附带关键源码示例,帮助你快速搭建企业内部 AI 编程助手。


一、方案目标

本文方案的目标不是简单跑通一个大模型,而是构建一套适合研发团队长期使用的 AI 编程基础设施。

核心目标如下:

  1. 代码不出内网
    开发者的代码、注释、接口文档、数据库结构等敏感信息只在企业内部流转。

  2. 兼容主流开发工具
    支持 VS Code、JetBrains 系列 IDE,或通过 OpenAI API 兼容协议接入各类插件。

  3. 支持代码补全与对话问答
    既可以实现类似 Copilot 的代码生成,也可以通过 Chat 方式解释代码、生成测试、重构方法。

  4. 统一网关管理
    所有模型请求通过内部 AI Gateway 转发,便于权限控制、日志审计、限流和模型切换。

  5. 可扩展 RAG 知识库
    将企业内部代码规范、技术文档、接口文档、组件库说明等接入知识库,让 AI 回答更贴近企业实际。

  6. 部署成本可控
    可根据团队规模选择单机 GPU、GPU 服务器集群,甚至 CPU 低成本实验环境。


二、整体架构设计

推荐架构如下:

┌──────────────────────────────┐
│          开发者 IDE           │
│ VS Code / JetBrains / Web UI │
└───────────────┬──────────────┘
                │ OpenAI Compatible API
                ▼
┌──────────────────────────────┐
│          AI Gateway           │
│  鉴权 / 限流 / 日志 / 路由      │
└───────────────┬──────────────┘
                │
     ┌──────────┴──────────┐
     ▼                     ▼
┌──────────────┐     ┌──────────────┐
│  LLM 推理服务 │     │  Embedding服务 │
│  Qwen/DeepSeek│     │ bge/e5/text2vec│
└───────┬──────┘     └───────┬──────┘
        │                    │
        ▼                    ▼
┌──────────────┐     ┌──────────────┐
│  模型文件存储 │     │ 向量数据库     │
│  /models      │     │ Milvus/Qdrant │
└──────────────┘     └──────────────┘
                │
                ▼
┌──────────────────────────────┐
│       企业知识库 / 代码仓库     │
│ GitLab / Wiki / API Docs     │
└──────────────────────────────┘

这套架构将能力分成几个层次:

  • 客户端层:开发者实际使用的 IDE 插件或 Web 页面;
  • 网关层:负责统一接入、权限认证、日志审计、请求转发;
  • 模型层:部署大语言模型、代码模型、Embedding 模型;
  • 知识层:接入企业内部文档、代码仓库、规范制度等;
  • 存储层:保存模型文件、向量索引、访问日志和配置数据。

三、模型选型建议

AI 编程场景对模型能力要求较高,尤其关注代码理解、代码生成、长上下文和中文理解能力。

1. 代码生成模型

可选模型包括:

模型 特点 适用场景
Qwen2.5-Coder 中文友好,代码能力强 企业通用 AI 编程
DeepSeek-Coder 代码推理能力较强 复杂代码生成、算法辅助
CodeLlama 开源生态成熟 英文代码场景
StarCoder2 代码补全表现较好 多语言代码补全
Yi-Coder 中文生态友好 国内企业研发

如果企业 GPU 资源有限,可以优先选择:

  • Qwen2.5-Coder-7B-Instruct
  • DeepSeek-Coder-6.7B-Instruct
  • Qwen2.5-Coder-14B-Instruct

如果拥有较强算力,例如 A800、H800、4090 多卡环境,可以考虑 32B 以上模型。

2. Embedding 模型

用于知识库检索,推荐:

  • bge-large-zh-v1.5
  • bge-m3
  • m3e-base
  • text2vec-large-chinese

对于中英文混合文档,推荐 bge-m3,兼容性较好。

3. 推理框架

常见推理框架:

框架 特点
vLLM 高并发,吞吐高,适合生产
Ollama 部署简单,适合快速验证
Text Generation WebUI 功能丰富,适合测试
llama.cpp 支持 CPU/量化模型,资源要求低
TGI HuggingFace 官方推理服务

生产环境建议使用 vLLM,因为它支持 OpenAI API 兼容接口,便于直接接入 IDE 插件和企业网关。


四、部署环境准备

以下是一套推荐环境:

操作系统:Ubuntu 22.04 LTS
GPU:NVIDIA RTX 4090 / A10 / A100 / A800 / H800
显存:24GB 起步,推荐 48GB+
内存:64GB 起步
磁盘:500GB SSD 起步
Docker:24+
NVIDIA Driver:535+
CUDA:12.x

如果只是测试,可以使用一台 4090 服务器部署 7B 或 14B 量化模型。


五、Docker Compose 私有化部署

下面提供一份基础版 docker-compose.yml,包含:

  • vLLM 推理服务;
  • FastAPI AI Gateway;
  • Qdrant 向量数据库;
  • PostgreSQL 日志数据库。

目录结构

ai-coding-private/
├── docker-compose.yml
├── gateway/
│   ├── main.py
│   ├── requirements.txt
│   └── config.py
├── models/
│   └── Qwen2.5-Coder-7B-Instruct/
├── data/
│   ├── qdrant/
│   └── postgres/
└── scripts/
    └── ingest_docs.py

六、docker-compose.yml 源码

version: "3.9"

services:
  vllm:
    image: vllm/vllm-openai:latest
    container_name: ai-vllm
    restart: always
    ports:
      - "8000:8000"
    volumes:
      - ./models:/models
    command:
      [
        "--model", "/models/Qwen2.5-Coder-7B-Instruct",
        "--served-model-name", "private-coder",
        "--host", "0.0.0.0",
        "--port", "8000",
        "--max-model-len", "32768",
        "--gpu-memory-utilization", "0.90"
      ]
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: all
              capabilities: ["gpu"]

  gateway:
    build: ./gateway
    container_name: ai-gateway
    restart: always
    ports:
      - "9000:9000"
    environment:
      - VLLM_BASE_URL=http://vllm:8000/v1
      - API_KEYS=dev-key-001,dev-key-002
    depends_on:
      - vllm
      - postgres
      - qdrant

  qdrant:
    image: qdrant/qdrant:latest
    container_name: ai-qdrant
    restart: always
    ports:
      - "6333:6333"
    volumes:
      - ./data/qdrant:/qdrant/storage

  postgres:
    image: postgres:15
    container_name: ai-postgres
    restart: always
    ports:
      - "5432:5432"
    environment:
      - POSTGRES_DB=ai_gateway
      - POSTGRES_USER=ai
      - POSTGRES_PASSWORD=ai_password
    volumes:
      - ./data/postgres:/var/lib/postgresql/data

七、AI Gateway 源码

网关的作用非常关键。不要让 IDE 插件直接访问模型服务,否则后续很难做权限控制、审计、限流和模型切换。

下面是一个简化版 FastAPI 网关,实现了:

  • API Key 鉴权;
  • OpenAI Chat Completions 兼容转发;
  • 请求日志记录;
  • 模型名称映射;
  • 后续可扩展限流与审计。

gateway/requirements.txt

fastapi==0.115.0
uvicorn==0.30.6
httpx==0.27.2
pydantic==2.8.2
python-dotenv==1.0.1

gateway/config.py

import os

VLLM_BASE_URL = os.getenv("VLLM_BASE_URL", "http://localhost:8000/v1")

API_KEYS = set(
    key.strip()
    for key in os.getenv("API_KEYS", "dev-key-001").split(",")
    if key.strip()
)

MODEL_MAPPING = {
    "gpt-4o-mini": "private-coder",
    "gpt-4": "private-coder",
    "private-coder": "private-coder"
}

gateway/main.py

import time
import uuid
from typing import Any, Dict

import httpx
from fastapi import FastAPI, Header, HTTPException, Request
from fastapi.responses import StreamingResponse, JSONResponse

from config import VLLM_BASE_URL, API_KEYS, MODEL_MAPPING

app = FastAPI(title="Private AI Coding Gateway")


def check_auth(authorization: str | None):
    if not authorization:
        raise HTTPException(status_code=401, detail="Missing Authorization header")

    if not authorization.startswith("Bearer "):
        raise HTTPException(status_code=401, detail="Invalid Authorization format")

    token = authorization.replace("Bearer ", "").strip()

    if token not in API_KEYS:
        raise HTTPException(status_code=403, detail="Invalid API Key")


def map_model(model_name: str) -> str:
    return MODEL_MAPPING.get(model_name, "private-coder")


@app.get("/health")
async def health():
    return {
        "status": "ok",
        "service": "private-ai-gateway",
        "upstream": VLLM_BASE_URL
    }


@app.post("/v1/chat/completions")
async def chat_completions(
    request: Request,
    authorization: str | None = Header(default=None)
):
    check_auth(authorization)

    req_id = str(uuid.uuid4())
    start_time = time.time()

    body: Dict[str, Any] = await request.json()
    body["model"] = map_model(body.get("model", "private-coder"))

    stream = body.get("stream", False)
    upstream_url = f"{VLLM_BASE_URL}/chat/completions"

    headers = {
        "Authorization": "Bearer EMPTY",
        "Content-Type": "application/json"
    }

    print({
        "request_id": req_id,
        "model": body.get("model"),
        "stream": stream,
        "messages_count": len(body.get("messages", []))
    })

    client = httpx.AsyncClient(timeout=300)

    if stream:
        async def event_stream():
            try:
                async with client.stream(
                    "POST",
                    upstream_url,
                    json=body,
                    headers=headers
                ) as response:
                    async for chunk in response.aiter_bytes():
                        yield chunk
            finally:
                await client.aclose()
                cost = round(time.time() - start_time, 3)
                print({
                    "request_id": req_id,
                    "cost_seconds": cost,
                    "stream": True
                })

        return StreamingResponse(
            event_stream(),
            media_type="text/event-stream"
        )

    try:
        async with client:
            response = await client.post(
                upstream_url,
                json=body,
                headers=headers
            )

        cost = round(time.time() - start_time, 3)
        print({
            "request_id": req_id,
            "cost_seconds": cost,
            "status_code": response.status_code
        })

        return JSONResponse(
            status_code=response.status_code,
            content=response.json()
        )

    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

gateway/Dockerfile

FROM python:3.11-slim

WORKDIR /app

COPY requirements.txt /app/requirements.txt

RUN pip install --no-cache-dir -r requirements.txt

COPY . /app

EXPOSE 9000

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "9000"]

八、启动部署

在项目根目录执行:

docker compose up -d

查看服务状态:

docker ps

测试 vLLM 是否正常:

curl http://localhost:8000/v1/models

测试网关:

curl http://localhost:9000/health

测试对话接口:

curl http://localhost:9000/v1/chat/completions \
  -H "Authorization: Bearer dev-key-001" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "private-coder",
    "messages": [
      {
        "role": "system",
        "content": "你是企业内部AI编程助手,擅长Java、Python、Go和前端工程。"
      },
      {
        "role": "user",
        "content": "请帮我写一个Python函数,实现批量读取目录下所有JSON文件并合并为一个列表。"
      }
    ],
    "temperature": 0.2
  }'

如果返回正常,说明基础私有化 AI 编程服务已经跑通。


九、VS Code 接入方案

私有化 AI 编程最重要的是接入开发工具。这里推荐使用支持 OpenAI API 兼容协议的插件,例如 Continue。

Continue 配置示例

在 VS Code 中安装 Continue 插件后,修改配置文件:

{
  "models": [
    {
      "title": "Private Coder",
      "provider": "openai",
      "model": "private-coder",
      "apiBase": "http://你的服务器IP:9000/v1",
      "apiKey": "dev-key-001"
    }
  ],
  "tabAutocompleteModel": {
    "title": "Private Coder Autocomplete",
    "provider": "openai",
    "model": "private-coder",
    "apiBase": "http://你的服务器IP:9000/v1",
    "apiKey": "dev-key-001"
  }
}

配置完成后,开发者即可在 VS Code 中使用私有模型进行:

  • 解释代码;
  • 生成函数;
  • 编写单元测试;
  • 生成接口文档;
  • 重构代码;
  • 修复 Bug;
  • 编写 SQL;
  • 生成正则表达式;
  • 代码审查。

十、企业知识库 RAG 扩展

仅仅部署大模型还不够。企业内部研发通常有大量私有知识,例如:

  • 统一技术规范;
  • 数据库设计规范;
  • 微服务接口文档;
  • 前端组件库说明;
  • CI/CD 流程;
  • 运维手册;
  • 历史事故复盘;
  • 业务术语表;
  • 老项目代码说明。

这些内容如果不接入 AI,模型回答就容易“泛泛而谈”。因此需要建设 RAG 知识库。

RAG 的基本流程如下:

文档采集 → 文本切分 → 向量化 → 写入向量数据库 → 用户提问 → 相似度检索 → 拼接上下文 → 大模型回答

下面给出一个简化版文档入库脚本。

scripts/ingest_docs.py

import os
import uuid
import requests
from qdrant_client import QdrantClient
from qdrant_client.models import Distance, VectorParams, PointStruct

QDRANT_URL = "http://localhost:6333"
COLLECTION_NAME = "dev_docs"

client = QdrantClient(url=QDRANT_URL)


def simple_split(text: str, chunk_size: int = 800, overlap: int = 100):
    chunks = []
    start = 0

    while start < len(text):
        end = start + chunk_size
        chunks.append(text[start:end])
        start = end - overlap

    return chunks


def fake_embedding(text: str):
    """
    示例函数:生产环境请替换为真实 Embedding 模型接口。
    例如 bge-m3、bge-large-zh-v1.5。
    """
    import random
    random.seed(hash(text))
    return [random.random() for _ in range(1024)]


def init_collection():
    collections = client.get_collections().collections
    names = [c.name for c in collections]

    if COLLECTION_NAME not in names:
        client.create_collection(
            collection_name=COLLECTION_NAME,
            vectors_config=VectorParams(
                size=1024,
                distance=Distance.COSINE
            )
        )


def ingest_file(file_path: str):
    with open(file_path, "r", encoding="utf-8") as f:
        text = f.read()

    chunks = simple_split(text)

    points = []
    for idx, chunk in enumerate(chunks):
        vector = fake_embedding(chunk)

        points.append(
            PointStruct(
                id=str(uuid.uuid4()),
                vector=vector,
                payload={
                    "file_path": file_path,
                    "chunk_index": idx,
                    "content": chunk
                }
            )
        )

    client.upsert(
        collection_name=COLLECTION_NAME,
        points=points
    )

    print(f"已入库:{file_path},切片数:{len(points)}")


def ingest_dir(dir_path: str):
    init_collection()

    for root, _, files in os.walk(dir_path):
        for name in files:
            if name.endswith((".md", ".txt")):
                ingest_file(os.path.join(root, name))


if __name__ == "__main__":
    ingest_dir("./docs")

生产环境中,需要将 fake_embedding 替换为真实 Embedding 服务。例如可以单独部署一个 Embedding API,或者使用 sentence-transformers 本地加载模型。


十一、AI 编程助手的典型 Prompt 模板

私有化部署后,为了提升使用效果,建议为团队设计统一 Prompt 模板。

1. 代码审查 Prompt

你是资深软件架构师,请从以下角度审查代码:

1. 是否存在明显 Bug;
2. 是否有性能问题;
3. 是否有安全风险;
4. 是否符合可读性和可维护性要求;
5. 是否符合企业编码规范;
6. 是否可以简化或重构。

请按照以下格式输出:

- 总体评价
- 发现的问题
- 修改建议
- 修改后的示例代码

2. 单元测试生成 Prompt

请为下面代码生成单元测试,要求:

1. 覆盖正常场景;
2. 覆盖异常场景;
3. 覆盖边界条件;
4. 使用项目当前测试框架;
5. 测试名称清晰表达业务含义;
6. 如需要 Mock,请给出 Mock 方式。

3. 老项目解释 Prompt

请解释下面代码的业务含义和执行流程,要求:

1. 先总结整体作用;
2. 再逐段解释关键逻辑;
3. 标记潜在风险;
4. 给出重构建议;
5. 如果涉及数据库或外部接口,请说明依赖关系。

十二、安全与合规设计

企业私有化部署不能只关注“能不能用”,还要关注“是否可控”。

建议至少实现以下安全能力:

1. 访问鉴权

每个开发者、团队或系统分配独立 API Key。后续可以进一步接入:

  • LDAP;
  • OAuth2;
  • 企业微信;
  • 飞书;
  • 钉钉;
  • 内部 SSO。

2. 请求审计

建议记录以下信息:

  • 请求人;
  • 请求时间;
  • 使用模型;
  • Token 消耗;
  • 请求来源 IP;
  • 是否命中敏感规则;
  • 响应耗时;
  • 错误状态。

但要注意:不要默认完整保存用户代码内容。如果必须保存,应进行脱敏和权限隔离。

3. 敏感信息过滤

可以在网关层增加规则,拦截以下内容:

  • 密码;
  • Token;
  • 私钥;
  • 数据库连接串;
  • 生产环境账号;
  • 身份证、手机号等个人信息。

4. 网络隔离

推荐部署方式:

开发网段 → AI Gateway → 模型服务

模型服务不直接暴露给开发者,只允许网关访问。这样可以避免越权调用和绕过审计。


十三、性能优化建议

AI 编程场景常见性能瓶颈包括首 Token 延迟、并发能力不足、显存不够、长上下文变慢等。

可以从以下方面优化:

  1. 使用 vLLM 提高吞吐
    vLLM 的 PagedAttention 对多并发场景效果明显。

  2. 控制上下文长度
    不要盲目设置超长上下文。代码问答一般 16K 到 32K 已经够用。

  3. 使用量化模型
    显存不足时可使用 AWQ、GPTQ、GGUF 等量化版本。

  4. 区分补全模型和对话模型
    代码补全要求低延迟,对话问答要求质量,可以分开部署。

  5. 增加缓存
    对重复 Prompt、文档问答、规范解释等场景增加缓存。

  6. 模型路由
    简单问题使用小模型,复杂重构和架构分析使用大模型。


十四、生产环境推荐配置

小团队配置

适合 5 到 20 人研发团队:

GPU:1 张 RTX 4090 24GB
模型:Qwen2.5-Coder-7B-Instruct
推理:vLLM
向量库:Qdrant
网关:FastAPI

中型团队配置

适合 20 到 100 人研发团队:

GPU:2 到 4 张 RTX 4090 / L20 / A800
模型:Qwen2.5-Coder-14B 或 32B
推理:vLLM 多实例
网关:Nginx + FastAPI
向量库:Milvus / Qdrant
日志:PostgreSQL + Loki
监控:Prometheus + Grafana

大型企业配置

适合 100 人以上研发团队:

GPU:A800 / H800 集群
模型:代码模型 + 通用模型 + Embedding模型
调度:Kubernetes
网关:统一 AI Gateway
权限:SSO / LDAP / RBAC
审计:集中日志平台
知识库:多租户 RAG
监控:全链路可观测

十五、落地实施路线

建议按以下阶段推进:

第一阶段:内部验证

目标是快速跑通。

  • 部署 7B 或 14B 代码模型;
  • 接入 VS Code;
  • 选择 3 到 5 名开发者试用;
  • 收集常见问题和 Prompt;
  • 验证响应速度和代码质量。

第二阶段:团队试点

目标是形成可复用流程。

  • 增加 API Key 管理;
  • 增加日志审计;
  • 接入团队规范文档;
  • 建立使用指南;
  • 输出最佳实践 Prompt;
  • 统计使用频率和效率提升。

第三阶段:企业推广

目标是平台化。

  • 接入统一身份认证;
  • 支持多模型路由;
  • 建设企业知识库;
  • 接入 GitLab、Jira、Wiki;
  • 建立安全审计机制;
  • 对不同团队开放独立空间。

十六、常见问题

1. 私有化 AI 编程一定需要 GPU 吗?

生产环境建议使用 GPU。CPU 也能跑小模型或量化模型,但速度较慢,不适合团队日常使用。

2. 7B 模型够不够?

对于普通代码解释、函数生成、简单重构,7B 模型可以满足入门需求。复杂架构分析、跨文件理解、复杂算法生成,建议使用 14B、32B 或更大模型。

3. 是否可以完全替代程序员?

不能。AI 编程助手适合辅助开发,不能替代工程设计、业务判断、安全审查和最终责任。企业应将其定位为“研发效率工具”,而不是“自动交付系统”。

4. 私有化后效果一定比公网产品好吗?

不一定。公网产品通常使用更强大的闭源模型。私有化的优势在于安全、可控、可定制。通过接入企业知识库和规范,私有化方案在内部业务场景中可以获得更高匹配度。


十七、总结

AI 编程私有化部署的核心价值,不只是把一个大模型部署到内网,而是建设一套面向研发流程的智能基础设施。

一套完整方案至少应包括:

  • 私有大模型推理服务;
  • OpenAI API 兼容网关;
  • IDE 插件接入;
  • API Key 鉴权;
  • 请求审计;
  • 企业知识库 RAG;
  • 敏感信息防护;
  • 性能监控和模型路由。

本文提供的 Docker Compose、FastAPI Gateway、VS Code 配置和知识库入库脚本,可以作为企业内部 AI 编程平台的最小可用版本。后续可以在此基础上继续扩展权限系统、管理后台、多模型调度、RAG 检索增强、代码仓库索引和团队级数据隔离。

对于企业来说,AI 编程私有化不是一次性项目,而是长期研发平台建设的一部分。越早建立统一、可控、可扩展的 AI 编程基础设施,越能在未来的软件研发竞争中获得效率优势。

目录结构
全文