大模型应用开发(七):基于LangChain+LLM的agent集成知识图谱、数据库和 RAG本地知识库功能集合

概要

本文深入探讨了如何利用LangChain和大模型,根据代理(agent)选择合适的工具,构建知识图谱、数据库和RAG本地知识库三种功能合一。并采用WebSocket实现实时通信,通过Postman进行问答测试。
可以说这是对之前所有代码的全面集成,将多个独立的小功能整合成一个完整的问答系统知识库,有需要的可以查看我之前发布的文章。

大模型应用开发(一):基于LangChain+LLM(千问)的基础问答使用,非常基础的内容哦
大模型应用开发(二):RAG实战教程,基于LangChain+Faiss+千问的本地知识库问答简单模式,一看就会
大模型应用开发(三):基于LangChain+LLM(千问)对于数据库SQLite保姆级的基础提问的一个功能
大模型应用开发(四):基于Langchain和LLM(千问大模型)对知识图谱(neo4j)的生成和自然语言简单问答的输出
大模型应用开发(五):基于 Flask 框架的 Python WebSocket 使用与测试
大模型应用开发(六):基于LangChain+LLM的agent实战教学包含Memory(上下文记忆和记忆存储)记忆功能

整体架构流程

请添加图片描述

技术名词解释

  • LangChain
  • LLM
  • Agent
  • Neo4j
  • Sqlite
  • Faiss

技术细节

第一部分:websocket实时通信接口

需要的安装包和注意事项移步 大模型应用开发(五):基于 Flask 框架的 Python WebSocket 使用与测试

from flask import Flask
from flask_sockets import Sockets
from flask_cors import *

from llm.agent_test.agent import agent_test

# Flask格式
app = Flask(__name__)
sockets = Sockets(app)
# 跨域问题
CORS(app, supports_credentials=True)


# lol查询接口
@sockets.route('/lol')
def echo_socket(ws):
    while not ws.closed:
        msg = ws.receive()
        if msg is not None:
            response = agent_test(msg)
            ws.send(response)


if __name__ == "__main__":
    from gevent import pywsgi
    from geventwebsocket.handler import WebSocketHandler

    # 注册ip和端口号
    server = pywsgi.WSGIServer(('127.0.0.1', 8082), app, handler_class=WebSocketHandler)
    print('server start')
    server.serve_forever()

第二部分:websocket中调用的agent_test

相关内容介绍移步大模型应用开发(六):基于LangChain+LLM的agent实战教学包含Memory(上下文记忆和记忆存储)记忆功能
这里区别的地方是tools = [neo4jInfo, SQLiteInfo, knowledgeInfo],tools工具可以增加多个

import json


from langchain import hub
from langchain.agents import AgentExecutor, create_structured_chat_agent
from langchain_community.chat_message_histories import RedisChatMessageHistory
from langchain_core.runnables import RunnableWithMessageHistory
from typing import Dict, Any
from llm.agent_tools.agent_tools import SQLiteInfo, neo4jInfo, knowledgeInfo
from llm.model_init.init import LLModel

message_history = RedisChatMessageHistory(
    url="redis://127.0.0.1:6379/1", session_id="my-session"
)

api_key = "sk-xxx"

llm_instance = LLModel(api_key=api_key)

llm = llm_instance.initialize_Tongyi_model()

prompt = hub.pull("hwchase17/structured-chat-agent")

tools = [neo4jInfo, SQLiteInfo, knowledgeInfo]
agent = create_structured_chat_agent(
    llm,
    tools,
    prompt
)

agent_executor = AgentExecutor(agent=agent,
                               tools=tools,
                               verbose=True,
                               intermediate_steps=True)

agent_with_chat_history = RunnableWithMessageHistory(
    agent_executor,
    # 必传参数,session_id 在大多数实际场景中,需要一个会话ID。它在这里并没有真正使用,
    # 因为我们使用的是一个简单的内存中的ChatMessageHistory
    lambda session_id: message_history,
    input_messages_key="input",
    history_messages_key="chat_history",
)


def agent_test(query: str):
    # 设置memory session_id
    response = agent_with_chat_history.invoke(
        {"input": query},
        config={"configurable": {"session_id": "123"}})

    result = response["output"]

    result: Dict[str, Any] = {
        "data": result
    }
    # 格式转换
    result = json.dumps(result, ensure_ascii=False)
    return result

第三部分是agent_tools工具:

这部分内容是把三个agent工具进行融合,使用tools工具给agent去根据每个tool工具的描述进行选择执行。
大模型应用开发(二):RAG实战教程,基于LangChain+Faiss+千问的本地知识库问答简单模式,一看就会
大模型应用开发(三):基于LangChain+LLM(千问)对于数据库SQLite保姆级的基础提问的一个功能
大模型应用开发(四):基于Langchain和LLM(千问大模型)对知识图谱(neo4j)的生成和自然语言简单问答的输出

from langchain.tools import tool
from langchain_community.chains.graph_qa.cypher import GraphCypherQAChain
from langchain_community.graphs import Neo4jGraph
from langchain_community.utilities import SQLDatabase
from langchain_core.prompts import PromptTemplate
from langchain_experimental.sql import SQLDatabaseChain

from llm.knowledge_base.knowledgeTest_0918 import FaissWord
from llm.model_init.init import LLModel

import os

api_key = "sk-xxx"

llm_instance = LLModel(api_key=api_key)
llm = llm_instance.initialize_Tongyi_model()


@tool(return_direct=True)
def SQLiteInfo(query: str):
    """数据库相关内容,胜率,别名"""
    db = SQLDatabase.from_uri(f"sqlite:///D:/sqlite/ai.db")
    # 数据库提示词
    template = ''' 给定一个输入问题,优先查询示例,很重要,根据{input}严格按照示例进行筛选输出,
                   按照示例进行查询,首先创建一个语法正确的{dialect}查询来运行,然后查看查询结果并返回答案,不要执行任何。
                   使用以下格式:
                   示例1:
                   Question:"盲僧2024年10月16日的胜率情况和场次和他的别名"
                   SQLQuery: SELECT 
                               OPGGGGGGGG.OPGG_WINNING_RATE RATE, 
                               OPGGGGGGGG.OPGG_SESSION SESSION, 
                               LOL_HERO_MSG.LOL_ALIAS  ALIAS
                             FROM 
                               OPGG_MSG OPGGGGGGGG
                             JOIN 
                                LOL_HERO_MSG 
                             ON 
                                OPGGGGGGGG.OPGG_LOL_HERO_NAME_ID = LOL_HERO_MSG.ID 
                             WHERE 
                                OPGGGGGGGG.OPGG_UPDATE_TIME = '2024-10-16' 
                                AND LOL_HERO_MSG.LOL_HERO_NAME = '盲僧';
                   SQLResult:"SQLquery的查询结果"
                   Answer:"盲僧在2024年10月16日这一天的胜率为RATE%。出场次数为SESSION,他的别名叫做ALIAS。
                   仅使用以下的表:
                   {table_info}
                   问题:{input}'''

    prompt = PromptTemplate(
        input_variables=["dialect", "table_info", "input"],
        template=template
    )
    # 创建一个生成 SQL 查询的链
    db_chain = SQLDatabaseChain.from_llm(llm, db, prompt=prompt, verbose=True)
    # 运行查询问题
    response = db_chain.invoke(query)
    response = response["result"]
    return response


@tool(return_direct=True)
def neo4jInfo(query: str):
    """知识图谱工具,查询人物关系和隶属地区"""
    os.environ["NEO4J_URI"] = "bolt://localhost:7687"
    os.environ["NEO4J_USERNAME"] = "neo4jlol"
    os.environ["NEO4J_PASSWORD"] = "12345678"
    os.environ["NEO4J_DATABASE"] = "neo4jlol"
    graph = Neo4jGraph()
    # cypher提示词
    cypher_generation_template = """  
          任务:  
          为Neo4j图数据库生成Cypher查询。  
          说明:  
          仅使用提供的模式中的关系类型和属性。  
          不要使用任何未提供的其他关系类型或属性。
          仅return出现的所有节点,只需要return问题的节点  
          请根据示例输出一样的Cypher
          模式:  
          {schema}  
          Cypher examples1:
          # 薇的姐妹是谁
            cypher
            MATCH (ws:人物 {{id: "蔚"}})-[:姐妹]->(ss:人物)
            RETURN ws, ss
          注意:  
          在回答中不要包含任何解释或道歉。  
          不要回答任何可能要求你构建除Cypher语句之外的任何文本的问题。  
          确保查询中的关系方向是正确的。  
          确保正确地为实体和关系设置别名。  
          不要运行会向数据库添加或删除内容的任何查询。  
          确保将后续所有语句都设置别名为with语句。  
          如果涉及线路指向节点的是routeNameA。
          问题是:  
          {question},返回问题出现的节点,不要返回属性
          """

    cypher_generation_prompt = PromptTemplate(
        input_variables=["schema", "question"], template=cypher_generation_template
    )
    # 问答提示词
    qa_generation_template = """您是一个助手,根据Neo4j Cypher查询的结果生成人类可读的响应。  
            查询结果部分包含基于用户自然语言问题生成的Cypher查询的结果。  
            提供的信息是权威的,您绝不能怀疑它或尝试使用内部知识来纠正它。  
            使答案听起来像对问题的回答。 
            不需要回答与问题无关的内容。
            查询结果:  
            {context}  
            问题:  
            {question}  
            示例1:
            问题:祖安有哪些人
            回答:英雄联盟祖安包含的英雄有
            如果提供的信息为空,请说您不知道答案。  
            空信息的样子是这样的:[] 
            如果信息不为空,您必须使用结果提供答案。
            """

    qa_generation_prompt = PromptTemplate(
        input_variables=["context", "question"], template=qa_generation_template
    )
    # graph neo4j数据库连接
    # llm 大模型
    # verbose true则输出cypher语句和返回的Full Context
    # validate_cypher true 确保语法正确,语义和底层数据匹配

    hospital_cypher_chain = GraphCypherQAChain.from_llm(
        llm=llm,
        graph=graph,
        verbose=True,
        qa_prompt=qa_generation_prompt,
        cypher_prompt=cypher_generation_prompt,
        validate_cypher=True
    )

    response = hospital_cypher_chain.invoke(query)
    response = response["result"]
    return response


@tool(return_direct=True)
def knowledgeInfo(query: str):
    """本地知识库查询Q、W、E、R具体介绍,双城之战"""
    response = FaissWord.faissTest(query)

    return response

使用postman进行测试
在这里插入图片描述
三个问题:图片是对应工具描述,agent通过问题和对工具的描述进行选择工具
1.查询盲僧胜率(查询数据库工具)
在这里插入图片描述

2.介绍盲僧的Q技能(RAG本地知识库工具)
在这里插入图片描述

3.祖安有哪些人物(neo4jInfo工具)
在这里插入图片描述
整体agent思考流程:

D:\AI\conda\envs\aiAgent\lib\site-packages\langsmith\client.py:354: LangSmithMissingAPIKeyWarning: API key must be provided when using hosted LangSmith API
  warnings.warn(
server start


> Entering new AgentExecutor chain...

{
  "action": "SQLiteInfo",
  "action_input": "查询盲僧胜率"
}


> Entering new SQLDatabaseChain chain...
查询盲僧胜率
SQLQuery:```sql
SELECT 
  OPGGGGGGGG.OPGG_WINNING_RATE RATE, 
  OPGGGGGGGG.OPGG_SESSION SESSION, 
  LOL_HERO_MSG.LOL_ALIAS ALIAS
FROM 
  OPGG_MSG OPGGGGGGGG
JOIN 
  LOL_HERO_MSG 
ON 
  OPGGGGGGGG.OPGG_LOL_HERO_NAME_ID = LOL_HERO_MSG.ID 
WHERE 
  LOL_HERO_MSG.LOL_HERO_NAME = '盲僧';


**SQLResult:** "SQLquery的查询结果"

**Answer:** "盲僧的胜率为RATE%,出场次数为SESSION,他的别名叫做ALIAS。"

请注意,上述SQL查询没有指定日期,因此它将返回所有记录中的盲僧胜率、场次和别名信息。如果需要特定日期的数据,请在WHERE子句中添加日期条件,如示例1所示。
SQLResult: [('49.32', 131374, '瞎子'), ('49.60', 131000, '瞎子')]
Answer:盲僧的胜率分别为49.32%49.60%,对应的场次分别为131374131000,他的别名叫做“瞎子”。
> Finished chain.
盲僧的胜率分别为49.32%49.60%,对应的场次分别为131374131000,他的别名叫做“瞎子”。


> Finished chain.


> Entering new AgentExecutor chain...

{
  "action": "knowledgeInfo",
  "action_input": "介绍盲僧的Q技能"
}
```盲僧·李青的Q技能名为“天音波/回音击”,具体说明如下:

### 天音波
- **冷却时间**11/10/9/8/7- **射程**1200
- **消耗**50能量

**技能效果**- 李青发出刺耳的声波定位敌人,对首个敌人造成55/80/105/130/155 (+100% 额外AD)物理伤害。
- 如果天音波击中敌人,李青在接下来3秒内可以施放回音击。

### 回音击
- **冷却时间**:无单独冷却时间,与天音波共享冷却时间
- **射程**1200
- **消耗**30能量

**技能效果**- 李青冲向被天音波击中的敌人,造成55/80/105/130/155 (+100% 额外AD)物理伤害,并根据敌人损失生命值0-100%造成额外百分比伤害(对野怪最多附加400点伤害)。

### 综合说明
- **天音波**主要用于探测和标记敌人,为后续的回音击创造条件。
- **回音击**则用于快速接近敌人并造成高额伤害,特别适合于追击和击杀低血量的敌人。
- 这两个技能的组合使得李青在野区和Gank中具有极高的机动性和爆发力。


> Finished chain.


> Entering new AgentExecutor chain...

{
  "action": "neo4jInfo",
  "action_input": "祖安有哪些人物"
}


> Entering new GraphCypherQAChain chain...
Generated Cypher:
cypher
MATCH (z:地点 {id: "祖安"})<-[:属于]-(p:人物)
RETURN z, p

Full Context:
[{'z': {'id': '祖安'}, 'p': {'id': '沃里克'}}, {'z': {'id': '祖安'}, 'p': {'id': '金克丝'}}, {'z': {'id': '祖安'}, 'p': {'id': '艾克'}}, {'z': {'id': '祖安'}, 'p': {'id': '辛吉德'}}, {'z': {'id': '祖安'}, 'p': {'id': '吉格斯'}}]

> Finished chain.
祖安的人物包括沃里克、金克丝、艾克、辛吉德和吉格斯。


> Finished chain.

小结

整体就是对之前几篇文章的一个汇总,非常简单的大模型应用工程,欢迎大家评论!祝大家周末快乐

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值