使用说明
多租户文档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)
后端设置
-
导航到后端目录:
cd backend -
创建虚拟环境:
python -m venv venv source venv/bin/activate # On Windows: venv\Scripts\activate -
安装依赖项:
pip install -r ../requirements.txt -
设置环境变量:
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 -
创建PostgreSQL数据库:
CREATE DATABASE documentai_db; -
运行迁移:
python manage.py migrate -
创建超级用户(可选,用于管理面板):
python manage.py createsuperuser -
运行开发服务器:
python manage.py runserver后端将在
http://localhost:8000GraphQL游乐场可在http://localhost:8000/graphql/
前端设置
-
导航到前端目录:
cd frontend -
安装依赖项:
npm install -
启动开发服务器:
npm start前端将在
http://localhost:3000
身份验证流程
JWT身份验证
该应用程序使用基于JWT的身份验证,流程如下:
- 登录:用户通过提供电子邮件和密码
token_auth突变 - 令牌生成:后端验证凭据并返回JWT令牌
- 令牌存储:前端将令牌存储在localStorage中
- 请求身份验证:Apollo客户端自动将令牌包含在
Authorization: JWT <token>头球 - 令牌验证: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解析器级别,而不是在前端。许可系统基于:
- 组织成员:用户必须是组织的成员才能访问其资源
- 活跃组织:用户选择要在其中工作的活动组织
- 基于角色的权限:具有不同能力的两个角色:
- 管理员:可以创建/管理文档,邀请用户
- 成员:可以阅读文档,问人工智能问题
权限执行点
所有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实现由三层组成:
-
MCP服务器层 (
backend/documents/mcp_server.py):MCPServer:公开文档内容的核心MCP服务器get_document_context(document_id):检索文档和格式作为MCP上下文format_context_for_mcp(context):将上下文字典格式化为MCP协议格式
-
MCP上下文提供程序 (
backend/documents/mcp_server.py):MCPContextProvider:业务逻辑和MCP协议之间的桥梁provide_document_context(document_id):通过MCP提供文档上下文
-
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
关键原则
-
无手动连接:上下文永远不会手动连接到提示中。所有上下文都经过MCP格式化。
-
关注点分离:
- MCP服务器:处理上下文检索和格式化
- LLM服务:处理LLM API通信
- GraphQL解析器:处理身份验证和业务逻辑
-
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;
许可证
创建此项目是为了进行评估。
