# ai_agent **Repository Path**: clockdotnet/ai_agent ## Basic Information - **Project Name**: ai_agent - **Description**: dev分支:增加uniapp移动端;基于 RAG(检索增强生成)的企业级知识库问答平台,支持多格式文档管理、混合检索、LangGraph 多节点 Agent 编排与流式问答。前端 Vue 3 + Vant,后端由 FastAPI(AI/RAG 引擎)和 Django(用户/权限服务)组成,提供完整的知识库权限体系和评估驱动的迭代优化闭环。 - **Primary Language**: Python - **License**: MPL-2.0 - **Default Branch**: dev - **Homepage**: http://120.27.247.229/ - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2026-10-22 - **Last Updated**: 2026-11-03 ## Categories & Tags **Categories**: Uncategorized **Tags**: 项目, 重要 ## README # 企业知识库智能问答系统 基于 RAG(检索增强生成)的企业级知识库问答平台,支持多格式文档管理、混合检索、LangGraph 多节点 Agent 编排与流式问答。前端 Vue 3 + Vant,后端由 FastAPI(AI/RAG 引擎)和 Django(用户/权限服务)组成,提供完整的知识库权限体系和评估驱动的迭代优化闭环。 ## 目录 - [技术亮点](#技术亮点) - [核心能力](#核心能力) - [项目演示](#项目演示) - [系统架构](#系统架构) - [技术栈](#技术栈) - [项目结构](#项目结构) - [配置说明](#配置说明) - [部署与启动](#部署与启动) - [Docker 部署](#docker-部署) - [页面入口](#页面入口) - [API 速览](#api-速览) - [RAG 与知识库机制](#rag-与知识库机制) - [LangGraph Agent 引擎](#langgraph-agent-引擎) - [MCP 协议集成](#mcp-协议集成) - [评估体系](#评估体系) - [测试与构建](#测试与构建) - [常见问题](#常见问题) - [相关文档](#相关文档) ## 技术亮点 | 亮点 | 说明 | |------|------| | 混合检索 + 父子分块 | 向量语义检索 + BM25 关键词检索双路召回;子块精准召回→父块提供完整上下文,recall@1 达 0.881 | | LangGraph 多节点 Agent | Coordinator 任务规划 → Knowledge 检索 → Critic 质量审查 → Finalize 生成,支持自我修正闭环 | | 评估驱动迭代 | 三层指标(检索/回答/编排)+ 消融对比,用数据而非直觉做工程决策 | | Critic 自我修正 | 大幅减少"知识库其实有,但被误判为没有"的情况(精确率 0.50→0.87),代价仅多一次 LLM 调用 | | 知识缺口自动发现 | 检索置信度低于阈值时,LLM 自动抽取未覆盖知识点落库,形成知识库补充闭环 | | 双服务架构 | FastAPI(AI 推理)+ Django(用户权限)独立部署、独立伸缩、故障隔离 | | SSE 流式输出 | Agent 每个节点的执行步骤实时推送到前端,用户可见「思考过程」 | | 多向量后端 | 支持 ChromaDB(嵌入式)和 Milvus(分布式)无缝切换 | | Docker 基础镜像优化 | 依赖预装基础镜像,日常构建仅复制源码,秒级完成 | | MCP 协议双向集成 | 对外暴露知识库检索为 MCP Server(stdio/SSE),对内作为 MCP Client 动态接入外部工具 | ## 核心能力 - AI 问答:支持普通 RAG 查询和 Agent 流式问答,回答可携带来源引用。 - LangGraph Agent 引擎(可选):Coordinator → Knowledge →(证据不足时)Critic → Task / KnowledgeGap → Finalize 的多节点图,每个节点的执行步骤会作为 SSE 事件实时推送到前端。 - 任务执行:识别到「文档对比 / 报告生成 / 申请文本生成」时,调用对应 prompt 工具产出结构化结果,区别于纯问答。 - 知识缺口记录:检索 0 命中或置信极低时,LLM 抽取"未覆盖的知识点"自动落库,管理员可在「我的 → 知识缺口」页查看并改状态。 - 会话管理:FastAPI 侧将会话和消息持久化到 MySQL,前端提供会话列表、切换和删除。 - 知识库管理:支持个人、部门、公司范围的知识库,并提供成员权限模型。 - 文档管理:支持 `txt`、`pdf`、`md`、`docx`、`pptx` 文件上传、去重、记录、删除和检索。 - 混合检索:向量检索 + BM25 关键词检索,兼顾语义召回和精确词匹配。 - 父子分块:小块用于召回,大块用于给 LLM 提供完整上下文。 - 重排序:默认使用 Qwen3-Reranker-0.6B 对召回文档精排,也支持阿里云重排序配置。 - 多向量后端:默认 ChromaDB,本地需要独立向量服务时可切换 Milvus。 - 用户服务:Django 提供注册、登录、JWT、用户资料、管理员账号管理和文件上传接口。 - 移动端适配 UI:底部 Tab 覆盖 AI 问答、会话、知识库、我的四个主入口。 - MCP Server:将知识库检索、文档重排序等核心能力封装为 MCP 工具,供 Claude Desktop、Cursor 等外部 AI 客户端通过标准协议调用。 - MCP Client:Agent 支持动态连接外部 MCP Server,自动发现并注册第三方工具,扩展 Agent 能力边界。 ## 项目演示 > 在线体验地址:http://120.27.247.229/ 以下截图来自项目实际界面,覆盖 AI 问答、会话管理、知识库管理、文档编译和账号权限等主要场景。 ### AI 问答 对话示例 基于个人或共享知识库进行流式问答,回答支持 Markdown 渲染、来源引用、Agent 执行步骤和审批操作。 ### 会话管理 对话管理页面 会话页支持搜索历史会话、继续对话、归档和删除,并在右侧展示会话统计与快捷操作。 ### 知识库管理 知识库管理页面 支持个人文档和共享知识库两个视图,管理员可创建个人、公开、部门、管理员专属等不同范围的知识库。 创建知识库选项 创建知识库时可填写名称、描述并选择访问范围,便于按个人、部门或管理权限隔离知识。 ### 文档上传与编译 个人知识库管理页面 个人知识库支持上传 `PDF`、`TXT`、`MD`、`DOCX`、`PPTX` 等文件,并展示资源概览、检索配置和危险操作。 知识库文档编译页面 知识库详情页可查看文档列表、分块数量、更新时间,并支持继续上传或删除指定文档。 ### 账号管理 账号管理页面 管理员可在账号管理页查看用户列表、创建账号、分配部门,并设置普通用户或管理员权限。 ## 系统架构 ```mermaid flowchart TD subgraph Frontend["Vue 3 + Vite + Vant,端口 3000"] A["AI 问答 /aichat"] B["会话管理 /sessions"] C["知识库 /knowledge"] D["我的 /my"] E["登录注册 /login /register"] end subgraph Gateway["Vite 开发代理"] P1["/api -> FastAPI 8000"] P2["/user、/file -> Django 8001"] end subgraph FastAPI["FastAPI RAG 服务,端口 8000"] F1["Agent / 流式问答"] F2["RAG 查询"] F3["会话与消息"] F4["知识库与文档管理"] F5["知识缺口管理"] F6["限流中间件"] end subgraph Graph["LangGraph Agent(AGENT_ENGINE=graph)"] G1["Coordinator 任务分类"] G2["Knowledge 检索"] G3["Critic 证据审查"] G4["Task:对比 / 报告 / 申请"] G5["KnowledgeGap 缺口记录"] G6["Finalize 输出"] G1 --> G2 G2 -->|证据充足| G4 G2 -->|证据不足| G3 G3 -->|改写重检索| G2 G3 -->|知识库无覆盖| G5 G3 -->|阈值偏严,可作答| G6 G4 --> G6 G5 --> G6 end subgraph RAG["RAG 核心"] R1["SmartTextSplitter"] R2["Parent / Child Chunks"] R3["ChromaDB 或 Milvus"] R4["BM25 + 向量混合检索"] R5["Qwen3 Reranker"] end subgraph UserService["Django 用户服务,端口 8001"] U1["注册 / 登录 / JWT"] U2["用户资料"] U3["管理员账号管理"] U4["文件上传"] end subgraph Storage["存储与依赖"] S1["MySQL:会话、消息、知识库、文档元数据"] S2["Redis:限流、缓存、Token 黑名单"] S3["Ollama 或阿里云百炼"] S4["本地模型目录:Reranker"] end A & B & C & D & E --> Gateway Gateway --> P1 --> FastAPI Gateway --> P2 --> UserService FastAPI --> Graph FastAPI --> RAG FastAPI --> UserService FastAPI --> Storage UserService --> Storage ``` ### 为什么拆分为两个服务 | 服务 | 定位 | 技术选型理由 | |------|------|------| | DjangoUserService | 用户/权限/部门/文件管理 | Django ORM + Admin + Celery 适合标准 CRUD | | backend (FastAPI) | AI 对话/RAG/LangGraph Agent | 原生 async + SSE 流式 + LangChain 生态集成 | 拆分收益: - **依赖隔离**:backend 含 torch/langchain 重依赖(镜像 ~1GB+),Django 轻量(~200MB),互不拖累 - **独立伸缩**:认证高峰扩 Django,AI 推理高峰扩 backend - **故障隔离**:AI 服务崩溃不影响登录;Django 升级时已签发 JWT 仍有效 ```text 前端 ──► DjangoUserService (:8001) ← 注册/登录/JWT 签发 └─► backend FastAPI (:8000) ← AI对话/RAG(验证 JWT,管理操作 proxy 回 Django) ``` ## 技术栈 | 模块 | 技术 | | --- | --- | | 前端 | Vue 3、Vite 7、Vant 4、Vue Router、Pinia、vue-i18n、axios、marked、highlight.js、DOMPurify | | RAG 后端 | FastAPI、LangChain、LangGraph、LangChain Community、LangChain Chroma、LangChain Milvus、SQLAlchemy、Pydantic、Redis | | 用户服务 | Django 5.2、Django REST framework、Simple JWT、drf-yasg、Celery、django-redis | | 向量与检索 | ChromaDB、Milvus、BM25、jieba、sentence-transformers、Qwen3-Reranker-0.6B | | 模型服务 | 阿里云百炼 Qwen、Ollama、本地 reranker 模型 | | 数据存储 | MySQL、Redis、本地 ChromaDB 文件、Milvus Docker Compose | ## 项目结构 ```text . ├── backend/ # FastAPI RAG 服务 │ ├── app/ │ │ ├── agent/ # LangChain Agent、工具和中间件 │ │ │ └── graph/ # LangGraph 图:coordinator/knowledge/task/knowledge_gap/finalize 节点 │ │ ├── tools/ # 任务工具:compare/report/form 三类 prompt 构造器 │ │ ├── cache/ # Redis 缓存装饰器 │ │ ├── config/ # rag/chroma/milvus/agent/prompt 配置 │ │ ├── core/ # 响应、限流、日志、异常处理 │ │ ├── db/ # MySQL / Redis 初始化 │ │ ├── models/ # 会话、消息、知识库、文档、分块、知识缺口表 │ │ ├── mcp/ # MCP Client:连接外部 MCP Server、发现并注册工具 │ │ ├── rag/ # 检索、向量后端、重排序、切片 │ │ ├── router/ # FastAPI 路由 │ │ ├── scheduler/ # 可选的目录监听导入任务 │ │ └── services/ # 会话、知识库、文档、父子块、知识缺口服务 │ ├── mcp_server/ # MCP Server:将核心能力暴露为 MCP 工具 │ ├── tests/ # 后端测试 │ ├── main.py # FastAPI 入口 │ ├── pyproject.toml │ └── .env.example ├── DjangoUserService/ # Django 用户服务 │ ├── apps/user/ # 注册、登录、JWT、用户资料、管理员接口 │ ├── apps/file/ # 文件上传接口 │ ├── DjangoUserService/ # Django settings / urls / celery │ ├── manage.py │ ├── pyproject.toml │ └── .env.example ├── front/ # Vue 3 前端 │ ├── src/views/ # AIChat、Sessions、KnowledgeBase、KnowledgeGaps、My 等页面 │ ├── src/components/ # TabBar 等公共组件 │ ├── src/config/api.js # 前端 API 端点 │ ├── src/router/index.js # 页面路由 │ ├── src/store/ # Pinia store │ └── vite.config.js # Vite 代理配置(端口/代理目标支持环境变量覆盖) ├── docs/ # 设计、计划、走查 runbook、测试语料、Milvus、模型、排障等文档 │ └── test-corpus/ # 企业行政制度测试语料 + 批量上传脚本 + 测试问题清单 ├── docker-compose.milvus.yml # 可选 Milvus 单机栈 └── README.md ``` ## 配置说明 ### FastAPI 后端环境变量 在 `backend/.env` 中配置。下面是常用项,真实密钥不要提交到仓库: ```env # LLM:ALIYUN 或 OLLAMA LLM_TYPE=ALIYUN OLLAMA_BASE_URL=http://localhost:11434 OLLAMA_MODEL_NAME=qwen3.5:0.8b ALIYUN_ACCESS_KEY_SECRET=your_api_key ALIYUN_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1 CHAT_MODEL_NAME=qwen3-max # Embedding:OLLAMA 或 ALIYUN EMBED_MODEL_TYPE=OLLAMA TEXT_EMBEDDING_MODEL_NAME=qwen3-embedding:0.6b ALIYUN_EMBED_MODEL_NAME=qwen3.7-text-embedding # MySQL MYSQL_USER=root MYSQL_PASSWORD=your_password MYSQL_HOST=127.0.0.1 MYSQL_PORT=3306 MYSQL_DATABASE=chat_history # Redis REDIS_HOST=127.0.0.1 REDIS_PORT=6379 REDIS_DB=0 # 向量后端:chroma 或 milvus VECTOR_STORE_BACKEND=chroma MILVUS_HOST=127.0.0.1 MILVUS_PORT=19530 # Django 用户服务 DJANGO_API_URL=http://127.0.0.1:8001 # Reranker RERANKER_TYPE=LOCAL RERANKER_MODEL_PATH=/path/to/models/Qwen3-Reranker-0.6B # Agent 引擎:loop(默认,传统单轮)或 graph(LangGraph 多节点) AGENT_ENGINE=loop # Critic 证据审查(仅 graph 引擎生效) AGENT_CRITIC_ENABLE=true AGENT_CRITIC_MAX_REVISIONS=1 # HyDE 假设文档:默认 false(评估显示开启后平均延迟约涨 3 倍且指标无提升) RAG_HYDE_ENABLE=false # 知识缺口阈值:最高 relevance_score 低于此值视为「知识库无明确依据」 RAG_GAP_THRESHOLD=0.75 # JWT:必须和 DjangoUserService/.env 的 JWT_SECRET_KEY 一致 SECRET_KEY=change_me ALGORITHM=HS256 # 可选:目录监听导入 SCHEDULER_ENABLED=false SCHEDULER_WATCH_DIR=data/watch SCHEDULER_INTERVAL_MINUTES=10 ``` ### Django 用户服务环境变量 在 `DjangoUserService/.env` 中配置: ```env JWT_SECRET_KEY=change_me DB_NAME=user_service DB_USER=root DB_PASSWORD=your_password DB_HOST=127.0.0.1 DB_PORT=3306 CELERY_BROKER_URL=redis://127.0.0.1:6379/0 CELERY_RESULT_BACKEND=redis://127.0.0.1:6379/0 REDIS_CACHE_URL=redis://127.0.0.1:6379/1 ``` 注意: - `SECRET_KEY` 和 `JWT_SECRET_KEY` 必须保持一致,否则 FastAPI 无法校验 Django 签发的 JWT。 - 建议统一使用 `127.0.0.1` 替代 `localhost`,避免 IPv6 回退延迟。 ### 前端环境变量 `front/vite.config.js` 支持以下进程级环境变量覆盖(多项目并存时避开端口冲突很有用): | 变量 | 默认值 | 说明 | | --- | --- | --- | | `FRONT_PORT` | `3000` | 前端本地开发端口 | | `API_TARGET` | `http://127.0.0.1:8000` | `/api` 代理到的 FastAPI 地址 | | `USER_TARGET` | `http://127.0.0.1:8001` | `/user`、`/file` 代理到的 Django 地址 | 启动示例(后端跑在 8010 时): ```bash API_TARGET=http://127.0.0.1:8010 npm run dev ``` ## 部署与启动 以下步骤面向一台全新的部署机器,以 Linux 为例(Windows 只需将路径和虚拟环境命令替换为对应写法)。部署时请把路径、数据库账号、模型和 API Key 替换为自己的环境。 ### 1. 获取代码 ```bash git clone cd ``` Windows 下命令基本一致,只需把虚拟环境路径改为 `.venv\Scripts\python.exe`。 ### 2. 准备基础环境 建议提前安装: | 依赖 | 用途 | | --- | --- | | Python 3.12+ | FastAPI RAG 服务 | | Python 3.10+ | Django 用户服务 | | uv | Python 依赖安装与虚拟环境管理 | | Node.js 20.19+ 或 22.12+ | Vue 3 / Vite 前端 | | MySQL 8.x | 用户、会话、知识库和文档元数据 | | Redis 7.x | 限流、缓存、Token 黑名单 | | Ollama 或阿里云百炼 API Key | Embedding 与聊天模型 | | Docker / Docker Compose | 可选,用于 Redis、MySQL、Milvus | Redis 可以直接用 Docker 启动: ```bash docker run -d --name redis-rag -p 6379:6379 redis:alpine ``` 如果使用 Milvus 作为向量库: ```bash docker compose -f docker-compose.milvus.yml up -d ``` 如果使用 Ollama embedding: ```bash ollama serve ollama pull qwen3-embedding:0.6b ``` ### 3. 安装项目依赖 ```bash cd backend && uv sync cd ../DjangoUserService && uv sync cd ../front && npm install ``` ### 4. 创建数据库 MySQL 中需要创建两个数据库,名称可以按 `.env` 调整: ```sql CREATE DATABASE chat_history CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE DATABASE user_service CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; ``` ### 5. 配置环境变量 复制示例配置,并按部署机器实际信息修改(各变量含义见上方「配置说明」): ```powershell Copy-Item backend\.env.example backend\.env Copy-Item DjangoUserService\.env.example DjangoUserService\.env ``` 重点确认:`SECRET_KEY` 与 `JWT_SECRET_KEY` 一致、数据库/Redis 地址正确、`LLM_TYPE` 和模型 Key 已填写。 ### 6. 初始化数据库 ```bash cd DjangoUserService python manage.py migrate ``` FastAPI 会在启动时自动执行 SQLAlchemy `create_all`,用于创建会话、消息、知识库、文档等表。Django 的用户表需要先执行 `migrate`。 ### 7. 启动服务 需要启动三个应用服务:Django 用户服务、FastAPI RAG 服务、Vue 前端。 Django 用户服务: ```bash cd DjangoUserService uvicorn DjangoUserService.asgi:application --host 0.0.0.0 --port 8001 ``` FastAPI RAG 服务: ```bash cd backend uvicorn main:app --host 0.0.0.0 --port 8000 --reload ``` Vue 前端: ```bash cd front npm run dev ``` 生产环境建议只暴露前端和网关端口,由 Nginx 反向代理到后端服务。 ### 8. 生产部署建议 开发启动可以直接使用 `npm run dev` 和 `--reload`。生产环境建议: 1. 前端执行构建并把 `front/dist` 交给 Nginx 托管: ```bash cd front npm run build ``` 2. Nginx 将 `/api` 代理到 FastAPI,将 `/user` 和 `/file` 代理到 Django。 3. FastAPI 使用 `uvicorn` 或进程管理器常驻运行,Django 使用 `gunicorn`、`uvicorn` 或平台服务管理器常驻运行。 4. 所有密钥、数据库密码、API Key 通过服务器环境变量或 `.env` 管理,不要提交到仓库。 5. MySQL、Redis、Milvus 和模型目录应使用持久化磁盘,避免容器重建后数据丢失。 Nginx 反向代理示例: ```nginx server { listen 80; server_name your-domain.com; root /path/to/project/front/dist; index index.html; location / { try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:8000/api/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } location /user/ { proxy_pass http://127.0.0.1:8001/user/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } location /file/ { proxy_pass http://127.0.0.1:8001/file/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } } ``` ### 9. 验证与访问 ```bash curl http://127.0.0.1:8000/ # 期望 {"message":"Hello World"} curl http://127.0.0.1:8001/docs/ # Django Swagger curl http://127.0.0.1:3000/ # 前端页面 ``` | 服务 | 地址 | | --- | --- | | 前端应用 | `http://127.0.0.1:3000` | | FastAPI 文档 | `http://127.0.0.1:8000/docs` | | Django Swagger | `http://127.0.0.1:8001/docs/` | ## Docker 部署 两个后端服务均已支持 Docker 容器化部署,采用**基础镜像 + 源码覆盖**策略:依赖预装到基础镜像中,日常构建仅复制源码,秒级完成。 ### 前置条件 - 已安装 Docker Desktop(Windows/macOS)或 Docker Engine + Docker Compose(Linux) - 外部 MySQL、Redis 服务可访问(容器内通过 `host.docker.internal` 或实际 IP 访问宿主机服务) ### DjangoUserService(Django 用户服务) Docker 文件:`Dockerfile.base`(基础镜像,含全部依赖)、`Dockerfile`(仅复制源码)、`docker-compose.yml`、`.dockerignore`、`.env.docker` **服务组成:** | 容器 | 说明 | |------|------| | `django-user-service` | Django Web 服务(uvicorn ASGI),端口 8001,启动时自动执行 `migrate` | | `django-celery-worker` | Celery 异步任务 Worker(gevent 池,监听 celery/email 队列) | **启动命令:** ```bash cd DjangoUserService # 首次部署或依赖变更时,构建基础镜像(仅需执行一次) docker build -f Dockerfile.base -t django-base:latest . # 日常构建并启动(秒级,只复制源码) docker compose up -d --build # 查看日志 docker compose logs -f web docker compose logs -f celery-worker # 停止服务 docker compose down ``` **关键配置(`.env.docker`):** | 变量 | 说明 | |------|------| | `JWT_SECRET_KEY` | 必须与 backend 的 `SECRET_KEY` 一致 | | `DB_*` | MySQL 连接参数 | | `CELERY_BROKER_URL` / `CELERY_RESULT_BACKEND` | Redis 连接 URL | | `DJANGO_DEBUG` | 生产环境设为 `false` | | `DJANGO_ALLOWED_HOSTS` | 允许的 Host 头,默认 `*` | **数据持久化:** - `media_data` 卷:挂载到 `/app/media`,保存用户上传的文件 --- ### backend(FastAPI RAG 服务) Docker 文件:`Dockerfile.base`(基础镜像,含全部依赖 + CPU-only torch)、`Dockerfile`(仅复制源码)、`docker-compose.yml`、`.dockerignore`、`.env.docker` **服务组成:** | 容器 | 说明 | |------|------| | `fastapi-backend` | FastAPI RAG 服务(uvicorn),端口 8000,含健康检查 | **启动命令:** ```bash cd backend # 首次部署或依赖变更时,构建基础镜像(仅需执行一次) docker build -f Dockerfile.base -t backend-base:latest . # 日常构建并启动(秒级,只复制源码) docker compose up -d --build # 查看日志 docker compose logs -f backend # 停止服务 docker compose down ``` **关键配置(`.env.docker`):** | 变量 | 说明 | |------|------| | `SECRET_KEY` | 必须与 DjangoUserService 的 `JWT_SECRET_KEY` 一致 | | `MYSQL_*` / `REDIS_*` | 数据库和缓存连接 | | `DJANGO_API_URL` | 容器内访问 Django 服务,默认 `http://host.docker.internal:8001` | | `RERANKER_TYPE` | Docker 中推荐 `ALIYUN`,避免挂载本地模型 | | `VECTOR_STORE_BACKEND` | `chroma`(嵌入式,数据存卷)或 `milvus` | | `LLM_TYPE` / `EMBED_MODEL_TYPE` | 模型服务选择 | **数据持久化:** | 卷 | 挂载路径 | 说明 | |------|------|------| | `chroma_data` | `/app/data/chromadb` | ChromaDB 向量数据,容器重建不丢失 | | `backend_logs` | `/log/backend` | 服务日志 | **构建特点:** - `torch-backend = "cpu"`(pyproject.toml 中配置):自动使用 CPU 版 torch,避免下载 ~2GB CUDA 版本 - `python-magic-bin` 仅在 Windows 安装(`sys_platform == 'win32'`),Linux 容器使用系统 `libmagic` - 基础镜像预装全部依赖,日常构建仅复制源码,秒级完成 --- ### 服务间通信 ```text ┌──────────────────────────────────────────────────────┐ │ Docker Host │ │ │ │ ┌─────────────────────┐ ┌─────────────────────┐ │ │ │ django-user-service │ │ fastapi-backend │ │ │ │ :8001 │◄──│ :8000 │ │ │ │ + celery-worker │ │ DJANGO_API_URL= │ │ │ └─────────────────────┘ │ host.docker. │ │ │ │ internal:8001 │ │ │ └─────────────────────┘ │ │ │ │ └──────────────────────────────────────┼──────────────┘ ▼ 外部 MySQL / Redis / 阿里云 LLM ``` - backend 容器通过 `host.docker.internal` 访问宿主机上运行的 Django 服务 - 如果两个服务都在同一 Docker 网络中,可将 `DJANGO_API_URL` 改为 Django 服务名 - 前端开发时仍通过 Vite 代理访问两个服务,无需额外配置 ### 常用运维命令 ```bash # 查看容器状态 docker compose ps # 重启单个服务 docker compose restart web # DjangoUserService docker compose restart backend # backend # 进入容器调试 docker exec -it django-user-service sh docker exec -it fastapi-backend sh # 强制重建(不使用缓存) docker compose build --no-cache docker compose up -d # 查看资源占用 docker stats django-user-service fastapi-backend django-celery-worker ``` ## 页面入口 | 页面 | 路由 | 说明 | | --- | --- | --- | | AI 问答 | `/aichat`、`/aichat/:sessionId` | 新对话、历史会话追问、流式回答、Markdown 渲染 | | 会话管理 | `/sessions` | 查看、进入和删除历史会话 | | 知识库 | `/knowledge` | 创建知识库、查看文档、上传文档、触发知识库问答 | | 知识缺口 | `/knowledge-gaps` | 查看 LangGraph KnowledgeGap 节点产生的待补充条目(普通用户看自己的,管理员看全部,可改状态) | | 我的 | `/my` | 用户信息、设置、账号管理入口、知识缺口入口 | | 登录 / 注册 | `/login`、`/register` | 用户认证 | | 个人资料 | `/profile` | 用户资料维护 | | 设置 | `/settings` | 偏好设置 | | 账号管理 | `/admin/accounts` | 管理员用户管理 | ## API 速览 ### FastAPI RAG 服务 | 方法 | 路径 | 说明 | | --- | --- | --- | | `POST` | `/api/agent/query/stream` | Agent 流式问答 | | `POST` | `/api/rag/query` | 普通 RAG 查询 | | `GET` | `/api/session/{session_id}` | 获取单个会话历史 | | `DELETE` | `/api/session/{session_id}` | 删除会话 | | `POST` | `/api/session/{session_id}/messages/{message_id}/feedback` | 回答审批(批准/拒绝,拒绝可联动重新生成) | | `GET` | `/api/sessions` | 获取当前用户会话 | | `POST` | `/api/vector/add/single` | 上传单个文档到个人知识 | | `POST` | `/api/vector/add/multiple` | 批量上传文档 | | `GET` | `/api/vector/list` | 查看个人文档 | | `DELETE` | `/api/vector/document/{doc_id}` | 删除文档 | | `DELETE` | `/api/vector/clean` | 清空个人文档 | | `POST` | `/api/kb` | 创建知识库 | | `GET` | `/api/kb/list` | 查看可访问知识库 | | `PATCH` | `/api/kb/{kb_id}` | 更新知识库 | | `DELETE` | `/api/kb/{kb_id}` | 删除知识库 | | `POST` | `/api/kb/{kb_id}/documents` | 上传文档到知识库 | | `GET` | `/api/kb/{kb_id}/documents` | 查看知识库文档 | | `POST` | `/api/kb/{kb_id}/query` | 在指定知识库内问答 | | `GET` | `/api/knowledge-gaps` | 列出知识缺口(管理员看全部,普通用户看自己的,可按 `status` 筛选) | | `PATCH` | `/api/knowledge-gaps/{gap_id}` | 修改知识缺口状态:`pending` / `reviewed` / `resolved` / `ignored` | ### Django 用户服务 | 方法 | 路径 | 说明 | | --- | --- | --- | | `POST` | `/user/register/` | 注册 | | `POST` | `/user/login/` | 登录并签发 JWT | | `POST` | `/user/logout/` | 登出并加入 Token 黑名单 | | `POST` | `/user/refresh-token/` | 刷新 Token | | `GET` | `/user/detail/` | 获取当前用户信息 | | `PUT/PATCH` | `/user/update/` | 更新用户资料 | | `GET` | `/user/list/` | 管理员获取用户列表 | | `PATCH` | `/user/{uuid}/set-admin/` | 设置管理员权限 | | `POST` | `/file/upload/` | 文件上传 | ## RAG 与知识库机制 ### 向量后端 通过 `VECTOR_STORE_BACKEND` 选择后端: - `chroma`:默认嵌入式模式,数据保存在 `backend/data/chromadb`。 - `milvus`:独立向量服务,依赖 `docker-compose.milvus.yml` 中的 etcd、MinIO、Milvus。 ### 文档处理 1. 上传文件后写入文档记录表,记录 `doc_id`、`user_id`、`kb_id`、文件名、MD5、大小和分块数。 2. 文本按语言智能分块,生成父块和子块。 3. 子块写入向量库,同时保存到 MySQL,供 BM25 构建索引。 4. 同名或相同 MD5 的文档按用户和知识库范围隔离,避免跨用户误判。 ### 检索流程 1. 根据用户和知识库权限过滤可访问内容。 2. 向量检索召回语义相似子块。 3. BM25 召回关键词相关子块。 4. 合并召回结果并映射到父块上下文。 5. 使用 reranker 精排。 6. 将上下文交给 LLM 生成回答,并返回引用来源。 ### 知识库权限 知识库支持 `personal`、`dept`、`company` 范围。成员权限分为: - `viewer`:可检索。 - `editor`:可上传和删除文档。 - `admin`:可管理成员和删除知识库。 ## LangGraph Agent 引擎 将后端环境变量切到 `AGENT_ENGINE=graph` 后,`/api/agent/query/stream` 不再走传统 loop,而是走 `backend/app/agent/graph/` 下的多节点图: ```text START → coordinator → (knowledge | finalize) knowledge → 证据充足 → (task | knowledge_gap | finalize) → 证据不足 → critic critic → (knowledge 改写重检索 | knowledge_gap | task | finalize) knowledge_gap → finalize task → finalize → END ``` critic 只在 knowledge 判定证据不足(最高相关度低于 `RAG_GAP_THRESHOLD`)时介入,不是每次检索都跑。`AGENT_CRITIC_ENABLE=false` 可摘掉 critic 节点、退化回单向流水线(紧急回退用);改写重检索的次数上限由 `AGENT_CRITIC_MAX_REVISIONS` 控制(默认 1,硬上限 5,避免逼近 LangGraph 的 recursion_limit)。 各节点职责: | 节点 | 作用 | | --- | --- | | `coordinator` | LLM 把用户问题归类到 `knowledge_qa` / `document_compare` / `report_generation` / `document_generation` / `knowledge_gap` 之一,并初始化执行计划 | | `knowledge` | 命中知识库的混合检索 + reranker,把候选文档塞进 state | | `critic` | 证据不足时介入,LLM 判定三类结果:`relevant`(阈值偏严,证据够用,直接作答)/ `needs_rewrite`(问题表述或指代导致召回不准,改写查询回 knowledge 重检索)/ `out_of_scope`(知识库确实无覆盖,转 knowledge_gap);自身异常时降级放行,不阻塞主路径 | | `task` | 当任务类型属于「对比 / 报告 / 申请」时,调用 `app/tools/` 下对应的 prompt 构造器(`compare_tool` / `report_tool` / `form_tool`)让 LLM 产出结构化结果 | | `knowledge_gap` | 检索结果空或最高 `relevance_score` 低于阈值时,LLM 抽出未覆盖的知识点,去重过滤后写入 `knowledge_gaps` 表,并把"已记录待补充条目"写回 task_messages | | `finalize` | 汇总 task_messages / knowledge 上下文 / 引用,生成最终回答;同时发送 token 用量事件 | 每个节点执行时都会通过 GraphRunner 把"识别任务类型 / 检索知识 / 审查证据 / 生成对比 / 记录知识缺口 / 生成回答"这类步骤事件 push 到前端,前端聊天页的「步骤」区会逐条显示。 知识缺口落库后会出现在 `/knowledge-gaps` 页:管理员看全部、普通用户只看自己产生的,状态可改 `pending` → `reviewed` / `resolved` / `ignored`。 > 实测语料、走查命令和典型问题清单见 [docs/test-corpus/README.md](./docs/test-corpus/README.md) 与 [docs/walkthroughs/p5b-knowledge-gap-walkthrough.md](./docs/walkthroughs/p5b-knowledge-gap-walkthrough.md)。 ### Agent 流式调用日志示例 以下是一次完整的 Agent 流式问答日志(查询"桂林旅游攻略 景点推荐 玩法"),展示了从用户提问到最终回答的端到端执行链路: gent流式调用日志 **各阶段说明:** | 阶段 | 日志标识 | 说明 | |------|---------|------| | Agent 启动 | `[Agent] 启动,消息数:6` | 加载 system prompt + 历史消息 + 当前 query | | LLM 第一轮决策 | `stage=model_turn round=1 tool_calls=1` | 模型判断需要调用 RAG 工具检索知识库 | | 权限过滤 | `stage=build_filter` | 按用户身份构建向量库/BM25 过滤条件(部门隔离) | | HyDE 跳过 | `RAG_HYDE_ENABLE=false` | 假设文档生成默认关闭,直接用原 query 检索 | | 检索器初始化 | `stage=retriever_init duration=0.000s` | BM25 缓存命中,无需重建索引 | | 子块检索 | `stage=child_retrieve child_count=6` | 向量 + BM25 混合检索,召回 6 个子块 | | 父块扩展 | `stage=parent_fetch requested=3 found=3` | 6 个子块去重映射到 3 个父块(完整上下文) | | Reranker 精排 | `stage=agent_context_rerank` | 阿里云 reranker 对 3 个文档精排打分 | | 缺口判定 | `max_score=0.7941 > 0.75` | 最高分超过阈值,知识库信息充足 | | LLM 第二轮生成 | `stage=model_turn round=2 content_chars=558` | 基于检索片段生成最终回答 | | 流式完成 | `[Agent流式] 完成` | 汇总:2 轮 LLM、1 次工具调用、3 个引用、5134 tokens | **性能指标解读:** - `first_chunk=1.291s`:LLM 首 token 延迟(思考时间) - `duration=1.928s`:RAG 工具总耗时(检索 + 重排) - `tokens=5134`:本次请求总 token 消耗(含输入 + 输出) - `citations=3`:返回给前端的结构化来源引用数 ### Agent 多节点调用日志示例 以下是 `AGENT_ENGINE=graph` 模式下,LangGraph 多节点图的完整执行流程(查询触发 coordinator → knowledge → critic → finalize 链路): LangGraph执行流程 **各节点执行说明:** | 节点 | 日志标识 | 说明 | |------|---------|------| | 协调器 | `[Coordinator]` | LLM 结构化输出判定任务类型(如 `knowledge_qa`),生成执行计划 | | 知识检索 | `[Knowledge]` | 混合检索(向量 + BM25)+ 父块扩展 + reranker 精排 | | 质量审查 | `[Critic]` | 评估检索结果是否充分、回答是否忠实,不充分则改写 query 重检索 | | 知识缺口 | `[KnowledgeGap]` | `max_score < 0.75` 时触发,提取未覆盖知识点写入数据库 | | 最终生成 | `[Finalize]` | 汇总上下文 + 引用,流式生成最终回答并统计 token 用量 | 与上方单循环(`AGENT_ENGINE=loop`)的区别:graph 模式由 coordinator 显式规划、critic 闭环审查,适合需要多步推理和质量保障的复杂查询;loop 模式则更轻量,适合简单问答。 ## MCP 协议集成 项目实现了 MCP(Model Context Protocol)的双向集成:既作为 **Server** 对外暴露核心能力,也作为 **Client** 动态接入外部工具。 ### MCP Server(对外暴露能力) 将知识库检索等核心 RAG 能力封装为标准 MCP 工具,供 Claude Desktop、Cursor、其他 Agent 等外部 AI 客户端调用。 **暴露的工具:** | 工具名 | 功能 | |--------|------| | `knowledge_base_search` | 知识库语义检索(向量 + BM25 + CrossEncoder 重排序),返回 Top-K 相关文档 | | `document_rerank` | 对候选文档按查询相关性精排 | | `list_knowledge_bases` | 列出系统中所有知识库及基本信息 | | `get_current_time` | 获取当前服务器时间 | **启动方式:** ```bash cd backend # stdio 模式(本地 MCP Client 以子进程方式调用) python -m mcp_server # SSE 模式(远程 HTTP 访问) python -m mcp_server --transport sse --port 9000 ``` **外部客户端配置示例(Claude Desktop / Cursor):** ```json { "mcpServers": { "enterprise-kb": { "command": "python", "args": ["-m", "mcp_server"], "cwd": "/path/to/backend" } } } ``` SSE 模式下,外部 Agent 通过 `http://:9000/sse` 端点连接并调用工具。 ### MCP Client(接入外部工具) Agent 支持在启动时连接配置的外部 MCP Server,自动发现工具并注册到可用工具列表中,LLM 可通过 function calling 直接调用。 **配置方式(`backend/.env`):** ```env # 方式一:内联 JSON MCP_SERVERS_JSON={"servers":[{"name":"filesystem","transport":"stdio","command":"npx","args":["-y","@modelcontextprotocol/server-filesystem","/tmp"]}]} # 方式二:配置文件路径 MCP_CONFIG_FILE=./mcp_servers.json ``` **配置文件格式:** ```json { "servers": [ { "name": "filesystem", "transport": "stdio", "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"] }, { "name": "remote-tools", "transport": "sse", "url": "http://localhost:9000/sse" } ] } ``` 未配置时模块静默跳过,不影响现有功能。外部工具名自动添加 `mcp_{server}_{tool}` 前缀,避免与内置工具冲突。 ## 评估体系 项目不止于把功能搭起来,还配了一套**配置驱动、可重复、支持消融对比**的评估管线(代码在 [`backend/eval/`](./backend/eval/)),用数据量化每个机制的真实收益——也就是「评估驱动迭代」而不是「凭感觉调参」。 **三层指标**,每层有独立的 ground truth: | 层 | 指标 | 标尺 | | --- | --- | --- | | 检索 | recall@1 / recall@3 / MRR | 标注的 `expected_doc` | | 回答 | 事实断言通过率 / grounding 忠实度 / rubric 覆盖率 | `answer_assertions`、引用文档 | | 编排 | 路由准确率 / 缺口精确率·召回率 | `expected_route`、`expect_gap_triggered` | **消融对比**(约 100 题人工标注集,子进程隔离注入开关,样本偏小、定位为指示性): | 配置 | 缺口精确率 | rubric 覆盖率 | 忠实度 | 平均延迟 | | --- | --- | --- | --- | --- | | baseline | 0.50 | 0.55 | 0.52 | 6.6s | | **+critic** | **0.87** | **0.69** | **0.65** | 7.5s | | +hyde | 0.52 | 0.59 | 0.51 | 18.9s | > 检索层 recall@1=0.881、MRR=0.933、事实断言通过率 0.99。 **几个用数据做的工程决策**: - **critic 自我修正闭环有效**:把知识缺口判定精确率从 0.50 提到 0.87、rubric 覆盖率 0.55→0.69、忠实度 0.52→0.65; - **HyDE 默认关,是算出来的**:开启后平均延迟从 6.6s 涨到 18.9s(约 3 倍),但检索和回答指标反而没涨,故代码默认关、保留 `RAG_HYDE_ENABLE` 作为可配开关; - **LLM-judge 可信度**:judge 用千问(与被测的 DeepSeek 跨家族)规避自评偏袒,配合 temperature=0、逐点 rubric 核对、人工校准一致性。 一条命令(`python -m eval.runner`)跑完整个配置矩阵,产出三层指标对比表 + 成本表。 ## 测试与构建 ```bash # 前端生产构建 cd front && npm run build # 后端测试 cd backend && python -m pytest # Django 检查 cd DjangoUserService && python manage.py check ``` ## 常见问题 ### 前端改了但浏览器没变化 优先检查 Vite 开发服务器的工作目录是否指向当前项目的 `front/`。路径错了就停掉旧进程,从正确目录重新启动。 ### FastAPI 调 Django 超时 本机代理可能拦截了 `127.0.0.1` 请求。启动服务时清空代理环境变量: ```bash # Linux / macOS unset HTTP_PROXY HTTPS_PROXY http_proxy https_proxy # Windows PowerShell $env:HTTP_PROXY=''; $env:HTTPS_PROXY=''; $env:http_proxy=''; $env:https_proxy='' ``` ### 知识库接口返回 401 需要先登录并让前端携带 `Authorization: Bearer `。FastAPI 会调用 Django `/user/detail/` 校验用户身份。 ### Redis 连接失败 确认 Redis 服务已启动且端口可达: ```bash redis-cli ping # 期望返回 PONG ``` ### Reranker 首次启动慢 首次启动会检查或下载 Qwen3-Reranker-0.6B。确认 `RERANKER_MODEL_PATH` 指向可写且空间充足的目录。 ## 相关文档 - [FastAPI API 文档](./backend/api.md) - [Django 用户服务 API](./DjangoUserService/api.md) - [前端 API 说明](./front/api.md) - [测试语料与一键灌库脚本](./docs/test-corpus/README.md) - [知识缺口走查 runbook](./docs/walkthroughs/p5b-knowledge-gap-walkthrough.md) - [设计文档](./docs/design/) - [实现计划](./docs/plans/) - [ModelScope 模型说明](./docs/modelscope_model.md) - [Milvus 迁移说明](./docs/migrate-to-milvus.md) - [故障排除](./docs/troubleshooting.md)