在官方例子中给出了通过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. Java算法之动态规划

    ①动态规划 动态规划(Dynamic Programming,DP)是运筹学的一个分支,是求解决策过程最优化的过程.20世纪50年代初,美国数学家贝尔曼(R.Bellman)等人在研究多阶段决策过程的 ...

  2. umich cv-5-2 神经网络训练2

    这节课中介绍了训练神经网络的第二部分,包括学习率曲线,超参数优化,模型集成,迁移学习 训练神经网络2 学习率曲线 超参数优化 模型集成 迁移学习 学习率曲线 在训练神经网络时,一个常见的思路就是刚开始 ...

  3. P1182 数列分段 Section II 题解

    Problem 考察知识点:二分.贪心. 题目描述 对于给定的一个数组,现要将其分成 \(M\) 段,并要求每段连续,且每段和的最大值最小. 思路 二分答案出每段和最大值的最小值,然后贪心检验是否满足 ...

  4. 我们在开发第一个flutter小程序时需要注意什么

    Flutter这些年发展的很快,特别是在 Google 持续的加持下,Flutter SDK 的版本号已经来到了 3开头,也正式开始对 Windows.macOS 和 Linux 桌面环境提供支持.如 ...

  5. linux其他命令(查找,软链接,打包和压缩,软件安装)笔记

    1,查找文件 *  是通配符,代表任意字符,0到多个. find 路径  -name  "*.txt"  : 查找在路径下所有以 .txt 结尾的文件. 2,软链接 (1)将桌面目 ...

  6. 带您了解 O2OA 流程中的人工活动处理方式

    这次咱们来介绍 O2OA (翱途) 开发平台流程引擎中的人工活动的处理方式和逻辑,O2OA (翱途) 主要采用拖拽可视化开发的方式完成流程的设计和配置,不需要过多的代码编写,业务人员可以直接进行修改操 ...

  7. logmein

    打开以后发现就是简单的字符串操作 关键比较 其中v7出按r转成字符 然后写出脚本进行操作 但是最后输出的结果不太对的样子 看了wp才知道以LL结尾的那个地方转为字符串以后要逆序操作,即字符串在内存中是 ...

  8. 牛客多校第二场 I.Penguins

    题意 两个企鹅,一个从地图的右下角走右上角,一个从另一个地图的左下角走到左上角,我们操控左边的企鹅,右边的企鹅与左边企鹅运动规则如下. 左边企鹅向左,右边企鹅向右 左边企鹅向右,右边企鹅向左 左边企鹅 ...

  9. 按既定顺序创建目标数组 (leetcode181周赛T1)

    给你两个整数数组 nums 和 index.你需要按照以下规则创建目标数组: 目标数组 target 最初为空. 按从左到右的顺序依次读取 nums[i] 和 index[i],在 target 数组 ...

  10. C语言计算并输出华氏温度为80F所对应的摄氏温度C。转换公式为:C=5*(F-32)/9

    #include <stdio.h> int main() { double F = 80.0, C;//定义摄氏温度变量,赋值华氏温度 C = 5 * (F - 32) / 9.0;// ...