第四章 基于本地部署的大语言模型OLlamaNeo4j图数据库的知识图谱搭建

news/2025/2/3 0:40:16/

目录

一、部署本地大语言模型Ollama

二、安装Neo4j数据库

三、应用本地大语言模型搭建知识图谱

1、导入依赖库

2、连接数据库

3、加载CSV文档

4、初始化(载入)大模型 

5、编写实体关系识别函数

6、处理文档生成知识图谱

7、将大模型识别出的关系写入数据库

8、设置QA链实现关于电影的问答功能 

9、实现电影推荐

改进与反思:

解决方法:

最终结果:


一、部署本地大语言模型Ollama

进入官网:Ollama

下载Ollama

安装Ollama到本地

 

安装完毕,打开命令行输入`ollama --help`检查是否安装成功。

 

选择合适的模型,并使用命令行指令`ollama run llama3.2:3b`进行本地安装(由于设备受限,我选择了参数大小为3b的llama3.2模型,本地存储占用2GB.)

安装完成后即可在本地进行对话

对话时只要输入运行相应模型的指令“ollama run 模型名称”即可。

 

二、安装Neo4j数据库

参考以下教程:

neo4j入门到精通——1、安装部署_neo4j需要jdk在系统环境中吗?-CSDN博客

Neo4j安装教程_51CTO博客_neo4j教程

NEO4J指定JDK路径_elasticsearch_K歌、之王-华为开发者空间

Java 11 / JDK 11 下载-CSDN博客

Neo4j启动指令:`neo4j.bat console`,停止指令:`neo4j stop`

默认用户名:`neo4j`,密码:`neo4j`

可视化网址:http://localhost:7474/

数据库用户名:neo4j,密码:your_password

注意:项目中的代码需要适配neo4j最新版,并配置相应的apoch包。

安装过程容易发生的错误:

Neo.ClientError.Statement.SyntaxError Unknown function 'apoc.version' (line 1, column 8 (offset: 7)) "RETURN apoc.version()"

  1. 检查 APOC 插件是否已安装

    如果您已经安装了 Neo4j 5.x,并且遇到这个错误,可能是因为 APOC 插件未安装或未启用。在 Neo4j 5.x 版本中,APOC 插件需要手动安装。

    您可以执行以下步骤来安装和配置 APOC 插件:

    a. 安装 APOC 插件

    • 访问 APOC Releases 页面,下载与您的 Neo4j 版本相匹配的 APOC 插件 .jar 文件。
    • 将下载的 .jar 文件放置到 Neo4j 的 plugins 目录中:
      • 如果您是手动安装的 Neo4j,plugins 目录通常位于 Neo4j 安装路径下。
      • 如果您使用 Docker 部署 Neo4j,请将 .jar 文件挂载到 Docker 容器中的 /var/lib/neo4j/plugins 目录。

    b. 配置 neo4j.conf 文件

    在 Neo4j 的配置文件 neo4j.conf 中,确保以下设置项存在并已启用(没有就自己添加):

  2. dbms.security.procedures.unrestricted=apoc.* dbms.security.procedures.allowlist=apoc.*

    • dbms.security.procedures.unrestricted 允许使用 APOC 中的所有过程。
    • dbms.security.procedures.allowlist 列出了允许的 APOC 过程。

    修改配置文件后,重启 Neo4j 服务以使设置生效。

  3. 确认 APOC 是否有效

    重新启动 Neo4j 后,您可以再次尝试查询 APOC 版本:

    在cypher输入指令:

    RETURN apoc.version()

    如果成功返回版本信息,说明 APOC 插件已安装并正确配置。

  4. 查看日志

    如果安装和配置后仍然无法使用 APOC,您可以查看 Neo4j 日志文件,通常位于 logs 目录下的 debug.logneo4j.log 文件,查看是否有错误或警告信息,帮助进一步排查问题。

完成这些步骤后,应该能够成功调用 APOC 函数。如果问题仍然存在,请提供更多详细的日志信息。

三、应用本地大语言模型搭建知识图谱

1、导入依赖库

from langchain_core.runnables import  RunnablePassthrough
from langchain_core.prompts import ChatPromptTemplate
from pydantic import BaseModel, Field
from langchain_core.output_parsers import StrOutputParser
from langchain_community.graphs import Neo4jGraph
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.chat_models import ChatOllama
from langchain_experimental.graph_transformers import LLMGraphTransformer
from neo4j import GraphDatabase
from yfiles_jupyter_graphs import GraphWidget
from langchain_community.vectorstores import Neo4jVector
from langchain_community.document_loaders import TextLoader
from langchain_community.vectorstores.neo4j_vector import remove_lucene_chars
from langchain_ollama import OllamaEmbeddings
import os
from langchain_experimental.llms.ollama_functions import OllamaFunctions
from neo4j import  Driverfrom dotenv import load_dotenvload_dotenv()

load_dotenv()函数用来加载本地环境,在项目文件夹中创建.env文件,写入相关代码,此函数能将文件内容链入程序中。

NEO4J_URI=neo4j://localhost:7687
NEO4J_USERNAME=neo4j
NEO4J_PASSWORD=12345678
import langchain
print(langchain.__version__)

0.3.7

2、连接数据库

# graph = Neo4jGraph()
graph = Neo4jGraph(url="neo4j://localhost:7687",  # 替换为您的 Neo4j 地址username="neo4j",              # 替换为您的用户名password="12345678",       # 替换为您的密码#database="my_database"         # 替换为您希望连接的数据库(默认是neo4j)
)

3、加载CSV文档

from langchain_community.document_loaders import CSVLoader
from langchain_core.documents import Document# 加载 CSV 文档
loader = CSVLoader(file_path="./data/douban_movies.csv",encoding='utf-8',  # 如果有中文,确保使用正确的编码csv_args={'delimiter': ',',  # CSV 分隔符,默认为逗号}
)
rows = loader.load()# 将每行数据作为一个文档
documents = [Document(page_content=row.page_content) for row in rows]# 检查文档数量
print(f"文档数量: {len(documents)}")
for i, doc in enumerate(documents[:5]):  # 打印前5个文档内容print(f"文档 {i+1}:")print(doc.page_content)print("---")

4、初始化(载入)大模型 

llm = OllamaFunctions(model="llama3.1:8b",  temperature=0,base_url="http://localhost:11434",format="json"
)
llm_transformer = LLMGraphTransformer(llm=llm)

5、编写实体关系识别函数

from tqdm.auto import tqdm
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import JsonOutputParser
from pydantic import BaseModel, Field
from typing import List
import json# 定义关系模式
class MovieRelation(BaseModel):movie_name: str = Field(description="电影名称")director: List[str] = Field(description="导演列表")screenwriter: List[str] = Field(description="编剧列表")actors: List[str] = Field(description="主演列表")relationships: List[dict] = Field(description="实体之间的关系列表")# 创建提示模板
prompt_template = """
请分析以下电影信息,识别出电影、导演、编剧和演员之间的关系:{text}请以JSON格式输出以下信息:
1. 电影名称
2. 导演列表
3. 编剧列表
4. 主演列表(仅包含前5名主演)
5. 实体之间的关系(如:导演-执导->电影,演员-主演->电影,编剧-编写->电影)请确保输出格式符合以下结构:
{{"movie_name": "电影名","director": ["导演1", "导演2"],"screenwriter": ["编剧1", "编剧2"],"actors": ["演员1", "演员2"],"relationships": [{{"source": "导演名", "relation": "执导", "target": "电影名"}},{{"source": "编剧名", "relation": "编写", "target": "电影名"}},{{"source": "演员名", "relation": "主演", "target": "电影名"}}]
}}
"""
# 创建提示对象
prompt = ChatPromptTemplate.from_template(prompt_template)

6、处理文档生成知识图谱


# 处理文档并生成知识图谱
def process_movie_relations(doc, llm):response = None  # 初始化response变量try:# 构建完整的提示chain = prompt | llm# 获取模型响应response = chain.invoke({"text": doc.page_content})# 添加调试信息print("原始响应类型:", type(response))print("原始响应内容:", response)# 尝试解析JSON响应if isinstance(response, str):try:parsed_response = json.loads(response)except json.JSONDecodeError as e:print(f"JSON解析错误: {str(e)}")print(f"问题响应: {response}")return Noneelif hasattr(response, 'content'):try:parsed_response = json.loads(response.content)except json.JSONDecodeError as e:print(f"JSON解析错误: {str(e)}")print(f"问题响应: {response.content}")return Noneelif isinstance(response, dict):parsed_response = responseelse:raise ValueError(f"无法处理的响应类型: {type(response)}")# 验证必要的字段required_fields = ['movie_name', 'director', 'screenwriter', 'actors', 'relationships']if all(field in parsed_response for field in required_fields):return parsed_responseelse:missing_fields = [field for field in required_fields if field not in parsed_response]raise ValueError(f"响应缺少必要字段: {missing_fields}")except Exception as e:print(f"处理错误: {str(e)}")if response:print(f"问题响应: {response}")return None

打印输出

 处理全部文档内容


# 处理所有文档并显示进度
results = []
failed_docs = []print(f"\n开始处理 {len(documents)} 部电影数据...")with tqdm(total=len(documents), desc="处理电影数据", unit="部") as pbar:for i, doc in enumerate(documents):try:result = process_movie_relations(doc, llm)if result:results.append(result)movie_name = result.get('movie_name', 'Unknown')tqdm.write(f"[{i+1}/{len(documents)}] ✓ 成功: {movie_name}")else:failed_docs.append(doc)tqdm.write(f"[{i+1}/{len(documents)}] ✗ 失败: 解析错误")except Exception as e:failed_docs.append(doc)tqdm.write(f"[{i+1}/{len(documents)}] ✗ 失败: {str(e)}")finally:pbar.update(1)# 打印详细统计
print("\n处理统计:")
print(f"总数据量: {len(documents)} 部电影")
print(f"成功处理: {len(results)} 部电影")
print(f"处理失败: {len(failed_docs)} 部电影")
print(f"成功率: {len(results)/len(documents)*100:.2f}%")# 保存成功的结果
with open('movie_relations.json', 'w', encoding='utf-8') as f:json.dump(results, f, ensure_ascii=False, indent=2)
print("\n成功的结果已保存到 movie_relations.json")# 保存失败的文档信息供后续分析
if failed_docs:with open('failed_movies.txt', 'w', encoding='utf-8') as f:for doc in failed_docs:f.write(f"---\n{doc.page_content}\n")print("失败的文档已保存到 failed_movies.txt")

成功率达到51.20%,正确转化成知识图谱的电影条数为128条,说明该模型转换能力还有待提高。

模型选取方面:

qwen2.5-coder:7b——直解析错误

llama3.1:8b  ——正确处理51.20%

可见,不同的模型对这种数据的解析能力是不同的,如果采用参数更大更适合实体关系抽取的模型效果会更好!由于本地电脑内存限制,我将继续使用已成功转化的128条数据进行图谱构建,以便给读者留下改进空间。

7、将大模型识别出的关系写入数据库

插入数据的时候,实体之间的关系是否符合:导演-执导->电影,演员-主演->电影,编剧-编写->电影

from langchain_community.graphs import Neo4jGraph
import json
from tqdm import tqdmdef import_to_neo4j(graph: Neo4jGraph, json_file: str):"""从JSON文件逐条导入电影关系数据到Neo4j数据库"""# 读取JSON文件print(f"正在读取文件: {json_file}")with open(json_file, 'r', encoding='utf-8') as f:movie_data = json.load(f)print(f"成功读取 {len(movie_data)} 条电影数据")try:# 清空数据库print("清空数据库...")graph.query("""MATCH (n)DETACH DELETE n""")# 创建索引print("创建索引...")graph.query("""CREATE INDEX IF NOT EXISTS FOR (m:Movie) ON (m.name)""")graph.query("""CREATE INDEX IF NOT EXISTS FOR (p:Person) ON (p.name)""")# 逐条处理数据print(f"\n开始导入数据,共 {len(movie_data)} 条记录...")success_count = 0error_count = 0with tqdm(total=len(movie_data), desc="导入进度") as pbar:for movie in movie_data:try:# 创建电影节点graph.query("""MERGE (m:Movie {name: $movie_name})""", {"movie_name": movie["movie_name"]})# 处理每个关系for rel in movie["relationships"]:# 创建人物节点graph.query("""MERGE (p:Person {name: $person_name})""", {"person_name": rel["source"]})# 根据关系类型创建关系if rel["relation"] == "执导":graph.query("""MATCH (p:Person {name: $person_name})MATCH (m:Movie {name: $movie_name})MERGE (p)-[:DIRECTED]->(m)""", {"person_name": rel["source"],"movie_name": movie["movie_name"]})elif rel["relation"] == "编写":graph.query("""MATCH (p:Person {name: $person_name})MATCH (m:Movie {name: $movie_name})MERGE (p)-[:WROTE]->(m)""", {"person_name": rel["source"],"movie_name": movie["movie_name"]})elif rel["relation"] == "主演":graph.query("""MATCH (p:Person {name: $person_name})MATCH (m:Movie {name: $movie_name})MERGE (p)-[:ACTED_IN]->(m)""", {"person_name": rel["source"],"movie_name": movie["movie_name"]})success_count += 1pbar.update(1)pbar.set_description(f"成功: {success_count}, 失败: {error_count}")except Exception as e:error_count += 1print(f"\n导入电影 {movie.get('movie_name', 'Unknown')} 失败: {str(e)}")pbar.update(1)pbar.set_description(f"成功: {success_count}, 失败: {error_count}")continue# 打印统计信息print("\n导入完成!")print(f"成功导入: {success_count}")print(f"导入失败: {error_count}")# 打印详细统计stats_result = graph.query("""MATCH (m:Movie)WITH COUNT(m) as moviesMATCH (p:Person)WITH movies, COUNT(p) as personsMATCH ()-[r]->()WITH movies, persons, COUNT(r) as relationsRETURN movies, persons, relations""")if stats_result and len(stats_result) > 0:stats = stats_result[0]print("\n数据库统计:")print(f"电影节点数: {stats['movies']}")print(f"人物节点数: {stats['persons']}")print(f"关系数: {stats['relations']}")# 打印各类关系的统计relation_stats = graph.query("""MATCH ()-[r]->()WITH type(r) as relation_type, COUNT(*) as countRETURN relation_type, countORDER BY count DESC""")print("\n关系类型统计:")for rel in relation_stats:print(f"{rel['relation_type']}: {rel['count']} 条")except Exception as e:print(f"导入过程中出错: {str(e)}")raise e# 使用示例
try:# 连接到Neo4j数据库graph = Neo4jGraph(url="neo4j://localhost:7687",username="neo4j",password="12345678"  # 替换为您的实际密码)# 导入数据import_to_neo4j(graph, 'movie_relations.json')except Exception as e:print(f"导入失败: {str(e)}")

8、设置QA链实现关于电影的问答功能 

# 导入必要的依赖
from langchain_core.prompts import PromptTemplate
from langchain.chains import GraphCypherQAChain# 修改Cypher查询模板
CYPHER_GENERATION_TEMPLATE = """任务: 生成查询图数据库的Cypher语句。
说明:
数据库中的关系模式如下:
- (Person)-[:DIRECTED]->(Movie) 表示导演关系
- (Person)-[:ACTED_IN]->(Movie) 表示演员关系
- (Person)-[:WROTE]->(Movie) 表示编剧关系
所有节点和关系的属性:
- Person节点有name属性
- Movie节点有name属性注意: 
- 不要使用未定义的关系类型或属性
- 返回完整的节点信息问题是:
{question}"""# 创建Cypher生成提示
CYPHER_GENERATION_PROMPT = PromptTemplate(input_variables=["schema", "question"], template=CYPHER_GENERATION_TEMPLATE
)# 创建新的QA链
chain = GraphCypherQAChain.from_llm(llm, graph=graph, verbose=True, allow_dangerous_requests=True,  # 添加这个参数cypher_prompt=PromptTemplate(input_variables=["question"], template=CYPHER_GENERATION_TEMPLATE)
)

这样设置的QA链可以:

将自然语言问题转换为Cypher查询在Neo4j数据库中执行查询将结果转换回自然语言回答您可以尝试各种问题,比如:某个导演导演了哪些电影、某个演员参演了哪些电影、某类型的电影推荐等。

# 测试查询
response = chain.run("宫崎骏执导了哪些电影?")
print(response)


# 测试查询
response = chain.run("评分最高的前5部电影是什么?")
print(response)

 


# 测试查询
response = chain.run("我想看一部战争与爱情相关的评分较高的电影有什么推荐?")
print(response)

 

9、实现电影推荐

 通过修改查询模板,添加相关的说明。

# 修改Cypher查询模板,添加推荐相关的说明
CYPHER_GENERATION_TEMPLATE = """任务: 生成查询图数据库的Cypher语句。
说明:
数据库中的关系模式如下:
- (Person)-[:DIRECTED]->(Movie) 表示导演关系
- (Person)-[:ACTED_IN]->(Movie) 表示演员关系
- (Person)-[:WROTE]->(Movie) 表示编剧关系
Movie节点的属性包括:
- name: 电影名称
- type: 电影类型
- rating: 豆瓣评分
- plot: 剧情简介请根据用户的偏好生成合适的推荐查询。问题是:
{question}"""# 创建新的QA链
chain = GraphCypherQAChain.from_llm(llm, graph=graph, verbose=True, allow_dangerous_requests=True,cypher_prompt=PromptTemplate(input_variables=["question"], template=CYPHER_GENERATION_TEMPLATE)
)# 测试各种推荐场景
recommendation_questions = [# 基于类型推荐"请推荐一些好看的爱情片","我想看评分高的动作片",# 基于导演推荐"我喜欢宫崎骏的作品风格,请推荐类似的动画电影","我看过张艺谋的《英雄》很喜欢,有类似风格的电影推荐吗",# 基于演员推荐"我很喜欢周星驰的喜剧电影,请推荐类似的","我是汤姆·汉克斯的粉丝,想看他的经典作品",# 基于评分推荐"请推荐一些豆瓣评分9分以上的经典电影","最近有什么好评的新电影推荐吗",# 组合条件推荐"想看一部评分高的爱情片,最好是90年代的经典","请推荐一些适合全家观看的动画电影"
]# 测试推荐
for question in recommendation_questions[:3]:  # 测试前3个问题print(f"\n问题:{question}")try:response = chain.run(question)print(f"推荐:{response}")except Exception as e:print(f"查询出错:{str(e)}")print("-" * 50)

 改进与反思:

 

解决方法:

 

import re
def normalize_movie_name(name):"""标准化电影名称,处理各种特殊情况"""# 常见的电影名称映射name_mapping = {"Coco": "寻梦环游记","小森林 夏秋篇 リトル・フォレスト 夏・秋": "小森林 夏秋篇","城王之李 City Lights": "城市之光","Rain Man": "雨人","The Notebook": "恋恋笔记本","Lord of War": "战争之王","Waterloo Bridge": "魂断蓝桥","黄崋小口橡小窗杀": "黄金三镖客","芦苇镇": "芦苇镇"}if name in name_mapping:return name_mapping[name]return namedef parse_movie_attributes(doc):"""从文档中解析电影属性"""movie = {}# 使用正则表达式提取各个属性patterns = {'name': r'电影名称:\s*(.*?)(?=\n|$)','director': r'导演:\s*(.*?)(?=\n|$)','writer': r'编剧:\s*(.*?)(?=\n|$)','actors': r'主演:\s*(.*?)(?=\n|$)','genres': r'类型:\s*(.*?)(?=\n|$)','country': r'制片国家/地区:\s*(.*?)(?=\n|$)','language': r'语言:\s*(.*?)(?=\n|$)','release_date': r'上映日期:\s*(.*?)(?=\n|$)','duration': r'片长:\s*(\d+).*?(?=\n|$)','rating': r'豆瓣评分:\s*([\d.]+)(?=\n|$)','plot': r'剧情简介:\s*(.*?)(?=\n\n|$)'}for key, pattern in patterns.items():match = re.search(pattern, doc, re.DOTALL)if match:value = match.group(1).strip()if key in ['director', 'writer', 'actors', 'genres']:# 处理列表类型的属性value = [v.strip() for v in value.split('/')]elif key == 'duration':# 转换为整数value = int(value)elif key == 'rating':# 转换为浮点数value = float(value)elif key == 'release_date':# 提取年份year_match = re.search(r'(\d{4})', value)if year_match:value = int(year_match.group(1))else:value = Nonemovie[key] = valuereturn moviedef update_movie_attributes(documents, graph):"""更新数据库中电影的属性"""success_count = 0error_count = 0skipped_count = 0# 获取数据库中现有的电影名称existing_movies = graph.query("""MATCH (m:Movie)RETURN m.name as name""")existing_names = {record['name'] for record in existing_movies}print(f"数据库中现有电影数量:{len(existing_names)}")with tqdm(total=len(documents), desc="更新电影属性") as pbar:for doc in documents:try:# 确保从doc对象中正确获取文本内容content = doc.page_content if hasattr(doc, 'page_content') else str(doc)# 解析文档中的电影信息movie = parse_movie_attributes(content)if not movie or 'name' not in movie:skipped_count += 1pbar.update(1)continue# 标准化电影名称movie_name = movie['name'].split()[0]  # 只取中文名部分db_name = None# 尝试直接匹配if movie_name in existing_names:db_name = movie_nameelse:# 尝试标准化后匹配normalized_name = normalize_movie_name(movie_name)if normalized_name in existing_names:db_name = normalized_name# 只处理找到匹配的电影if db_name:# 处理类型列表genres = movie.get('genres', [])if isinstance(genres, str):genres = [g.strip() for g in genres.split('/')]# 更新电影属性update_query = """MATCH (m:Movie {name: $db_name})SET m.rating = toFloat($rating),m.year = toInteger($year),m.duration = toInteger($duration),m.country = $country,m.language = $language,m.genres = $genres,m.plot = $plot"""params = {'db_name': db_name,'rating': movie.get('rating'),'year': movie.get('release_date'),'duration': movie.get('duration'),'country': movie.get('country'),'language': movie.get('language'),'genres': genres,'plot': movie.get('plot', '')}# 打印调试信息print(f"\n正在更新电影: {db_name}")print(f"评分: {params['rating']}")print(f"类型: {params['genres']}")graph.query(update_query, params)success_count += 1else:skipped_count += 1except Exception as e:print(f"处理电影时出错: {str(e)}")error_count += 1pbar.update(1)print(f"\n更新完成!")print(f"成功更新: {success_count}")print(f"更新失败: {error_count}")print(f"跳过处理: {skipped_count}")

 

 最终结果:

设置QA链,根据电影内容进行推荐。

# 修改Cypher查询模板,添加更多维度的推荐说明
CYPHER_GENERATION_TEMPLATE = """任务: 根据用户需求生成Neo4j查询语句,实现电影推荐。数据库模式说明:
1. 节点类型:
- Movie: 电影节点
- Person: 人物节点(导演/演员/编剧)2. 关系类型:
- (Person)-[:DIRECTED]->(Movie): 导演关系
- (Person)-[:ACTED_IN]->(Movie): 演员关系  
- (Person)-[:WROTE]->(Movie): 编剧关系3. Movie节点属性:
- name: 电影名称
- rating: 豆瓣评分(float)
- year: 上映年份(int) 
- duration: 片长(int,分钟)
- country: 制片国家
- language: 语言
- genres: 电影类型(list)
- plot: 剧情简介推荐维度说明:
1. 基于类型推荐: 使用genres属性匹配
2. 基于评分推荐: 使用rating属性筛选
3. 基于年代推荐: 使用year属性筛选
4. 基于导演/演员推荐: 通过关系查询
5. 基于国家/语言推荐: 使用country/language属性
6. 多维度组合推荐: 结合多个属性用户问题:
{question}请生成合适的Cypher查询语句,注意:
1. 优先按评分降序排序
2. 建议返回电影名称、评分、年份、类型等关键信息
3. 适当限制返回结果数量(如LIMIT 5)
4. 确保ORDER BY在LIMIT之前
"""# 创建新的QA链
chain = GraphCypherQAChain.from_llm(llm,graph=graph,verbose=True,allow_dangerous_requests=True,  # 添加这个参数来确认安全风险cypher_prompt=PromptTemplate(input_variables=["question"],template=CYPHER_GENERATION_TEMPLATE)
)# # 测试各种推荐场景
# test_questions = [
#     # 单维度推荐
#     "请推荐一些评分超过9分的经典电影",
#     "有什么好看的动作片推荐?",
#     "90年代的经典电影有哪些?",
#     "宫崎骏导演的动画电影推荐",#     # 多维度组合推荐
#     "想看一部评分高的爱情片,最好是90年代的",
#     "有什么适合全家一起看的、评分不错的动画电影?",
#     "请推荐几部张艺谋导演的、评分高于8分的电影",
#     "想看一部评分高的日本电影,最好是剧情片"
# ]# # 测试推荐效果
# for question in test_questions:
#     print(f"\n问题: {question}")
#     print("-" * 50)
#     try:
#         response = chain.run(question)
#         print(f"推荐结果:\n{response}")
#     except Exception as e:
#         print(f"查询出错: {str(e)}")
#     print("=" * 50)
chain.run("请推荐一些评分超过9分的经典电影")

test_queries = ["请推荐一些评分超过9分的经典电影","有什么好看的动作片推荐?","90年代的经典电影有哪些?","宫崎骏导演的动画电影推荐"
]for query in test_queries:print(f"\n问题: {query}")try:response = chain.run(query)print(f"回答:\n{response}")except Exception as e:print(f"错误: {str(e)}")

 

还是有一些不足,但是回答的正确率已经达到60%以上。

程序文件链接:

通过网盘分享的文件:豆瓣电影知识图谱构建.rar
链接: https://pan.baidu.com/s/1aKIHXtZXCi-FjFLrfW8z6A 提取码: 6bkp 
--来自百度网盘超级会员v5的分享


http://www.ppmy.cn/news/1568824.html

相关文章

家政预约小程序11分类展示

目录 1 创建页面2 配置导航菜单3 配置侧边栏选项卡4 配置数据列表5 首页和分类页联动总结 我们现在在首页开发了列表显示服务信息的功能,在点击导航菜单的时候,需要自动跳转到对应的分类,本篇我们介绍一下使用侧边栏选项卡实现分类显示的功能…

2025年01月26日Github流行趋势

项目名称:onlook 项目地址url:https://github.com/onlook-dev/onlook项目语言:TypeScript历史star数:4871今日star数:207项目维护者:Kitenite, drfarrell, iNerdStack, abhiroopc84, apps/dependabot项目简…

matlab提取滚动轴承故障特征

为了精准、稳定地提取滚动轴承故障特征,提出了基于变分模态分解和奇异值分解的特征提取方法,采用标准模糊C均值聚类(fuzzy C means clustering, FCM)进行故障识 别。对同一负荷下的已知故障信号进行变分模态分解,利用 奇异值分解技术进一步提…

洛谷 P8724 [蓝桥杯 2020 省 AB3] 限高杆

洛谷题目传送门 题目描述 某市有 n 个路口,有 m 段道路连接这些路口,组成了该市的公路系统。其中一段道路两端一定连接两个不同的路口。道路中间不会穿过路口。 由于各种原因,在一部分道路的中间设置了一些限高杆,有限高杆的路…

【暴力洗盘】的实战技术解读-北玻股份和三变科技

龙头的上攻与回调动作都是十分惊人的。不惊人不足以吸引投资者的关注,不惊人也就不能成为龙头了。 1.建筑节能概念--北玻股份 建筑节能,是指在建筑材料生产、房屋建筑和构筑物施工及使用过程中,满足同等需要或达到相同目的的条件下&#xf…

6.攻防世界php_rce

进入题目页面如下 进入页面后也没有发现注入点,加上题目提示是php,还有rce RCE(Remote Code Execution)远程代码执行漏洞 基本概念 远程代码执行指攻击者无需物理接触目标系统,通过网络等远程方式,向目标…

Redis 基础命令

1. redis 命令官网 https://redis.io/docs/latest/commands/ 2. 在 redis-cli 中使用 help 命令 # 查看 help string 基础命令 keys * # * 代表通配符set key value # 设置键值对del key # 删除键expire key 时间 # 给键设置时间 # -2 代表时间到期了, -1 代表…

stm32硬件实现与w25qxx通信

使用的型号为stm32f103c8t6与w25q64。 STM32CubeMX配置与引脚衔接 根据stm32f103c8t6引脚手册,采用B12-B15四个引脚与W25Q64连接,实现SPI通信。 W25Q64SCK(CLK)PB13MOSI(DI)PB15MISO(DO)PB14CS&#xff08…