在官方例子中给出了通过chain = NebulaGraphQAChain.from_llm(ChatOpenAI(temperature=0), graph=graph, verbose=True)来检索NebulaGraph图数据库。本文介绍了通过GPT2替换ChatOpenAI的思路和实现,暂时不考虑效果。之所以没用ChatGLM2是因为加载模型太慢,调试不方便,不过将GPT2替换为ChatGLM2也很方便。

一.通过ChatOpenAI来检索NebulaGraph

1.NebulaGraph_OpenAI.py代码实现

  如果没有ChatGPT的key和proxy是没法运行的,如下所示:

"""
langchain连接NebulaGraph的例子
"""
from langchain.chat_models import ChatOpenAI
from langchain.chains import NebulaGraphQAChain
from langchain.graphs import NebulaGraph

graph = NebulaGraph(
    space="basketballplayer",
    username="root",
    password="nebula",
    address="172.21.31.166",
    port=9669,
    session_pool_size=30,  # 设置连接池大小
)
print(graph.get_schema)

chain = NebulaGraphQAChain.from_llm(  # 从语言模型创建问答链
    ChatOpenAI(temperature=0), graph=graph, verbose=True
)
chain.run("Who played in The Godfather II?")

2.NebulaGraphQAChain默认prompt

  基本思路是介绍、举例、图Schema和限制,如下所示:

> Entering new NebulaGraphQAChain chain...
Generated nGQL:
Task:Generate NebulaGraph Cypher statement to query a graph database.

Instructions:

First, generate cypher then convert it to NebulaGraph Cypher dialect(rather than standard):
1. it requires explicit label specification only when referring to node properties: v.`Foo`.name
2. note explicit label specification is not needed for edge properties, so it's e.name instead of e.`Bar`.name
3. it uses double equals sign for comparison: `==` rather than `=`
For instance:
diff
< MATCH (p:person)-[e:directed]->(m:movie) WHERE m.name = 'The Godfather II'
< RETURN p.name, e.year, m.name;
---
> MATCH (p:`person`)-[e:directed]->(m:`movie`) WHERE m.`movie`.`name` == 'The Godfather II'
> RETURN p.`person`.`name`, e.year, m.`movie`.`name`;

Use only the provided relationship types and properties in the schema.
Do not use any other relationship types or properties that are not provided.
Schema:
Node properties: [{'tag': 'player', 'properties': [('name','string'), ('age', 'int64')]}, {'tag': 'team', 'properties': [('name','string')]}]
Edge properties: [{'edge': 'follow', 'properties': [('degree', 'int64')]}, {'edge':'serve', 'properties': [('start_year', 'int64'), ('end_year', 'int64')]}]
Relationships: ['(:player)-[:follow]->(:player)', '(:player)-[:serve]->(:team)']

Note: Do not include any explanations or apologies in your responses.
Do not respond to any questions that might ask anything else than for you to construct a Cypher statement.
Do not include any text except the generated Cypher statement.

The question is:
player100'age is what?

Full Context:
{}

二.通过GPT2来检索NebulaGraph

1.NebulaGraph_GPT2.py代码实现

  使用自定义的GPT2()替换ChatOpenAI(temperature=0)即可,如下所示:

"""
langchain连接NebulaGraph的例子
"""
from langchain.chains import NebulaGraphQAChain
from langchain.graphs import NebulaGraph
from examples.GPT2 import GPT2

graph = NebulaGraph(  # 连接NebulaGraph
    space="basketballplayer",
    username="root",
    password="nebula",
    address="172.24.211.214",
    port=9669,
    session_pool_size=30,  # 设置连接池大小
)
print(graph.get_schema)  # 获取图的schema

chain = NebulaGraphQAChain.from_llm(  # 从语言模型创建问答链
    GPT2(), graph=graph, verbose=True
)
chain.run("player100'name is what?")  # 运行问答链
chain.run("player100'age is what?")  # 运行问答链

2.GPT2.py代码实现

  主要是继承LLM类,并且实现def _call(self, prompt: str, stop: Optional[List[str]] = None) -> str:函数,如下所示:

import time
import logging
import requests
from typing import Optional, List, Dict, Mapping, Any

import langchain
from langchain.llms.base import LLM
from langchain.cache import InMemoryCache

logging.basicConfig(level=logging.INFO)
# 启动llm的缓存,如果同一个问题被第二次提问,模型可以快速给出答案,而不用再次调用模型,节省时间
langchain.llm_cache = InMemoryCache()

class GPT2(LLM):
    # 模型服务url
    url = "http://127.0.0.1:8595/chat"

    @property  # 这个装饰器的作用是将一个方法变成一个属性来使用
    def _llm_type(self) -> str:
        return "gpt2"

    def _construct_query(self, prompt: str) -> Dict:
        """
        构造请求体
        """
        query = {
            "human_input": prompt
        }
        return query

    @classmethod  # 这个装饰器的作用是将一个方法变成一个类方法来使用
    def _post(cls, url: str, query: Dict) -> Any:
        """
        POST请求
        """
        _headers = {"Content_Type": "application/json"}
        with requests.session() as sess:  # 这个with语句的作用是在这个语句块中创建的对象,会在执行完语句块后自动销毁
            resp = sess.post(url, json=query, headers=_headers, timeout=60)
        return resp

    def _call(self, prompt: str, stop: Optional[List[str]] = None) -> str:
        """
        注释:这个方法是用来调用模型的,这个方法的参数是prompt和stop,prompt是用户输入的内容,stop是用户输入的结束标志
        """
        query = self._construct_query(prompt=prompt)  # 构造请求体
        resp = self._post(url=self.url, query=query)  # post请求

        if resp.status_code == 200:  # 判断请求是否成功
            resp_json = resp.json()  # 获取返回结果
            predictions = resp_json['response']  # 获取返回结果中的response字段
            return predictions  # 返回模型结果
        else:
            return "请求模型"

    @property  # 这个装饰器的作用是将一个方法变成一个属性来使用
    def _identifying_params(self) -> Mapping[str, Any]:
        """
        这个方法的作用是获取识别参数
        """
        _param_dict = {
            "url": self.url
        }
        return _param_dict

if __name__ == "__main__":
    llm = GPT2()  # 实例化GPT2类
    while True:  # 这个while循环的作用是让用户可以一直输入
        human_input = input("Human: ")  # 获取用户输入
        begin_time = time.time() * 1000  # 获取当前时间

        response = llm(human_input, stop=["you"])  # 调用模型
        end_time = time.time() * 1000  # 获取当前时间
        used_time = round(end_time - begin_time, 3)  # 计算模型调用时间
        logging.info(f"GPT2 process time: {used_time}ms")  # 打印模型调用时间

        print(f"GPT2: {response}")  # 打印模型返回结果

3.GPT2_Flask.py代码实现

  主要是通过Flask将GPT2进行API封装,如下所示:

import os
import json
import torch
from flask import Flask
from flask import request
from transformers import GPT2LMHeadModel, GPT2Tokenizer

os.environ["CUDA_VISIBLE_DEVICES"] = "0"  # 指定GPU,0表示使用第一个GPU

pretrained_model_name_or_path = "L:/20230713_HuggingFaceModel/gpt2"
tokenizer = GPT2Tokenizer.from_pretrained(pretrained_model_name_or_path, trust_remote_code=True)
model = GPT2LMHeadModel.from_pretrained(pretrained_model_name_or_path, trust_remote_code=True).half().cuda()
model.eval()

app = Flask(__name__)

@app.route("/", methods=["POST", "GET"])
def root():
    return "Welcome to gpt2 model"

@app.route("/chat", methods=["POST"])
def chat():
    data_seq = request.get_data()  # 获取请求数据
    data_dict = json.loads(data_seq)  # 将请求数据转换为字典
    human_input = data_dict["human_input"]  # 获取请求数据中的human_input字段

    # response, _ = model.chat(tokenizer, human_input, history=[])  # ChatGLM可使用这个方法

    # 将输入文本编码为令牌
    input_ids = tokenizer.encode(human_input, return_tensors="pt")
    input_ids = input_ids.cuda()
    # 进行模型推理
    with torch.no_grad():  # 这个with语句的作用是在这个语句块中创建的对象,会在执行完语句块后自动销毁
        output = model.generate(input_ids, max_length=50, num_return_sequences=1)  # 生成模型输出,max_length表示生成的最大长度,num_return_sequences表示生成的序列数
    output = output.cuda()
    # 将生成的令牌解码为字符串,skip_special_tokens=True表示跳过特殊字符,clean_up_tokenization_spaces=True表示清理分词空格
    response = tokenizer.decode(output[0], skip_special_tokens=True, clean_up_tokenization_spaces=True)

    result_dict = {  # 构造返回结果
        "response": response
    }
    result_seq = json.dumps(result_dict, ensure_ascii=False)  # 将返回结果转换为json字符串
    return result_seq  # 返回结果

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8595, debug=False)

  因为通用LLM通过prompt将text转换为nGQL并不专业,觉得以后的发展思路应该还是专用LLM作为agent来做这个事情。

参考文献:

[1]https://huggingface.co/gpt2

[2]使用LLMs模块接入自定义大模型:https://blog.csdn.net/zhaomengsen/article/details/130585397

[3]https://github.com/ai408/Langchain-Chatchat/blob/master/examples/NebulaGraph_GPT2.py

[4]https://github.com/ai408/Langchain-Chatchat/blob/master/examples/GPT2.py

[5]https://github.com/ai408/Langchain-Chatchat/blob/master/examples/GPT2_Flask.py

Langchain-Chatchat项目:2.1-通过GPT2模型来检索NebulaGraph的更多相关文章

  1. 团队项目作业:利用NABCD模型进行竞争性需求分析

    NABC正是这样的一套框架,当你试图提出一项崭新的提案之际,它能够提供四个思维基点,令你的商业策划具备天马行空的基础. 具体来说,NABC是四个关键词的首字母缩写- Need(需求)-现在市场上未被满 ...

  2. mnist手写数字识别——深度学习入门项目(tensorflow+keras+Sequential模型)

    前言 今天记录一下深度学习的另外一个入门项目——<mnist数据集手写数字识别>,这是一个入门必备的学习案例,主要使用了tensorflow下的keras网络结构的Sequential模型 ...

  3. 一个关于vue+mysql+express的全栈项目(六)------ 聊天模型的设计

    一.数据模型的设计 这里我们先不讨论群聊的模型,指讨论两个人之间的聊天,我们可以把两个人实时聊天抽象为(点对点)的实时通讯,如下图 我们上面的所说的模型其实也就是数据包的模型应该怎么设计,换句话说就是 ...

  4. 创建基于ASP.NET core 3.1 的RazorPagesMovie项目(二)-应用模型类配合基架生成工具生成Razor页面

    本节中,将学习添加用于管理跨平台的SQLLite数据库中的电影的类Movie.从ASP.NET core 模板创建的应用使用SQLLite数据库. 应用模型类(Movie)配合Entity Frame ...

  5. 项目开发常见字符串处理模型-strstr-while/dowhile模型

    strstr-whiledowhile模型用于在母字符串中查找符合特征的子字符串. c语言库提供了strstr函数,strstr函数用于判断母字符串中是否包含子字符串,包含的话返回子字符串的位置指针, ...

  6. 作业6 团队项目之需求 (NABCD模型)

     N A B C D模型分析 WorkGroup:NewApps 组员:欧其锋(201306114305  http://www.cnblogs.com/ouqifeng/) 吕日荣(20130611 ...

  7. 项目需求与分析--NABCD模型

    合作项目特点NABCD分析结果: 特点:便捷 N(Need 需求):在大学期间内,我们通常会有许多不用的课本或书籍或者其他东西,堆积起来又没有地方放,想卖出去就要建一个群,十分麻烦,开发该软件用户可直 ...

  8. 《BI项目笔记》基于雪花模型的维度设计

    GBGradeCode 外键关系: 1 烟叶等级 T_GBGradeCode.I_DistinctionID=T_Distinction.I_DistinctionID 烟叶等级分为:上等烟.中等烟. ...

  9. 项目需求分析与建议-NABCD模型

    N(Need 需求) 首先我们的创意解决了现有阶段学校查空余教师的问题,充分解决了同学们上自习却找不到教室的苦衷,同时也会适当的拓展一些适当的学习计时功能或者每日一语等等,来帮助同学们来控制好学习时间 ...

  10. 项目需求分析与建议——NABCD模型

    特点一:旧物再利用N:需求:在我们的校园生活中,会遇到许多自己用不到的东西例如,学过的课本.废置的闲置物品等,这些"废物"往往占据着许多空间却不能够发挥自身的价值,通过我们的校园二 ...

随机推荐

  1. Jmeter中使用BeanShell获取接口返回的指定值

    第一步:先引入jar包编写代码的时候,引入了一个jar包,是需要把它添加在测试计划中的  第一种:获取data中的paramName和paramVal值 //获取当前请求响应结果 String res ...

  2. 轻松掌握组件启动之MongoDB(下):高可用复制集架构环境搭建

    引言 上一章节中,我们详细介绍了在典型的三节点复制集环境中搭建MongoDB的步骤和注意事项.从准备配置文件到启动MongoDB进程,我们一步步指导读者完成了环境的设置.在本章节中,我们将进一步深入, ...

  3. JNI编程之java层和native层的数组数据的交互

    一.前言 JNI中的数组类型分为基本类型数组和引用类型数组,他们的处理方式是不一样的.基本类型数组中的元素都是jni基本数据类型,可以直接访问:但是引用类型的数组中的元素是一个类的实例,不能直接访问, ...

  4. Redis7

    Redis是基于内存的K-V键值对内存数据库 浅谈Redis7新特性 主要是自身底层性能和资源利用率上的提高和优化. 多AOF文件支持 config命令增强 限制客户端内存使用 listpack紧凑列 ...

  5. [C++]STL - 队列(Queue) 栈(Stack) 链表(list)

    STL - 队列(Queue) 栈(Stack) 链表(list) Queue 队列 结构特征 这是一种线性储存结构 其数据有先进先出的特点 这种特点被称为FIFO(First In First Ou ...

  6. logback java动态配置【动态修改日志级别,动态修改appender】(转)

    logback 动态配置 写在前面在做java日志之前,强烈建议大家读一下这篇java日志的前世今生,对理清java日志框架很有帮助!1奉上地址: 一个著名的日志系统是怎么设计出来的 然后说一下,为啥 ...

  7. Qt+FFmpeg播放mp4文件视频

    关键词:Qt FFmpeg C++ MP4 视频 源码下载在系列原文地址. 先看效果. 这是一个很简单的mp4文件播放demo,为了简化,没有加入音频数据解析,即只有图像没有声音. 音视频源的播放可以 ...

  8. 题解 CF1742G

    题目描述: 给你一个序列 \(A\),要求将 \(A\) 重新排序,使得序列 \(A\) 的前缀或和序列 \(B\) 的字典序最大. 题目分析: 这道题我们首先考虑一个性质,就是前缀或和序列 \(B\ ...

  9. [NOIP 考前备战] 线段树刷题

    备战线段树 T1 AcWing .1275. 最大数 查询最大值 + 单点修改 #include <bits/stdc++.h> #define int long long using n ...

  10. Vue07-Axios

    Axios axios是一个网络请求相关的库. axios: ajax i/o system 使用axios编写的网络请求代码,可以运行在浏览器端,也可以在Node环境中运行. 01. 支持的请求方式 ...