GLM-4-9B-Chat-1M中文长文本专项:200万字小说情节追踪与角色关系图谱生成
GLM-4-9B-Chat-1M中文长文本专项:200万字小说情节追踪与角色关系图谱生成
你有没有想过,让AI一口气读完一整部《三体》或者《红楼梦》,然后和你聊聊里面的情节发展、人物关系和隐藏的伏笔?这听起来像是科幻小说里的场景,但现在,借助GLM-4-9B-Chat-1M这个支持百万字上下文的大模型,这个想法已经变成了现实。
今天,我们就来一起探索如何用这个“超级大脑”,来处理和分析超长文本,特别是用它来追踪一部200万字小说的复杂情节,并自动生成清晰的角色关系图谱。无论你是文学研究者、内容创作者,还是单纯对AI能力感到好奇的技术爱好者,这篇文章都将为你展示一个全新的文本分析视角。
1. 为什么需要处理百万字长文本?
在开始动手之前,我们先聊聊为什么这个能力如此重要。
想象一下,你是一位网文编辑,每天要审阅几十万字的连载小说;或者你是一位学术研究者,需要分析整部古籍的脉络。传统的方法要么是把文本切成小块分别处理,结果丢失了整体的连贯性;要么是人工阅读,效率低下且容易遗漏细节。
GLM-4-9B-Chat-1M的1M上下文长度,大约能容纳200万个中文字符。这意味着:
- 完整理解:可以把一整部超长篇小说一次性喂给模型,让它建立完整的“世界观记忆”
- 关联分析:模型能记住几百章之前埋下的伏笔,并在后续分析中关联起来
- 效率革命:几分钟内完成人类需要数天甚至数周才能完成的文本梳理工作
接下来,我将带你从环境部署开始,一步步实现这个有趣的应用。
2. 快速部署与验证:让模型跑起来
2.1 环境准备与一键部署
首先,我们需要在CSDN星图镜像广场找到GLM-4-9B-Chat-1M的镜像。这个镜像已经预配置好了vLLM推理框架和Chainlit前端界面,大大简化了部署流程。
部署成功后,我们需要确认服务是否正常运行。打开WebShell,执行以下命令查看日志:
cat /root/workspace/llm.log
如果看到类似下面的输出,说明模型已经成功加载并准备好接收请求了:
INFO:__main__:Loading model from /root/autodl-tmp/glm-4-9b-chat-1m
INFO:__main__:Model loaded successfully
INFO:__main__:Starting vLLM engine...
INFO:__main__:vLLM engine started on port 8000
2.2 测试基础对话能力
模型部署好后,我们先做个简单的测试,确保一切正常。打开Chainlit前端界面,这是一个为对话式AI设计的Web界面,用起来很像ChatGPT。
尝试问一个简单的问题:“你好,请介绍一下你自己。”
如果模型正确响应,说明基础对话功能正常。接下来,我们就可以挑战更复杂的任务了。
3. 实战:200万字小说情节分析
现在进入正题。我们假设手头有一部200万字的小说文本(可以是TXT格式),想要让AI帮我们分析其中的情节发展和人物关系。
3.1 准备超长文本数据
首先,我们需要把小说文本准备好。这里有个小技巧:虽然模型支持1M上下文,但实际处理时,我们可以根据需求灵活控制输入长度。
# 读取小说文本文件
def load_novel_text(file_path):
with open(file_path, 'r', encoding='utf-8') as f:
text = f.read()
return text
# 如果文本过长,可以按章节分割
def split_by_chapters(text, max_chars_per_chunk=500000):
"""
将文本按大致均匀的大小分割,尽量保持章节完整性
"""
chunks = []
current_chunk = ""
# 这里假设章节以“第X章”开头
lines = text.split('\n')
for line in lines:
if len(current_chunk) + len(line) < max_chars_per_chunk:
current_chunk += line + '\n'
else:
chunks.append(current_chunk)
current_chunk = line + '\n'
if current_chunk:
chunks.append(current_chunk)
return chunks
# 使用示例
novel_text = load_novel_text("novel.txt")
chunks = split_by_chapters(novel_text)
print(f"文本被分割为 {len(chunks)} 个块")
3.2 情节脉络提取
现在,我们让AI从这200万字中提取主要的情节线。这里的关键是设计合适的提示词(prompt),引导模型关注我们关心的内容。
import requests
import json
def analyze_plot_structure(text_chunk, api_url="http://localhost:8000/v1/chat/completions"):
"""
分析文本块的情节结构
"""
prompt = f"""你是一位专业的文学分析师。请分析以下小说文本,提取主要的情节发展脉络。
要求:
1. 找出3-5条主要情节线
2. 每条情节线用一句话概括核心冲突
3. 标注每条线涉及的主要角色
4. 分析情节之间的关联性
小说文本:
{text_chunk[:100000]} # 控制输入长度,避免过长
请以JSON格式返回分析结果,包含以下字段:
- main_plots: 列表,每个元素包含title(情节标题)、summary(情节概要)、characters(涉及角色)、connections(与其他情节的关联)
"""
payload = {
"model": "glm-4-9b-chat-1m",
"messages": [
{"role": "user", "content": prompt}
],
"max_tokens": 2000,
"temperature": 0.3 # 较低的温度值让输出更稳定
}
response = requests.post(api_url, json=payload)
result = response.json()
return result["choices"][0]["message"]["content"]
# 对每个文本块进行分析
plot_analyses = []
for i, chunk in enumerate(chunks[:3]): # 先分析前3个块作为示例
print(f"正在分析第{i+1}个文本块...")
analysis = analyze_plot_structure(chunk)
plot_analyses.append(analysis)
print(f"第{i+1}块分析完成")
3.3 角色关系图谱生成
这是最有趣的部分——让AI从文本中自动识别角色关系,并生成结构化的关系数据。
def extract_character_relationships(text_chunk):
"""
从文本中提取角色关系
"""
prompt = f"""请从以下小说文本中提取所有重要角色及其相互关系。
要求:
1. 识别所有出现的重要角色(主角、重要配角)
2. 分析角色之间的关系类型:亲情、友情、爱情、敌对、师徒、同事等
3. 评估关系强度:强、中、弱
4. 提取关系发展的关键事件
请特别注意:
- 同一个人物的不同称呼要统一(如“张三”、“张先生”、“三爷”都指向同一人物)
- 关系可能随时间变化,请标注关系的变化点
小说文本:
{text_chunk[:80000]}
请以JSON格式返回,包含以下结构:
{{
"characters": [
{{
"name": "角色名",
"aliases": ["别名1", "别名2"],
"role": "角色定位(主角/配角/反派等)"
}}
],
"relationships": [
{{
"from": "角色A",
"to": "角色B",
"type": "关系类型",
"strength": "关系强度",
"evidence": "文本证据",
"chapter": "出现章节"
}}
]
}}
"""
payload = {
"model": "glm-4-9b-chat-1m",
"messages": [
{"role": "user", "content": prompt}
],
"max_tokens": 2500,
"temperature": 0.2 # 更低的温度确保关系提取的准确性
}
response = requests.post("http://localhost:8000/v1/chat/completions", json=payload)
result = response.json()
return json.loads(result["choices"][0]["message"]["content"])
# 提取角色关系
character_data = []
for i, chunk in enumerate(chunks[:2]):
print(f"正在从第{i+1}个文本块提取角色关系...")
relationships = extract_character_relationships(chunk)
character_data.append(relationships)
print(f"找到{len(relationships['characters'])}个角色,{len(relationships['relationships'])}条关系")
4. 可视化展示:让分析结果一目了然
分析得到的数据是结构化的,但还不够直观。我们可以用一些简单的可视化方法,让结果更加生动。
4.1 生成角色关系图
我们可以用NetworkX和Matplotlib来绘制角色关系网络图:
import networkx as nx
import matplotlib.pyplot as plt
from matplotlib import font_manager
def create_relationship_graph(character_data):
"""
创建角色关系网络图
"""
G = nx.Graph()
# 添加节点(角色)
for character in character_data['characters']:
G.add_node(character['name'],
role=character['role'],
aliases=character.get('aliases', []))
# 添加边(关系)
for rel in character_data['relationships']:
# 根据关系类型设置边的属性
edge_attrs = {
'type': rel['type'],
'strength': rel['strength'],
'label': f"{rel['type']}({rel['strength']})"
}
G.add_edge(rel['from'], rel['to'], **edge_attrs)
return G
def draw_relationship_graph(G, output_path="character_relationships.png"):
"""
绘制关系图
"""
plt.figure(figsize=(20, 16))
# 根据角色类型设置节点颜色
node_colors = []
for node in G.nodes():
role = G.nodes[node].get('role', 'unknown')
if role == '主角':
node_colors.append('red')
elif role == '重要配角':
node_colors.append('orange')
elif role == '反派':
node_colors.append('purple')
else:
node_colors.append('skyblue')
# 根据关系强度设置边的粗细
edge_weights = []
for u, v, data in G.edges(data=True):
strength = data.get('strength', '中')
if strength == '强':
edge_weights.append(3)
elif strength == '中':
edge_weights.append(2)
else:
edge_weights.append(1)
# 绘制网络图
pos = nx.spring_layout(G, k=2, iterations=50)
# 绘制节点
nx.draw_networkx_nodes(G, pos,
node_size=800,
node_color=node_colors,
alpha=0.9)
# 绘制边
nx.draw_networkx_edges(G, pos,
width=edge_weights,
alpha=0.5,
edge_color='gray')
# 绘制标签
nx.draw_networkx_labels(G, pos,
font_size=10,
font_family='SimHei')
# 添加图例
plt.title("小说角色关系图谱", fontsize=16, fontweight='bold')
# 保存图片
plt.tight_layout()
plt.savefig(output_path, dpi=300, bbox_inches='tight')
plt.show()
print(f"关系图已保存到: {output_path}")
# 使用示例
if character_data:
# 合并多个文本块的角色数据
merged_characters = []
merged_relationships = []
for data in character_data:
merged_characters.extend(data['characters'])
merged_relationships.extend(data['relationships'])
combined_data = {
'characters': merged_characters,
'relationships': merged_relationships
}
G = create_relationship_graph(combined_data)
draw_relationship_graph(G)
4.2 情节时间线可视化
除了角色关系,情节发展的时间线也很重要:
import plotly.graph_objects as go
from datetime import datetime, timedelta
def create_plot_timeline(plot_analyses):
"""
创建情节发展时间线
"""
fig = go.Figure()
# 假设每个文本块代表一段时间
time_points = []
plot_lines = {}
for i, analysis_str in enumerate(plot_analyses):
try:
analysis = json.loads(analysis_str)
time_point = f"第{i+1}部分"
time_points.append(time_point)
for plot in analysis.get('main_plots', []):
plot_title = plot['title']
if plot_title not in plot_lines:
plot_lines[plot_title] = []
# 用情节的复杂程度或重要性作为Y轴值
importance = len(plot.get('characters', [])) + len(plot.get('connections', []))
plot_lines[plot_title].append(importance)
except:
continue
# 为每条情节线添加轨迹
colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7']
for idx, (plot_title, values) in enumerate(plot_lines.items()):
if len(values) == len(time_points):
fig.add_trace(go.Scatter(
x=time_points,
y=values,
mode='lines+markers',
name=plot_title,
line=dict(color=colors[idx % len(colors)], width=3),
marker=dict(size=8)
))
fig.update_layout(
title="小说情节发展脉络",
xaxis_title="故事进展",
yaxis_title="情节复杂度/重要性",
hovermode='x unified',
template='plotly_white',
height=500
)
# 保存为HTML文件,方便交互查看
fig.write_html("plot_timeline.html")
print("情节时间线已保存为 plot_timeline.html")
return fig
# 生成时间线图
if plot_analyses:
timeline_fig = create_plot_timeline(plot_analyses)
5. 进阶技巧与优化建议
在实际使用中,你可能会遇到一些挑战。这里分享几个我总结的实用技巧:
5.1 处理超长文本的策略
虽然模型支持1M上下文,但实际使用时还是要讲究策略:
- 分层处理:先让模型阅读全文,提取大纲和主要角色;再针对特定章节进行深入分析
- 摘要链:对超长文本先进行分段摘要,然后用摘要作为上下文进行详细分析
- 增量分析:像人类读书一样,让模型“读完一章,分析一章”,然后累积知识
def incremental_analysis(chunks):
"""
增量式分析:模拟人类逐章阅读的过程
"""
accumulated_knowledge = ""
all_analyses = []
for i, chunk in enumerate(chunks):
print(f"正在阅读和分析第{i+1}章...")
prompt = f"""基于之前的知识和新的章节内容,请更新对小说的理解。
之前掌握的信息:
{accumulated_knowledge[:5000]} # 控制知识库大小
新的章节内容:
{chunk[:50000]}
请更新:
1. 新增的角色及其关系
2. 情节的新发展
3. 之前伏笔的揭示情况
4. 整体故事走向的调整
"""
# 调用模型进行分析
analysis = analyze_with_model(prompt)
all_analyses.append(analysis)
# 更新知识库(保留最重要的信息)
accumulated_knowledge = summarize_knowledge(accumulated_knowledge, analysis)
return all_analyses
5.2 提升分析准确性的方法
- 多次提问,交叉验证:对同一个问题用不同角度提问,比较答案的一致性
- 提供示例:在prompt中给出你期望的输出格式示例
- 分步骤引导:不要一次性要求太多分析,而是分步骤进行
- 设置检查点:让模型在分析过程中自我检查逻辑一致性
5.3 性能优化建议
- 批量处理:如果有多个分析任务,尽量批量发送请求
- 缓存结果:对相同的文本分析进行缓存,避免重复计算
- 异步处理:对于耗时较长的分析,使用异步请求避免阻塞
6. 实际应用场景拓展
这个技术不仅仅能用于小说分析,在很多实际场景中都有应用价值:
6.1 学术研究助手
- 分析整部古籍的脉络和思想体系
- 对比不同版本文献的差异
- 提取学术专著的核心观点和论证结构
6.2 企业知识管理
- 分析公司历年文档,构建知识图谱
- 从会议纪要中提取决策脉络和行动项
- 整理产品需求文档,追踪功能演进
6.3 内容创作支持
- 为编剧分析剧本结构和人物弧光
- 帮网文作者检查情节漏洞和角色一致性
- 辅助非虚构写作的资料整理和脉络梳理
6.4 教育应用
- 自动生成经典文学作品的导读和分析
- 为学生提供个性化的阅读辅助
- 帮助教师准备教学材料和讨论问题
7. 总结
通过今天的探索,我们看到了GLM-4-9B-Chat-1M在处理超长文本方面的强大能力。从部署模型到实际应用,从基础对话到复杂的文学分析,这个支持百万字上下文的模型为我们打开了一扇新的大门。
关键收获:
- 技术可行性:1M的上下文长度确实能处理整部小说的分析任务,保持信息的连贯性和完整性
- 实用价值:自动化的情节追踪和角色关系提取,能大幅提升文本分析的效率
- 易用性:配合Chainlit前端,即使不是专业开发者也能轻松使用
- 扩展性:这套方法可以轻松适配到其他长文本分析场景
给初学者的建议:
- 先从短文本开始练习,熟悉prompt设计技巧
- 多尝试不同的分析角度,找到最适合你需求的方法
- 不要追求一次完美,迭代优化往往效果更好
- 结合实际需求,让技术真正为你创造价值
长文本分析的世界才刚刚开启,随着模型能力的不断提升,我们能做的事情会越来越多。无论是文学研究、内容创作还是知识管理,这种“让AI读完整本书”的能力,都将成为我们理解和处理复杂信息的强大工具。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。
更多推荐

所有评论(0)