多租户文档AI助手

一个基于Django + React + GraphQL的多租户文档AI问答应用,支持角色权限管理和MCP协议文档上下文处理。

  • by Huzaifa9559
  • Python
  • 本地部署
  • 2 星标
  • 更新于
在 GitHub 查看 Huzaifa9559/Custom-MCP-Server

使用说明

多租户文档AI助手

Django+React+GraphQL应用程序,使用MCP(模型上下文协议)进行上下文提供,提供具有多租户组织支持的AI驱动的文档问答。

技术栈

后端

  • Django 5.0.3 -Web框架
  • 石墨烯Django 3.2.0 -GraphQL集成
  • PostgreSQL -数据库
  • django图形库jwt 0.4.0 -JWT身份验证
  • MCP(模型上下文协议) -文档上下文暴露
  • OpenAI/人类学/双子座 -LLM集成

前端

  • 反应18.2.0 -UI框架
  • 阿波罗客户端3.9.5 -GraphQL客户端
  • React路由器DOM 6.22.3 -路由

特性

  • 多租户架构:用户可以属于多个组织
  • 基于角色的访问控制:具有不同权限的管理员和成员角色
  • JWT身份验证:基于令牌的安全身份验证
  • 文档管理:创建、查看和管理文档(仅限ADMIN)
  • AI问答:使用LLM询问有关文档的问题
  • MCP集成:通过模型上下文协议提供的文档上下文
  • GraphQL API:所有操作均通过GraphQL进行(无REST API)

项目设置

先决条件

  • Python 3.8+
  • Node.js 14+
  • PostgreSQL 12+
  • LLM API密钥(OpenAI、Anthropic或Gemini)

后端设置

  1. 导航到后端目录:

    cd backend
    
  2. 创建虚拟环境:

    python -m venv venv
    source venv/bin/activate  # On Windows: venv\Scripts\activate
    
  3. 安装依赖项:

    pip install -r ../requirements.txt
    
  4. 设置环境变量:

    cp ../env.example ../.env
    

    编辑 .env 使用您的配置文件:

    SECRET_KEY=your-django-secret-key-here
    DEBUG=True
    DB_NAME=documentai_db
    DB_USER=postgres
    DB_PASSWORD=postgres
    DB_HOST=localhost
    DB_PORT=5432
    JWT_SECRET_KEY=your-jwt-secret-key-here
    JWT_ALGORITHM=HS256
    LLM_API_KEY=your-llm-api-key-here
    LLM_PROVIDER=openai  # or anthropic, gemini
    LLM_MODEL=gpt-4-turbo-preview  # or claude-3-5-sonnet-20241022, gemini-pro
    ALLOWED_ORIGINS=http://localhost:3000,http://localhost:3001
    
  5. 创建PostgreSQL数据库:

    CREATE DATABASE documentai_db;
    
  6. 运行迁移:

    python manage.py migrate
    
  7. 创建超级用户(可选,用于管理面板):

    python manage.py createsuperuser
    
  8. 运行开发服务器:

    python manage.py runserver
    

    后端将在 http://localhost:8000 GraphQL游乐场可在 http://localhost:8000/graphql/

前端设置

  1. 导航到前端目录:

    cd frontend
    
  2. 安装依赖项:

    npm install
    
  3. 启动开发服务器:

    npm start
    

    前端将在 http://localhost:3000

身份验证流程

JWT身份验证

该应用程序使用基于JWT的身份验证,流程如下:

  1. 登录:用户通过提供电子邮件和密码 token_auth 突变
  2. 令牌生成:后端验证凭据并返回JWT令牌
  3. 令牌存储:前端将令牌存储在localStorage中
  4. 请求身份验证:Apollo客户端自动将令牌包含在 Authorization: JWT <token> 头球
  5. 令牌验证:GraphQL中间件(JSONWebTokenMiddleware)提取并验证令牌,设置 info.context.user

GraphQL身份验证突变

mutation {
  token_auth(email: "user@example.com", password: "password123") {
    token
    user {
      id
      email
    }
  }
}

身份验证中间件

JWT身份验证由以下人员处理:

  • 后端: graphql_jwt.middleware.JSONWebTokenMiddleware -从授权标头中提取JWT
  • 后端: graphql_jwt.backends.JSONWebTokenBackend -验证JWT并设置 request.user
  • 前端:阿波罗客户 authLink -将JWT令牌添加到所有请求中

权限处理策略

基于组织的访问控制

所有权限均已强制执行 在GraphQL解析器级别,而不是在前端。许可系统基于:

  1. 组织成员:用户必须是组织的成员才能访问其资源
  2. 活跃组织:用户选择要在其中工作的活动组织
  3. 基于角色的权限:具有不同能力的两个角色:
    • 管理员:可以创建/管理文档,邀请用户
    • 成员:可以阅读文档,问人工智能问题

权限执行点

所有GraphQL解析器在返回数据之前都会检查权限:

文档查询

  • documents:需要活跃的组织成员资格
  • document(id):需要文档所在组织的成员资格
  • aiConversations(documentId):需要文档所在组织的成员资格

文档突变

  • create_document:需要在活动组织中担任ADMIN角色
  • ask_document_ai_question:需要文档组织中的成员或管理员角色

组织突变

  • invite_user_to_organization:需要目标组织中的ADMIN角色
  • set_active_organization:要求加入目标组织

权限实用程序功能

位于 backend/organizations/permissions.py:

  • require_active_organization(user):确保用户已选择活动组织
  • require_organization_member(user, org_id):确保用户是会员
  • require_organization_admin(user, org_id):确保用户是管理员
  • get_user_role_in_organization(user, org_id):返回用户的角色

所有权限功能提升 PermissionError 被捕获并转化为 GraphQLError 在解析器中,确保正确的错误响应。

MCP实施方法

模型上下文协议(MCP)概述

MCP用于以标准化的、基于协议的方式向LLM提供文档上下文。该实现确保了上下文准备和LLM执行之间的清晰分离。

MCP架构

MCP实现由三层组成:

  1. MCP服务器层 (backend/documents/mcp_server.py):

    • MCPServer:公开文档内容的核心MCP服务器
    • get_document_context(document_id):检索文档和格式作为MCP上下文
    • format_context_for_mcp(context):将上下文字典格式化为MCP协议格式
  2. MCP上下文提供程序 (backend/documents/mcp_server.py):

    • MCPContextProvider:业务逻辑和MCP协议之间的桥梁
    • provide_document_context(document_id):通过MCP提供文档上下文
  3. LLM服务集成 (backend/documents/llm_service.py):

    • LLMService:与LLM提供商集成
    • 用途 MCPContextProvider 获取上下文(不是手动字符串连接)

LLM上下文是如何传递的

上下文流遵循以下模式:

User Question → GraphQL Resolver → LLMService.ask_question()
  → MCPContextProvider.provide_document_context()
    → MCPServer.get_document_context()
      → Document Model (database)
    → MCPServer.format_context_for_mcp()
  → LLM Provider (OpenAI/Anthropic/Gemini) with MCP-formatted context

关键原则

  1. 无手动连接:上下文永远不会手动连接到提示中。所有上下文都经过MCP格式化。

  2. 关注点分离:

    • MCP服务器:处理上下文检索和格式化
    • LLM服务:处理LLM API通信
    • GraphQL解析器:处理身份验证和业务逻辑
  3. MCP协议合规性:上下文根据MCP协议标准进行格式化,具有适当的结构:

    Document Context (MCP):
    Title: <title>
    Content:
    <content>
    
    Metadata:
    - Document ID: <id>
    - Organization ID: <org_id>
    - Created: <timestamp>
    

MCP上下文示例

当用户询问有关文档ID 1的问题时:

# MCPContextProvider retrieves context via MCP
context = mcp_provider.provide_document_context(document_id=1)

# Context is formatted as:
"""
Document Context (MCP):
Title: Example Document
Content:
This is the document content...

Metadata:
- Document ID: 1
- Organization ID: 1
- Created: 2024-01-01T00:00:00
"""

# This formatted context is then passed to LLM
# (not manually concatenated)

MCP代码位置

  • MCP服务器: backend/documents/mcp_server.py
  • LLM服务(使用MCP): backend/documents/llm_service.py
  • GraphQL解析器(调用LLM服务): backend/documents/schema.py (AskDocumentAIQuestion突变)

GraphQL API

查询

获取组织

query {
  organizations {
    id
    name
    created_at
  }
}

获取文档

query {
  documents {
    id
    title
    content
    created_at
  }
}

按ID获取文档

query {
  document(id: 1) {
    id
    title
    content
    created_at
  }
}

获取AI对话

query {
  ai_conversations(documentId: 1) {
    id
    question
    answer
    created_at
  }
}

突变

创建文档(仅限ADMIN)

mutation {
  create_document(title: "My Document", content: "Document content...") {
    document {
      id
      title
      content
    }
  }
}

询问文档AI问题(管理员和成员)

mutation {
  ask_document_ai_question(documentId: 1, question: "What is this document about?") {
    conversation {
      id
      question
      answer
      created_at
    }
  }
}

邀请用户加入组织(仅限ADMIN)

mutation {
  invite_user_to_organization(
    organizationId: 1
    userEmail: "user@example.com"
    role: "MEMBER"
  ) {
    success
    membership {
      id
      role
    }
  }
}

设置活动组织

mutation {
  set_active_organization(organizationId: 1) {
    success
    organization {
      id
      name
    }
  }
}

安全考虑

环境变量

  • 永不承诺 .env 文件 -它在里面 .gitignore
  • 从环境变量加载的所有机密
  • 使用 env.example 作为模板

API密钥管理

  • 存储在环境变量中的LLM API密钥
  • 候选人必须使用自己的API密钥
  • 代码库中没有硬编码的秘密

许可执行

  • 在解析器级别强制执行的所有权限
  • 前端权限仅用于用户体验,不用于安全
  • 未经授权的访问会返回GraphQL错误(不是无声故障)

数据库模型

用户

  • 扩展Django的抽象用户
  • 电子邮件作为用户名
  • active_organization_id:当前选定的组织

组织

  • 多租户集装箱
  • 拥有众多文件和会员资格

组织成员

  • 将用户链接到组织
  • 角色:管理员、成员
  • 对(用户、组织)的唯一约束

文件

  • 属于某个组织
  • 有标题和内容
  • 曲目创建者

A转换

  • 将问题/答案链接到文档
  • 存储问题、答案和时间戳
  • 按创建日期排序(最新优先)

测试应用程序

1.创建用户和组织

使用Django admin或GraphQL突变:

# First, create a user via Django admin or script
# Then login
mutation {
  token_auth(email: "admin@example.com", password: "password") {
    token
  }
}

# Set active organization (after being invited)
mutation {
  set_active_organization(organizationId: 1) {
    success
  }
}

2.创建文档(作为ADMIN)

mutation {
  create_document(
    title: "Project Documentation"
    content: "This document contains important information about the project..."
  ) {
    document {
      id
      title
    }
  }
}

3.问人工智能问题

mutation {
  ask_document_ai_question(
    documentId: 1
    question: "Summarize the key points"
  ) {
    conversation {
      question
      answer
    }
  }
}

项目结构

assignment/
├── backend/
│   ├── config/           # Django settings and main schema
│   ├── users/            # User model and auth schema
│   ├── organizations/    # Organization models, permissions, schema
│   ├── documents/        # Document models, MCP server, LLM service, schema
│   └── manage.py
├── frontend/
│   ├── src/
│   │   ├── components/   # React components
│   │   ├── apollo-client.js
│   │   └── App.js
│   └── package.json
├── requirements.txt
├── env.example
├── .gitignore
└── README.md

故障排除

JWT身份验证不起作用

  • 验证令牌是否正在发送 Authorization: JWT <token> 格式
  • 检查 JWT_SECRET_KEY 在 .env 匹配用于对令牌进行签名的密钥
  • 确保 JSONWebTokenMiddleware 在...里 GRAPHENE.MIDDLEWARE

LLM API错误

  • 验证 LLM_API_KEY 已设置 .env
  • 检查API密钥是否对所选提供程序有效
  • 确保有足够的API信用/配额

权限错误

  • 确保用户已选择活动组织
  • 验证用户是否是组织的成员
  • 检查用户的角色是否与所需权限级别匹配

数据库连接问题

  • 验证PostgreSQL是否正在运行
  • 检查中的数据库凭据 .env
  • 确保数据库存在: CREATE DATABASE documentai_db;

许可证

创建此项目是为了进行评估。