企业内网搭建AI办公平台:从部署架构到源码实现
AI办公 私有化部署方案|附源码
在企业数字化转型过程中,AI办公已经从“锦上添花”的工具,逐渐变成提升组织效率的基础设施。无论是智能文档问答、会议纪要生成、知识库检索、合同审阅、邮件润色,还是自动生成周报、日报、方案大纲,AI都能显著降低重复性劳动成本。
但是,对于很多企业来说,直接使用公有云AI产品会面临一些现实问题:
- 企业内部文档、合同、财务数据、客户资料不适合上传到第三方平台;
- 部分行业存在合规要求,例如政务、金融、医疗、教育、制造等;
- 需要对模型、知识库、权限、日志、审计进行统一管控;
- 希望将AI能力集成到现有OA、IM、CRM、ERP等系统中;
- 长期高频使用公有云API,成本不可控。
因此,越来越多企业开始考虑将AI办公能力进行私有化部署。本文将从整体架构、技术选型、部署流程、核心源码、功能扩展、安全策略等方面,完整介绍一套可落地的AI办公私有化部署方案。
一、方案目标
本方案的目标是搭建一套运行在企业内网或私有云环境中的AI办公平台,具备以下能力:
-
本地大模型对话
- 支持接入本地部署的大语言模型;
- 支持多轮对话、上下文记忆;
- 可用于写作、总结、翻译、润色、代码辅助等办公场景。
-
企业知识库问答
- 支持上传PDF、Word、Excel、Markdown、TXT等文档;
- 自动进行文本切分、向量化和入库;
- 用户提问时,从知识库中检索相关内容,再由大模型生成答案。
-
文档智能处理
- 自动生成会议纪要;
- 自动提取合同关键条款;
- 自动生成周报、月报、方案大纲;
- 支持文档摘要、改写、翻译。
-
权限与审计
- 支持用户登录;
- 支持不同部门、不同角色访问不同知识库;
- 记录用户提问、模型回答、文档上传、知识库检索日志。
-
私有化运行
- 所有数据均保存在企业内部;
- 大模型、向量库、数据库、后端服务、前端页面均可本地部署;
- 支持Docker一键部署。
二、整体架构设计
整套AI办公系统可以分为六个核心模块:
┌────────────────────────────┐
│ 前端页面 │
│ Chat UI / 知识库 / 文档处理 │
└──────────────┬─────────────┘
│ HTTP / WebSocket
┌──────────────▼─────────────┐
│ 后端服务 │
│ FastAPI / Flask / Spring AI │
└───────┬───────────┬────────┘
│ │
│ │
┌───────▼───┐ ┌───▼────────┐
│ 大模型服务 │ │ 向量数据库 │
│ Ollama等 │ │ Milvus/FAISS │
└───────┬───┘ └───┬────────┘
│ │
┌───────▼───────────▼────────┐
│ 企业知识库文档存储 │
│ PDF / Word / Excel / TXT │
└──────────────┬─────────────┘
│
┌──────────────▼─────────────┐
│ 关系型数据库 │
│ MySQL / PostgreSQL │
└────────────────────────────┘
1. 前端层
前端主要负责提供用户交互界面,包括:
- AI对话窗口;
- 知识库管理;
- 文档上传;
- 历史会话查看;
- 用户权限管理;
- 提示词模板管理。
技术上可以选择:
- Vue3 + Element Plus;
- React + Ant Design;
- Next.js;
- 普通HTML页面。
如果企业已有OA系统,也可以将AI办公作为一个独立模块嵌入。
2. 后端服务层
后端负责业务逻辑处理,包括:
- 用户鉴权;
- 会话管理;
- 文档上传与解析;
- 文本切分;
- 调用Embedding模型生成向量;
- 向量检索;
- 拼接Prompt;
- 调用大模型生成回答;
- 日志记录。
推荐使用:
- Python FastAPI;
- Java Spring Boot + Spring AI;
- Node.js NestJS。
本文源码示例采用 Python FastAPI,因为它开发效率高,和AI生态兼容性好。
3. 大模型服务层
私有化部署大模型可以使用以下方式:
| 部署方式 | 说明 |
|---|---|
| Ollama | 部署简单,适合快速落地 |
| vLLM | 推理性能好,适合高并发 |
| LM Studio | 图形化部署,适合测试 |
| Text Generation WebUI | 功能丰富 |
| TensorRT-LLM | 适合高性能GPU环境 |
企业初期建议使用 Ollama,因为它安装简单、模型管理方便、API调用友好。
可选模型包括:
- Qwen2.5;
- DeepSeek-R1-Distill;
- Llama3;
- ChatGLM;
- Baichuan;
- Yi。
例如部署Qwen模型:
ollama pull qwen2.5:7b
ollama run qwen2.5:7b
4. 向量数据库
知识库问答的核心是RAG,即检索增强生成。常见向量数据库有:
| 向量库 | 特点 |
|---|---|
| FAISS | 本地轻量,适合中小型知识库 |
| Milvus | 功能强大,适合企业级场景 |
| Chroma | 简单易用,适合原型开发 |
| Weaviate | 支持丰富数据结构 |
| pgvector | 与PostgreSQL结合,适合数据库统一管理 |
本文示例使用 Chroma,因为部署简单,适合快速验证。如果生产环境中文档数量较大,可以切换为Milvus或pgvector。
三、核心功能流程
1. 普通AI对话流程
用户输入问题
↓
后端接收请求
↓
加载历史上下文
↓
拼接Prompt
↓
调用本地大模型
↓
返回结果给前端
↓
保存会话日志
普通对话不依赖知识库,适合写作、翻译、润色、邮件生成等通用办公场景。
2. 知识库问答流程
用户提出问题
↓
对问题进行向量化
↓
在向量数据库中检索相似文档片段
↓
取Top-K相关内容
↓
将相关内容与用户问题拼接成Prompt
↓
调用大模型生成回答
↓
返回答案和引用来源
这种方式的优势是,大模型不需要重新训练,只需要把企业内部资料放入知识库,就能实现“基于企业资料的智能问答”。
3. 文档入库流程
上传文档
↓
解析文档文本
↓
清洗文本
↓
按固定长度切分
↓
生成Embedding向量
↓
写入向量数据库
↓
记录文档元数据
文档切分非常重要。如果切分太短,语义不完整;如果切分太长,检索不精准。通常建议每段控制在500到1000个中文字符左右,并设置一定重叠区域。
四、Docker私有化部署方案
下面给出一个最小可运行的部署方案,包含:
- Ollama大模型服务;
- FastAPI后端;
- Chroma向量库;
- Web前端;
- PostgreSQL数据库。
1. 项目目录结构
ai-office-private/
├── docker-compose.yml
├── backend/
│ ├── main.py
│ ├── requirements.txt
│ ├── rag.py
│ ├── llm.py
│ ├── document_loader.py
│ └── Dockerfile
├── frontend/
│ ├── index.html
│ └── nginx.conf
└── data/
├── uploads/
└── chroma/
五、Docker Compose源码
下面是 docker-compose.yml 示例:
version: "3.9"
services:
ollama:
image: ollama/ollama:latest
container_name: ai-office-ollama
ports:
- "11434:11434"
volumes:
- ./data/ollama:/root/.ollama
restart: always
postgres:
image: postgres:15
container_name: ai-office-postgres
environment:
POSTGRES_DB: ai_office
POSTGRES_USER: ai_user
POSTGRES_PASSWORD: ai_password
ports:
- "5432:5432"
volumes:
- ./data/postgres:/var/lib/postgresql/data
restart: always
backend:
build: ./backend
container_name: ai-office-backend
ports:
- "8000:8000"
environment:
OLLAMA_BASE_URL: http://ollama:11434
OLLAMA_MODEL: qwen2.5:7b
CHROMA_DIR: /app/data/chroma
UPLOAD_DIR: /app/data/uploads
volumes:
- ./data:/app/data
depends_on:
- ollama
- postgres
restart: always
frontend:
image: nginx:latest
container_name: ai-office-frontend
ports:
- "8080:80"
volumes:
- ./frontend/index.html:/usr/share/nginx/html/index.html
- ./frontend/nginx.conf:/etc/nginx/conf.d/default.conf
depends_on:
- backend
restart: always
六、后端源码
1. requirements.txt
fastapi==0.115.0
uvicorn==0.30.6
requests==2.32.3
python-multipart==0.0.9
chromadb==0.5.5
pypdf==4.3.1
python-docx==1.1.2
sentence-transformers==3.0.1
2. Dockerfile
FROM python:3.10-slim
WORKDIR /app
COPY requirements.txt /app/requirements.txt
RUN pip install --no-cache-dir -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
COPY . /app
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
3. llm.py
该文件用于调用Ollama本地大模型。
import os
import requests
OLLAMA_BASE_URL = os.getenv("OLLAMA_BASE_URL", "http://localhost:11434")
OLLAMA_MODEL = os.getenv("OLLAMA_MODEL", "qwen2.5:7b")
def chat_with_ollama(prompt: str) -> str:
url = f"{OLLAMA_BASE_URL}/api/generate"
payload = {
"model": OLLAMA_MODEL,
"prompt": prompt,
"stream": False
}
response = requests.post(url, json=payload, timeout=300)
response.raise_for_status()
data = response.json()
return data.get("response", "")
4. document_loader.py
该文件用于解析上传的文档。
import os
from pypdf import PdfReader
from docx import Document
def load_pdf(file_path: str) -> str:
reader = PdfReader(file_path)
texts = []
for page in reader.pages:
text = page.extract_text()
if text:
texts.append(text)
return "\n".join(texts)
def load_docx(file_path: str) -> str:
doc = Document(file_path)
texts = []
for paragraph in doc.paragraphs:
if paragraph.text.strip():
texts.append(paragraph.text.strip())
return "\n".join(texts)
def load_txt(file_path: str) -> str:
with open(file_path, "r", encoding="utf-8") as f:
return f.read()
def load_document(file_path: str) -> str:
ext = os.path.splitext(file_path)[1].lower()
if ext == ".pdf":
return load_pdf(file_path)
if ext == ".docx":
return load_docx(file_path)
if ext in [".txt", ".md"]:
return load_txt(file_path)
raise ValueError(f"暂不支持的文件类型:{ext}")
def split_text(text: str, chunk_size: int = 800, overlap: int = 120):
chunks = []
start = 0
while start < len(text):
end = start + chunk_size
chunk = text[start:end]
if chunk.strip():
chunks.append(chunk.strip())
start = end - overlap
return chunks
5. rag.py
该文件用于实现知识库向量化与检索。
import os
import chromadb
from sentence_transformers import SentenceTransformer
CHROMA_DIR = os.getenv("CHROMA_DIR", "./data/chroma")
client = chromadb.PersistentClient(path=CHROMA_DIR)
collection = client.get_or_create_collection(name="office_knowledge")
embedding_model = SentenceTransformer("BAAI/bge-small-zh-v1.5")
def embed_texts(texts):
vectors = embedding_model.encode(texts, normalize_embeddings=True)
return vectors.tolist()
def add_documents(chunks, filename: str):
embeddings = embed_texts(chunks)
ids = []
metadatas = []
for index, chunk in enumerate(chunks):
ids.append(f"{filename}_{index}")
metadatas.append({
"filename": filename,
"chunk_index": index
})
collection.add(
ids=ids,
documents=chunks,
embeddings=embeddings,
metadatas=metadatas
)
return len(chunks)
def search_documents(query: str, top_k: int = 5):
query_embedding = embed_texts([query])[0]
result = collection.query(
query_embeddings=[query_embedding],
n_results=top_k
)
documents = result.get("documents", [[]])[0]
metadatas = result.get("metadatas", [[]])[0]
return [
{
"content": doc,
"metadata": meta
}
for doc, meta in zip(documents, metadatas)
]
6. main.py
这是后端主入口。
import os
import shutil
from fastapi import FastAPI, UploadFile, File
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from llm import chat_with_ollama
from rag import add_documents, search_documents
from document_loader import load_document, split_text
UPLOAD_DIR = os.getenv("UPLOAD_DIR", "./data/uploads")
os.makedirs(UPLOAD_DIR, exist_ok=True)
app = FastAPI(title="AI办公私有化平台")
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
class ChatRequest(BaseModel):
message: str
class RagRequest(BaseModel):
question: str
top_k: int = 5
@app.get("/")
def health_check():
return {
"status": "ok",
"message": "AI办公私有化平台运行中"
}
@app.post("/api/chat")
def chat(req: ChatRequest):
prompt = f"""
你是企业内部AI办公助手,请使用专业、准确、简洁的方式回答用户问题。
用户问题:
{req.message}
"""
answer = chat_with_ollama(prompt)
return {
"answer": answer
}
@app.post("/api/upload")
async def upload_file(file: UploadFile = File(...)):
file_path = os.path.join(UPLOAD_DIR, file.filename)
with open(file_path, "wb") as buffer:
shutil.copyfileobj(file.file, buffer)
text = load_document(file_path)
chunks = split_text(text)
count = add_documents(chunks, file.filename)
return {
"filename": file.filename,
"chunks": count,
"message": "文档已成功入库"
}
@app.post("/api/rag")
def rag_chat(req: RagRequest):
docs = search_documents(req.question, req.top_k)
context = "\n\n".join([
f"资料来源:{item['metadata'].get('filename')}\n内容:{item['content']}"
for item in docs
])
prompt = f"""
你是企业内部知识库问答助手。
请严格基于以下资料回答用户问题。
如果资料中没有相关信息,请明确说明“知识库中未找到相关依据”,不要编造答案。
【知识库资料】
{context}
【用户问题】
{req.question}
请输出:
1. 简洁答案;
2. 依据说明;
3. 引用的资料来源。
"""
answer = chat_with_ollama(prompt)
return {
"answer": answer,
"references": docs
}
七、前端页面源码
为了方便演示,下面提供一个极简HTML页面。生产环境可以替换成Vue或React。
index.html
AI办公私有化平台
AI办公私有化平台
一、普通AI对话
二、上传知识库文档
三、知识库问答
nginx.conf
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html;
}
location /api/ {
proxy_pass http://backend:8000/api/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
八、部署步骤
1. 安装Docker和Docker Compose
在Linux服务器上执行:
curl -fsSL https://get.docker.com | bash
systemctl enable docker
systemctl start docker
安装Docker Compose插件:
docker compose version
如果未安装,可根据系统版本安装对应插件。
2. 启动服务
进入项目目录:
cd ai-office-private
docker compose up -d
查看服务状态:
docker ps
3. 拉取本地模型
进入Ollama容器:
docker exec -it ai-office-ollama bash
拉取模型:
ollama pull qwen2.5:7b
如果服务器GPU资源充足,可以使用更大的模型,例如:
ollama pull qwen2.5:14b
如果服务器资源有限,可以使用轻量模型:
ollama pull qwen2.5:3b
4. 访问系统
浏览器访问:
http://服务器IP:8080
后端接口地址:
http://服务器IP:8000
Ollama接口地址:
http://服务器IP:11434
九、服务器配置建议
AI办公私有化部署对硬件有一定要求,尤其是大模型推理。
1. 小型团队配置
适合10到30人内部试用:
CPU:8核以上
内存:32GB
GPU:可选,推荐RTX 3060 12GB或以上
硬盘:500GB SSD
模型:Qwen2.5 7B / DeepSeek蒸馏7B
2. 中型企业配置
适合50到300人使用:
CPU:16核以上
内存:64GB以上
GPU:RTX 4090 24GB / A5000 / L40S
硬盘:1TB NVMe SSD
模型:Qwen2.5 14B / 32B量化模型
3. 大型企业配置
适合高并发、多部门、多知识库:
CPU:32核以上
内存:128GB以上
GPU:A100 / H100 / L40S多卡
硬盘:企业级NVMe SSD
推理框架:vLLM
向量库:Milvus / pgvector
数据库:PostgreSQL高可用集群
如果只是文档问答和办公写作,7B到14B模型基本可以满足大多数需求。如果需要复杂推理、代码生成、合同审查等,则建议选择更大模型或接入混合模型路由。
十、生产环境优化建议
上面的源码可以实现最小可用系统,但如果要用于企业生产环境,还需要做进一步优化。
1. 用户认证与权限控制
建议增加以下能力:
- 用户登录;
- JWT Token鉴权;
- 部门权限;
- 知识库权限;
- 管理员角色;
- 操作审计。
例如,销售部门只能访问销售资料,财务部门只能访问财务制度,法务部门可以访问合同模板和法律文档。
2. 文档权限隔离
知识库不仅要能检索,还要能控制“谁可以检索”。可以在向量数据metadata中增加字段:
{
"filename": "财务报销制度.pdf",
"department": "finance",
"permission": "finance_only"
}
查询时根据当前用户角色过滤:
where={
"department": user.department
}
这样可以避免越权访问。
3. 日志与审计
企业内部AI系统必须具备日志能力,包括:
- 用户提问内容;
- 模型返回内容;
- 检索到的知识库片段;
- 用户上传的文件;
- 操作时间;
- IP地址;
- 用户ID。
日志的价值不仅在于安全审计,也可以用于后续分析哪些知识被频繁查询,从而优化知识库建设。
4. Prompt模板管理
不同办公场景可以配置不同Prompt模板,例如:
周报生成模板
你是专业的企业办公助手。
请根据用户提供的工作内容,生成一份结构清晰的周报。
要求包括:
1. 本周完成工作;
2. 重点成果;
3. 存在问题;
4. 下周计划;
5. 需要协同的事项。
合同审查模板
你是企业法务审查助手。
请从以下角度审查合同:
1. 付款条款;
2. 违约责任;
3. 交付周期;
4. 保密条款;
5. 争议解决方式;
6. 对我方不利的风险点。
通过模板化管理,可以让AI输出更加稳定,也方便企业沉淀办公方法论。
5. 流式输出
当前示例中采用非流式返回,用户需要等待模型完整生成。生产环境中建议改成流式输出,提升体验。
FastAPI可以使用 StreamingResponse,Ollama也支持流式接口。这样用户可以像使用ChatGPT一样,看到答案逐字生成。
6. 多模型路由
不同任务可以使用不同模型:
| 场景 | 推荐模型 |
|---|---|
| 日常写作 | 7B模型 |
| 知识库问答 | 7B或14B模型 |
| 代码生成 | Code模型 |
| 合同审查 | 更大参数模型 |
| 快速分类 | 小模型 |
| 向量化 | BGE / M3E |
通过多模型路由,可以平衡效果、成本和响应速度。
7. 文档解析增强
真实企业文档格式复杂,可能包含:
- 表格;
- 图片;
- 扫描件;
- 页眉页脚;
- 水印;
- 多栏排版;
- 附件;
- 复杂编号。
因此可以增加:
- OCR识别;
- 表格解析;
- 版面分析;
- 文档去噪;
- Excel结构化解析;
- 图片内容识别。
对于扫描PDF,可以接入PaddleOCR或其他OCR服务。
十一、安全与合规策略
私有化部署的核心价值之一就是安全,但“部署在内网”并不等于安全。建议从以下几个方面建设。
1. 网络隔离
- AI服务部署在内网;
- 不开放不必要端口;
- Ollama服务不直接暴露公网;
- 前端通过网关访问后端;
- 后端再访问模型服务和数据库。
2. 数据加密
- 数据库存储加密;
- 文档存储加密;
- HTTPS访问;
- 敏感字段脱敏;
- 定期备份。
3. 权限最小化
- 普通用户只能访问自己的会话;
- 部门用户只能访问部门知识库;
- 管理员操作需要审计;
- 禁止匿名上传敏感文档。
4. 内容安全
可以增加敏感词检测和输出过滤,例如:
- 防止泄露客户隐私;
- 防止输出内部机密;
- 防止生成违规内容;
- 对高风险问题进行拦截或转人工审核。
5. 模型幻觉控制
知识库问答场景下,应要求模型“基于资料回答”,并在Prompt中明确:
如果知识库资料中没有相关依据,请回答:知识库中未找到相关依据。
不要编造制度、条款、金额、日期、人员信息。
同时返回引用来源,让用户可以追溯答案依据。
十二、常见问题
1. 为什么文档上传后问不到答案?
可能原因包括:
- 文档解析失败;
- 文档内容为空;
- 切分粒度不合理;
- Embedding模型效果不好;
- 问题表达与文档内容差异太大;
- top_k设置过小;
- 向量库没有持久化成功。
可以先打印检索结果,确认是否能召回相关片段。
2. 模型回答很慢怎么办?
可以从以下方面优化:
- 使用GPU推理;
- 换用更小模型;
- 使用量化模型;
- 改用vLLM;
- 开启流式输出;
- 降低上下文长度;
- 降低top_k数量;
- 增加缓存。
3. 是否必须使用GPU?
不是必须。小模型可以在CPU上运行,但速度较慢。如果企业希望多人同时使用,建议至少配置一张具备较大显存的GPU。
4. 私有化部署是否需要训练模型?
多数办公场景不需要重新训练。推荐优先使用RAG知识库方案,通过文档检索增强模型回答。只有在特定行业术语、特定格式输出、复杂业务流程中,才考虑微调模型。
5. 能不能接入现有OA系统?
可以。后端提供REST API后,OA系统可以直接调用。例如:
- 在OA审批页面增加“AI总结”按钮;
- 在会议系统中增加“生成会议纪要”;
- 在知识库页面增加“问AI”;
- 在邮件系统中增加“邮件润色”。
十三、后续扩展方向
这套AI办公私有化系统可以继续扩展为企业级AI中台。
1. AI Agent办公助手
可以让AI不仅回答问题,还能执行任务,例如:
- 查询日程;
- 创建待办;
- 调用OA审批接口;
- 检索CRM客户信息;
- 生成并发送邮件;
- 自动汇总项目进度。
2. 多知识库管理
支持按部门、项目、业务线建立知识库:
- 公司制度知识库;
- 财务报销知识库;
- 法务合同知识库;
- 产品资料知识库;
- 技术文档知识库;
- 客户服务知识库。
3. 企业微信/钉钉/飞书集成
将AI办公接入IM系统,可以显著提升使用率。例如员工在企业微信群中直接提问:
@AI助手 请总结一下本周项目风险
AI自动查询项目文档并返回结果。
4. 工作流自动化
结合工作流引擎,可以实现:
- 文档上传后自动摘要;
- 合同提交后自动风险审查;
- 会议录音结束后自动生成纪要;
- 客户反馈自动分类;
- 工单自动推荐解决方案。
十四、总结
AI办公私有化部署的本质,不是简单安装一个聊天机器人,而是把大模型、企业知识库、办公流程、权限体系和数据安全结合起来,形成企业内部可控、可用、可持续迭代的智能办公平台。
本文提供了一套完整的最小可运行方案,包括:
- Ollama本地大模型服务;
- FastAPI后端接口;
- Chroma向量数据库;
- 文档上传与解析;
- RAG知识库问答;
- 简易前端页面;
- Docker Compose一键部署源码。
对于中小企业,可以先基于这套方案快速搭建原型,用于知识库问答、文档摘要、办公写作等场景。对于大型企业,则可以在此基础上进一步增加权限控制、日志审计、多模型路由、流式输出、文档解析增强、统一网关和高可用架构。
最终,AI办公私有化系统的价值不只是“能聊天”,而是让企业内部知识真正流动起来,让员工更快找到答案,让管理者更快掌握信息,让组织整体效率持续提升。