517691c2d6
6.18 更新数据配置路径统一,和前端demo
231 lines
8.1 KiB
Python
231 lines
8.1 KiB
Python
from langchain_openai import ChatOpenAI
|
|
from langchain_core.output_parsers import StrOutputParser
|
|
from langchain_core.prompts import ChatPromptTemplate
|
|
from langchain_core.prompts.prompt import PromptTemplate
|
|
from langchain_core.output_parsers import JsonOutputParser
|
|
|
|
from extraction_info import neo4j_url, neo4j_username, neo4j_password
|
|
|
|
qwen_llm = ChatOpenAI(
|
|
openai_api_base="https://api.siliconflow.cn/v1",
|
|
model_name="Qwen/Qwen2.5-72B-Instruct",
|
|
# sk-muuqautpcyuowjtgfecbnivqodlhzydtfslqkmwbknawejsx
|
|
openai_api_key="sk-bbeamiumkouptsrueilgufqqyuumelcsivxwjbdugqwsqhwj",
|
|
temperature=0.1
|
|
)
|
|
|
|
deep_v3 = ChatOpenAI(
|
|
openai_api_base="https://api.siliconflow.cn/v1",
|
|
model_name="deepseek-ai/DeepSeek-V3",
|
|
# sk-muuqautpcyuowjtgfecbnivqodlhzydtfslqkmwbknawejsx
|
|
openai_api_key="sk-bbeamiumkouptsrueilgufqqyuumelcsivxwjbdugqwsqhwj",
|
|
temperature=0.1
|
|
)
|
|
|
|
def Problem_rewrite():
|
|
PromptTemplate1 = """
|
|
请根据用户的输入内容,替换其中内容:
|
|
|
|
【用户输入】:
|
|
{query}
|
|
|
|
【检索内容】:
|
|
{retriever}
|
|
|
|
【举例】:
|
|
用户输入:塔材装材费是多少?
|
|
检索内容:角钢塔_塔材装材费_元
|
|
得到的结果:【角钢塔_塔材装材费_元】是多少?
|
|
|
|
【要求】:
|
|
- 不允许输出任何解释、标点符号或额外内容,仅在原输入上进行替换
|
|
- 替换后的内容要加上【】
|
|
"""
|
|
|
|
Prompt = ChatPromptTemplate.from_template(PromptTemplate1)
|
|
|
|
Chain = Prompt | deep_v3 | StrOutputParser()
|
|
# Chain = Prompt | llm | StrOutputParser()
|
|
|
|
return Chain
|
|
|
|
def question_answer():
|
|
PromptTemplate1 = """
|
|
请根据用户的输入内容,和检索到的信息,回答问题:
|
|
|
|
【用户输入】:
|
|
{query}
|
|
|
|
【实际检索目标】:
|
|
{retriever_keywords}
|
|
|
|
【检索内容】:
|
|
{retriever_info}
|
|
|
|
【要求】:
|
|
- 不允许输出任何解释、标点符号或额外内容
|
|
- 要选找到和实际检索目标最接近的检索内容,直接读取相关信息进行解答,不做任何运算
|
|
- 检索到的信息不一定有用,如果和问题毫无相关性,则回答不会
|
|
"""
|
|
|
|
Prompt = ChatPromptTemplate.from_template(PromptTemplate1)
|
|
|
|
Chain = Prompt | deep_v3 | StrOutputParser()
|
|
# Chain = Prompt | llm | StrOutputParser()
|
|
|
|
return Chain
|
|
|
|
|
|
def question_answer_calculation():
|
|
PromptTemplate1 = """
|
|
请根据用户的实际检索目标查到的内容,基于用户输入和计算公式回答问题:
|
|
|
|
【用户输入】:
|
|
{query}
|
|
|
|
【实际检索目标】:
|
|
{retriever_keywords}
|
|
|
|
【计算公式】:
|
|
{calculation}
|
|
|
|
【检索内容】:
|
|
{retriever_info}
|
|
|
|
【要求】:
|
|
- 不允许输出任何解释、标点符号或额外内容
|
|
- 要选找到和实际检索目标最接近的检索内容,直接读取相关信息进行解答,不做任何运算
|
|
- 检索到的信息不一定有用,如果和问题毫无相关性,则回答不会
|
|
"""
|
|
|
|
Prompt = ChatPromptTemplate.from_template(PromptTemplate1)
|
|
|
|
Chain = Prompt | deep_v3 | StrOutputParser()
|
|
# Chain = Prompt | llm | StrOutputParser()
|
|
|
|
return Chain
|
|
|
|
|
|
"""neo4j"""
|
|
|
|
from langchain_community.graphs import Neo4jGraph
|
|
|
|
|
|
|
|
graph = Neo4jGraph(
|
|
url = neo4j_url,
|
|
username = neo4j_username,
|
|
password = neo4j_password,
|
|
)
|
|
|
|
graph.refresh_schema()
|
|
|
|
|
|
from langchain.prompts import (
|
|
PromptTemplate,
|
|
SystemMessagePromptTemplate,
|
|
HumanMessagePromptTemplate,
|
|
ChatPromptTemplate,
|
|
)
|
|
|
|
cypher_generation_template = """
|
|
# 任务:
|
|
为 Neo4j 图数据库生成 Cypher 查询。
|
|
|
|
# 说明:
|
|
仅使用架构中提供的关系类型和属性。 不得使用架构中未提供的关系类型或属性。
|
|
|
|
# 架构:
|
|
{schema}
|
|
|
|
# 注意:
|
|
不得在回答中包含任何解释或道歉。
|
|
不得回答任何不要求构造 Cypher 查询的问题。
|
|
回答中不得包含除生成的 Cypher 查询以外的任何文本。
|
|
请确保查询中关系的方向正确,并正确为实体和关系设置别名。
|
|
在查询中使用 WITH 为后续语句设置别名(例如,WITH v as visit, c.billing_amount as billing_amount)。
|
|
如果需要进行数字除法运算,请确保对分母进行非零过滤。
|
|
|
|
# 注意
|
|
在查询关键字时,不能使用MATCH (n:PropertyNode),要用最原始的MATCH (n)
|
|
在查询中分析缺失属性时,必须使用 IS NULL 或 IS NOT NULL。
|
|
不得在查询中返回嵌套属性。
|
|
不得在查询中包含 "GROUP BY" 语句。
|
|
请确保为所有后续语句使用 WITH 设置别名(例如,WITH v as visit, c.billing_amount as billing_amount)。
|
|
如果需要进行数字除法运算,请确保对分母进行非零过滤。
|
|
|
|
# 示例:
|
|
|
|
1.
|
|
输入:
|
|
查找一下【工程数据/安装工程/安装/架空输电线路本体工程/基础工程】的【定额】下的【YX2-1/YX2-2/YX2-3/YX2-4/YX2-5/YX2-6/YX2-7】
|
|
输出:
|
|
MATCH (root:ProjectDivisionItem [name: '架空输电线路本体工程'])-[:HAS_CHILD]->(base:ProjectDivisionItem [name: '基础工程'])
|
|
MATCH path = (base)-[:HAS_CHILD]->(child)-[:HAS_COMPONENT*1..]->(component)
|
|
WHERE ANY(prop IN keys(component) WHERE toString(component[prop]) =~ 'YX2-[1-7]')
|
|
RETURN component
|
|
|
|
2.
|
|
输入:
|
|
查找一下【工程数据/安装工程/安装/架空输电线路本体工程/杆塔工程/杆塔组立/铁塔、钢管杆组立】的【主材】下的【角钢】
|
|
输出:
|
|
MATCH (root:ProjectDivisionItem [name: '架空输电线路本体工程'])-[:HAS_CHILD]->(base1:ProjectDivisionItem [name: '杆塔工程'])-[:HAS_CHILD]->(base2:ProjectDivisionItem [name: '杆塔组立'])-[:HAS_CHILD]->(base3:ProjectDivisionItem [name: '铁塔、钢管杆组立'])
|
|
MATCH path = (base3)-[:HAS_COMPONENT*1..]->(component)
|
|
WHERE ANY(prop IN keys(component) WHERE toString(component[prop]) CONTAINS '角钢')
|
|
RETURN component
|
|
|
|
3.
|
|
输入:
|
|
查找一下【架空输电线路本体工程/架线工程/导地线架设】和【架空输电线路本体工程/架线工程/导地线跨越架设】的【主材】下的【高导电率】
|
|
输出:
|
|
MATCH (root:ProjectDivisionItem [name: '架空输电线路本体工程'])
|
|
-[:HAS_CHILD]->(base1:ProjectDivisionItem [name: '架线工程'])-[:HAS_CHILD]->(base:ProjectDivisionItem)
|
|
WHERE base.name IN ['导地线架设', '导地线跨越架设']
|
|
MATCH path = (base)-[:HAS_COMPONENT*1..]->(component)
|
|
WHERE ANY(prop IN keys(component) WHERE toString(component[prop]) CONTAINS '高导电率')
|
|
RETURN component
|
|
|
|
|
|
问题:
|
|
{question}
|
|
"""
|
|
|
|
cypher_generation_prompt = PromptTemplate(
|
|
input_variables=["schema", "question"], template=cypher_generation_template
|
|
)
|
|
|
|
qa_generation_template = """你是一个助手,根据 Neo4j Cypher 查询的结果生成可读的回答。查询结果部分包含根据用户的自然语言问题生成的 Cypher 查询结果。提供的信息是权威的;你必须始终使用这些信息来构建回答,不得使用内部知识来质疑或更正这些信息。确保回答听起来像是对问题的直接回应。
|
|
|
|
用户提出了以下问题:
|
|
{question}
|
|
|
|
运行了一个 Cypher 查询,生成了以下结果:
|
|
{context}
|
|
|
|
如果提供的信息是空的,就说明你不知道答案。
|
|
空的信息看起来是这样的:[]
|
|
|
|
如果查询结果不为空,你必须提供一个回答。
|
|
|
|
如果有查询结果数据,绝不能说你没有正确的信息。如果用户提问时需要显示所有相关查询结果,确保你显示所有相关结果。你必须始终假设提供的查询结果与问题相关。回答时只能基于提供的查询结果构建答案。
|
|
|
|
"""
|
|
|
|
qa_generation_prompt = PromptTemplate(
|
|
input_variables=["context", "question"], template=qa_generation_template
|
|
)
|
|
|
|
from langchain.chains import GraphCypherQAChain
|
|
|
|
booway_cypher_chain = GraphCypherQAChain.from_llm(
|
|
allow_dangerous_requests=True,
|
|
cypher_llm=deep_v3, # 用于生成Cypher查询的LLM
|
|
qa_llm=deep_v3, # 用于根据Cypher查询结果生成答案的LLM
|
|
graph=graph,
|
|
verbose=True,
|
|
qa_prompt=qa_generation_prompt,
|
|
cypher_prompt=cypher_generation_prompt,
|
|
validate_cypher=True,
|
|
top_k=100,
|
|
return_intermediate_steps=True
|
|
) |