概要
本文深入探讨了如何利用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%,对应的场次分别为131374和131000,他的别名叫做“瞎子”。
> Finished chain.
盲僧的胜率分别为49.32%和49.60%,对应的场次分别为131374和131000,他的别名叫做“瞎子”。
> 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.
小结
整体就是对之前几篇文章的一个汇总,非常简单的大模型应用工程,欢迎大家评论!祝大家周末快乐