ChatGLM3-6B-128K长文本处理实战:一键部署与Python爬虫数据整合
ChatGLM3-6B-128K长文本处理实战:一键部署与Python爬虫数据整合
你是不是也遇到过这样的烦恼?辛辛苦苦用Python爬虫抓了一大堆网页数据,结果发现全是长篇大论的文章、报告、文档,看得眼花缭乱,根本不知道从哪开始分析。手动整理?几十上百页的内容,光是看完就得花一整天。用传统的文本处理工具?处理长文档时要么卡死,要么只能截取片段,重要的上下文信息全丢了。
我之前做市场调研时就深有体会,从十几个行业网站爬了几百份分析报告,加起来超过50万字。当时试了好几个模型,要么处理不了这么长的文本,要么效果差强人意,直到遇到了ChatGLM3-6B-128K。
这个模型最吸引我的地方就是它能一口气处理128K的上下文,换算下来大概是9万个汉字,相当于120页A4纸的内容。更重要的是,它部署起来特别简单,用Ollama基本上就是一行命令的事。今天我就来分享一下,怎么把ChatGLM3-6B-128K和Python爬虫结合起来,搭建一个自动化处理长文本数据的流程。
1. 为什么需要长文本处理能力?
在开始动手之前,咱们先聊聊为什么长文本处理这么重要。你可能觉得,不就是把文章变短一点吗?其实远不止这么简单。
想象一下这些场景:
- 市场调研:你需要分析竞争对手的几十份产品文档、技术白皮书、用户手册,每份都几十页
- 学术研究:要整理某个领域过去五年的所有重要论文,每篇论文都上万字
- 新闻监控:每天跟踪几十个新闻源,生成当日要闻摘要
- 法律文档:处理合同、协议、法规文件,这些文档通常结构复杂、篇幅很长
传统的处理方法要么是人工阅读(效率太低),要么是用规则抽取(不够智能),要么是用普通的大模型(上下文长度不够,会丢失重要信息)。
ChatGLM3-6B-128K的128K上下文长度意味着什么?我做了个简单的对比:
| 处理方式 | 最大处理长度 | 相当于 | 适用场景 |
|---|---|---|---|
| 普通ChatGLM3-6B | 约8K tokens | 6千汉字,8页A4纸 | 日常对话、短文分析 |
| ChatGLM3-6B-128K | 约128K tokens | 9万汉字,120页A4纸 | 长文档分析、多文档整合、深度研究 |
| 人工阅读 | 无限制但效率低 | - | 需要深度理解的关键文档 |
用大白话说就是:如果你要处理的文档基本都在8页以内,用普通版就够了;但如果经常要处理几十页甚至上百页的内容,那128K版本就是刚需。
2. 快速部署ChatGLM3-6B-128K
好了,理论说完了,咱们来点实际的。部署ChatGLM3-6B-128K其实特别简单,我用的是Ollama,这应该是最省事的方法了。
2.1 环境准备
首先确保你的机器满足基本要求:
- 内存:至少16GB(模型本身3.6GB,运行还需要一些内存)
- 显存:如果有GPU的话,6GB以上会快很多;没有GPU也能用CPU跑,就是慢点
- 系统:Linux、macOS、Windows都行,我是在Ubuntu上测试的
- 网络:能正常访问外网(下载模型需要)
2.2 一键安装Ollama
如果你的系统还没装Ollama,先装一下:
# Linux/macOS 安装命令
curl -fsSL https://ollama.com/install.sh | sh
# Windows 用户可以直接去官网下载安装包
# https://ollama.com/download
安装完成后,验证一下:
ollama --version
应该能看到版本号,比如 ollama version 0.1.xx。
2.3 拉取并运行ChatGLM3-6B-128K
这才是最爽的一步,真的就是一行命令:
ollama run chatglm3:6b
等等,你可能会问:不是说128K版本吗?怎么是chatglm3:6b?这里有个小细节,Ollama上的chatglm3:6b实际上就是128K版本的。我查了一下模型信息,确认它的上下文长度确实是131072(也就是128K)。
第一次运行会下载模型,大概3.6GB,取决于你的网速。下载完成后,会自动进入对话模式,你可以试试跟它聊天:
>>> 你好,请介绍一下你自己
如果能看到正常的回复,说明模型已经成功运行了。
2.4 验证长文本处理能力
光说能处理128K,咱们得验证一下。我写了个简单的测试脚本:
import requests
import json
def test_long_context():
# 构造一个超长的提示词
# 这里用重复的文本模拟长上下文,实际使用时会是真实的文档内容
long_text = "这是一段测试文本。" * 20000 # 大约10万字
prompt = f"""
请分析以下文本的主要内容,并提取关键信息:
{long_text}
请用简洁的语言总结文本的核心观点。
"""
# 通过Ollama的API调用
response = requests.post(
'http://localhost:11434/api/generate',
json={
'model': 'chatglm3:6b',
'prompt': prompt,
'stream': False
}
)
if response.status_code == 200:
result = response.json()
print("模型回复:", result['response'])
print("处理耗时:", result.get('total_duration', 'N/A'))
else:
print("请求失败:", response.text)
if __name__ == "__main__":
test_long_context()
运行这个脚本,如果模型能正常处理并返回总结,说明128K上下文确实生效了。我测试的时候,处理10万字的文本大概用了20多秒(在RTX 4090上)。
3. Python爬虫数据采集实战
模型准备好了,现在来看看数据从哪里来。我用的是Python爬虫,这里分享几个实用的技巧。
3.1 简单的网页内容抓取
先来个最基本的例子,用requests和BeautifulSoup:
import requests
from bs4 import BeautifulSoup
import time
import json
class SimpleWebCrawler:
def __init__(self):
self.headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}
def fetch_article(self, url):
"""抓取单篇文章"""
try:
response = requests.get(url, headers=self.headers, timeout=10)
response.raise_for_status()
response.encoding = response.apparent_encoding
soup = BeautifulSoup(response.text, 'html.parser')
# 移除脚本和样式
for script in soup(["script", "style"]):
script.decompose()
# 提取正文 - 这里需要根据目标网站调整选择器
# 常见的内容选择器
selectors = [
'article', '.article-content', '.post-content',
'#content', '.content', 'main'
]
content = None
for selector in selectors:
element = soup.select_one(selector)
if element:
content = element.get_text(strip=True, separator='\n')
break
# 如果没找到,取整个body
if not content:
content = soup.body.get_text(strip=True, separator='\n')
# 提取标题
title = soup.title.string if soup.title else "无标题"
return {
'url': url,
'title': title,
'content': content[:500000], # 限制长度,避免太长
'timestamp': time.strftime('%Y-%m-%d %H:%M:%S')
}
except Exception as e:
print(f"抓取失败 {url}: {e}")
return None
def batch_fetch(self, urls, delay=1):
"""批量抓取多篇文章"""
results = []
for url in urls:
print(f"正在抓取: {url}")
article = self.fetch_article(url)
if article:
results.append(article)
print(f"成功抓取: {article['title'][:50]}...")
time.sleep(delay) # 礼貌性延迟,避免被封
return results
def save_to_file(self, articles, filename='crawled_data.jsonl'):
"""保存为JSONL格式,方便后续处理"""
with open(filename, 'w', encoding='utf-8') as f:
for article in articles:
f.write(json.dumps(article, ensure_ascii=False) + '\n')
print(f"已保存 {len(articles)} 篇文章到 {filename}")
# 使用示例
if __name__ == "__main__":
crawler = SimpleWebCrawler()
# 示例URL列表 - 实际使用时替换成你的目标网站
urls = [
'https://example.com/article1',
'https://example.com/article2',
# ... 更多URL
]
articles = crawler.batch_fetch(urls)
crawler.save_to_file(articles)
3.2 处理动态加载的网站
现在很多网站用JavaScript动态加载内容,这时候需要用Selenium:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
class DynamicContentCrawler:
def __init__(self):
options = webdriver.ChromeOptions()
options.add_argument('--headless') # 无头模式,不显示浏览器窗口
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')
self.driver = webdriver.Chrome(options=options)
self.wait = WebDriverWait(self.driver, 10)
def fetch_dynamic_content(self, url):
"""抓取动态加载的内容"""
try:
self.driver.get(url)
time.sleep(2) # 等待页面加载
# 等待主要内容加载
self.wait.until(
EC.presence_of_element_located((By.TAG_NAME, "article"))
)
# 滚动页面加载更多内容(如果需要)
self.driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(1)
# 提取内容
article = self.driver.find_element(By.TAG_NAME, "article")
content = article.text
return {
'url': url,
'content': content,
'title': self.driver.title
}
except Exception as e:
print(f"动态抓取失败 {url}: {e}")
return None
def close(self):
self.driver.quit()
# 使用示例
crawler = DynamicContentCrawler()
content = crawler.fetch_dynamic_content('https://example.com/dynamic-article')
crawler.close()
3.3 爬虫注意事项
这里提醒几个重要的点:
- 遵守robots.txt:抓取前检查目标网站的
robots.txt,尊重网站的爬虫规则 - 设置延迟:不要在短时间内发送大量请求,加个
time.sleep(),做个有礼貌的爬虫 - 处理异常:网络可能不稳定,网站可能改版,代码里要做好异常处理
- 数据去重:同样的内容可能抓多次,记得去重
- 存储策略:及时保存到文件或数据库,避免程序崩溃数据丢失
我一般会这样组织爬取的数据:
data/
├── raw/ # 原始抓取数据
├── processed/ # 清洗后的数据
├── summaries/ # 模型生成的结果
└── logs/ # 运行日志
4. 用ChatGLM3处理爬虫数据
数据抓回来了,现在轮到ChatGLM3-6B-128K大显身手了。我设计了一个完整的处理流程。
4.1 数据预处理
首先,原始数据需要清洗一下:
import re
import json
class DataPreprocessor:
def __init__(self):
# 常见的中文停用词(简化版)
self.stop_words = set([
'的', '了', '在', '是', '我', '有', '和', '就',
'不', '人', '都', '一', '一个', '上', '也', '很',
'到', '说', '要', '去', '你', '会', '着', '没有',
'看', '好', '自己', '这', '那', '他', '她', '它'
])
def clean_text(self, text):
"""清洗文本"""
if not text:
return ""
# 移除HTML标签
text = re.sub(r'<[^>]+>', '', text)
# 移除特殊字符和多余空白
text = re.sub(r'[^\w\u4e00-\u9fff\s.,!?;:,。!?;:]', '', text)
text = re.sub(r'\s+', ' ', text).strip()
# 简单分词(按空格和标点)
words = re.findall(r'[\u4e00-\u9fff]+|[a-zA-Z]+|\d+', text)
# 移除停用词
filtered_words = [w for w in words if w not in self.stop_words]
return ' '.join(filtered_words)
def split_long_text(self, text, max_length=100000):
"""如果文本太长,分割成多个片段"""
# 128K tokens大约对应9万汉字,这里留点余量
if len(text) <= max_length:
return [text]
# 尝试按段落分割
paragraphs = text.split('\n\n')
chunks = []
current_chunk = []
current_length = 0
for para in paragraphs:
para_length = len(para)
if current_length + para_length > max_length and current_chunk:
# 当前块已满,保存并开始新块
chunks.append('\n\n'.join(current_chunk))
current_chunk = [para]
current_length = para_length
else:
current_chunk.append(para)
current_length += para_length
if current_chunk:
chunks.append('\n\n'.join(current_chunk))
return chunks
def process_file(self, input_file, output_file):
"""处理整个文件"""
processed_articles = []
with open(input_file, 'r', encoding='utf-8') as f:
for line in f:
article = json.loads(line.strip())
# 清洗内容
cleaned_content = self.clean_text(article.get('content', ''))
# 分割长文本
content_chunks = self.split_long_text(cleaned_content)
processed_article = {
'original_title': article.get('title', ''),
'url': article.get('url', ''),
'content_chunks': content_chunks,
'chunk_count': len(content_chunks),
'total_length': len(cleaned_content)
}
processed_articles.append(processed_article)
# 保存处理后的数据
with open(output_file, 'w', encoding='utf-8') as f:
json.dump(processed_articles, f, ensure_ascii=False, indent=2)
print(f"处理完成,共 {len(processed_articles)} 篇文章")
return processed_articles
4.2 调用ChatGLM3进行文本分析
现在是最核心的部分——用ChatGLM3分析文本:
import requests
import json
import time
from typing import List, Dict
class ChatGLMAnalyzer:
def __init__(self, model_name="chatglm3:6b", base_url="http://localhost:11434"):
self.model_name = model_name
self.base_url = base_url
self.api_url = f"{base_url}/api/generate"
def analyze_single_chunk(self, text_chunk, analysis_type="summary"):
"""分析单个文本块"""
# 根据分析类型构造不同的提示词
prompts = {
"summary": """
请仔细阅读以下文本,然后:
1. 用一段话概括核心内容(100字以内)
2. 提取3-5个关键要点
3. 判断文本的主要类型(如技术文档、新闻报道、学术论文等)
文本内容:
{text}
请按照上述要求回答。
""",
"qa": """
基于以下文本内容,请回答这个问题:{question}
相关文本:
{text}
请确保回答基于文本内容,不要编造信息。
""",
"extract": """
请从以下文本中提取指定信息:
需要提取的信息类型:{info_type}
文本内容:
{text}
请以JSON格式返回提取结果。
"""
}
if analysis_type not in prompts:
analysis_type = "summary"
prompt_template = prompts[analysis_type]
if analysis_type == "summary":
prompt = prompt_template.format(text=text_chunk)
elif analysis_type == "qa":
# 这里需要传入question参数
prompt = prompt_template.format(question="[问题]", text=text_chunk)
else:
prompt = prompt_template.format(info_type="关键信息", text=text_chunk)
try:
response = requests.post(
self.api_url,
json={
'model': self.model_name,
'prompt': prompt,
'stream': False,
'options': {
'temperature': 0.3, # 较低的温度,让输出更稳定
'num_predict': 1000 # 最大生成长度
}
},
timeout=60 # 长文本处理可能需要更长时间
)
if response.status_code == 200:
result = response.json()
return {
'success': True,
'response': result['response'],
'processing_time': result.get('total_duration', 0)
}
else:
return {
'success': False,
'error': f"API请求失败: {response.status_code}",
'response': None
}
except requests.exceptions.Timeout:
return {
'success': False,
'error': "请求超时,文本可能太长",
'response': None
}
except Exception as e:
return {
'success': False,
'error': str(e),
'response': None
}
def analyze_long_document(self, content_chunks: List[str], analysis_type="summary"):
"""分析长文档(可能被分成多个块)"""
all_results = []
for i, chunk in enumerate(content_chunks):
print(f"正在处理第 {i+1}/{len(content_chunks)} 个文本块...")
result = self.analyze_single_chunk(chunk, analysis_type)
if result['success']:
all_results.append({
'chunk_index': i,
'content_preview': chunk[:200] + "...",
'analysis': result['response'],
'processing_time': result['processing_time']
})
print(f" 第 {i+1} 块处理成功,耗时 {result['processing_time']/1e9:.2f} 秒")
else:
print(f" 第 {i+1} 块处理失败: {result['error']}")
all_results.append({
'chunk_index': i,
'error': result['error'],
'analysis': None
})
# 避免请求过于频繁
time.sleep(0.5)
return all_results
def synthesize_results(self, chunk_results: List[Dict], original_title=""):
"""综合多个块的分析结果"""
if not chunk_results:
return "无分析结果"
# 如果只有一个块,直接返回
if len(chunk_results) == 1:
return chunk_results[0]['analysis']
# 多个块需要综合
synthesis_prompt = """
我有一篇长文档,被分成了多个部分进行分析。现在需要你帮我综合这些分析结果,形成对整篇文档的完整理解。
文档标题:{title}
文档共分为 {chunk_count} 个部分。
各部分分析结果如下:
{chunk_analyses}
请基于以上各部分的分析,为整篇文档生成:
1. 一个完整的摘要(200字以内)
2. 文档的核心论点或主要发现
3. 文档的结构特点
4. 如果有矛盾或不一致的地方,请指出
请用清晰的结构回答。
"""
# 准备各部分分析结果
chunk_analyses_text = ""
for i, result in enumerate(chunk_results):
if result.get('analysis'):
chunk_analyses_text += f"\n--- 第 {i+1} 部分 ---\n"
chunk_analyses_text += result['analysis'] + "\n"
prompt = synthesis_prompt.format(
title=original_title,
chunk_count=len(chunk_results),
chunk_analyses=chunk_analyses_text
)
# 调用模型进行综合
final_result = self.analyze_single_chunk(prompt, "summary")
if final_result['success']:
return final_result['response']
else:
return "综合分析失败:" + final_result.get('error', '未知错误')
4.3 完整的处理流程
把上面的组件组合起来,形成一个完整的处理管道:
import os
from datetime import datetime
class LongTextProcessingPipeline:
def __init__(self):
self.crawler = SimpleWebCrawler()
self.preprocessor = DataPreprocessor()
self.analyzer = ChatGLMAnalyzer()
def run_pipeline(self, urls, output_dir="output"):
"""运行完整流程"""
# 创建输出目录
os.makedirs(output_dir, exist_ok=True)
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
# 1. 爬取数据
print("步骤1: 爬取网页数据...")
raw_articles = self.crawler.batch_fetch(urls, delay=2)
raw_file = os.path.join(output_dir, f"raw_{timestamp}.jsonl")
self.crawler.save_to_file(raw_articles, raw_file)
# 2. 预处理数据
print("\n步骤2: 预处理文本数据...")
processed_file = os.path.join(output_dir, f"processed_{timestamp}.json")
processed_articles = self.preprocessor.process_file(raw_file, processed_file)
# 3. 分析数据
print("\n步骤3: 使用ChatGLM3分析文本...")
analysis_results = []
for i, article in enumerate(processed_articles):
print(f"\n分析文章 {i+1}/{len(processed_articles)}: {article['original_title'][:50]}...")
if article['content_chunks']:
# 分析每个文本块
chunk_results = self.analyzer.analyze_long_document(
article['content_chunks'],
analysis_type="summary"
)
# 综合结果
if any(r.get('analysis') for r in chunk_results):
synthesis = self.analyzer.synthesize_results(
chunk_results,
original_title=article['original_title']
)
else:
synthesis = "所有块分析失败"
analysis_results.append({
'title': article['original_title'],
'url': article['url'],
'chunk_count': article['chunk_count'],
'total_length': article['total_length'],
'chunk_analyses': chunk_results,
'final_summary': synthesis
})
# 保存中间结果
temp_file = os.path.join(output_dir, f"analysis_temp_{timestamp}.json")
with open(temp_file, 'w', encoding='utf-8') as f:
json.dump(analysis_results, f, ensure_ascii=False, indent=2)
# 4. 保存最终结果
print("\n步骤4: 保存分析结果...")
final_file = os.path.join(output_dir, f"final_analysis_{timestamp}.json")
with open(final_file, 'w', encoding='utf-8') as f:
json.dump({
'pipeline_run_time': timestamp,
'total_articles': len(analysis_results),
'articles': analysis_results
}, f, ensure_ascii=False, indent=2)
# 5. 生成报告摘要
print("\n步骤5: 生成总体报告...")
self.generate_report(analysis_results, output_dir, timestamp)
print(f"\n 流程完成!结果保存在 {output_dir}/")
return final_file
def generate_report(self, analysis_results, output_dir, timestamp):
"""生成总体报告"""
report_file = os.path.join(output_dir, f"report_{timestamp}.txt")
with open(report_file, 'w', encoding='utf-8') as f:
f.write("=" * 60 + "\n")
f.write("长文本处理分析报告\n")
f.write("=" * 60 + "\n\n")
f.write(f"报告生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
f.write(f"分析文章总数: {len(analysis_results)}\n\n")
total_length = sum(a['total_length'] for a in analysis_results)
f.write(f"处理文本总量: {total_length:,} 字符\n")
successful_articles = sum(1 for a in analysis_results if a['final_summary'] and "失败" not in a['final_summary'])
f.write(f"成功分析文章: {successful_articles}/{len(analysis_results)}\n\n")
f.write("-" * 60 + "\n")
f.write("各文章分析摘要\n")
f.write("-" * 60 + "\n\n")
for i, article in enumerate(analysis_results):
f.write(f"文章 {i+1}: {article['title'][:50]}...\n")
f.write(f"URL: {article['url']}\n")
f.write(f"长度: {article['total_length']:,} 字符, 分块: {article['chunk_count']}\n")
if article['final_summary'] and "失败" not in article['final_summary']:
f.write("摘要:\n")
# 取摘要的前3行
summary_lines = article['final_summary'].split('\n')[:3]
for line in summary_lines:
f.write(f" {line}\n")
else:
f.write("状态: 分析失败\n")
f.write("\n" + "-" * 40 + "\n\n")
print(f"报告已生成: {report_file}")
# 使用示例
if __name__ == "__main__":
# 配置要爬取的URL
target_urls = [
# 这里替换成你的目标URL
# 'https://example.com/long-article-1',
# 'https://example.com/long-article-2',
]
# 运行完整流程
pipeline = LongTextProcessingPipeline()
# 如果URL列表为空,使用测试模式
if not target_urls:
print("未提供URL,运行测试模式...")
# 这里可以添加测试逻辑
else:
result_file = pipeline.run_pipeline(
urls=target_urls,
output_dir="./processing_results"
)
print(f"最终结果文件: {result_file}")
5. 实际应用案例
光讲代码可能有点抽象,我分享一个实际的应用案例,这样你能更清楚怎么用这套东西。
5.1 案例:行业竞品分析
假设你在一家科技公司,需要分析10个主要竞争对手的产品文档和技术白皮书。每份文档都50-100页,全是技术细节。
传统做法:
- 安排2-3个员工专门阅读
- 每人每天能看完1-2份文档
- 需要手动整理要点、做对比表格
- 整个过程至少一周,还可能漏掉重要信息
用我们的方案:
- 数据收集:写爬虫抓取竞争对手官网的文档(约10个网站,每个网站3-5份文档)
- 自动处理:运行上面的管道,一晚上就能处理完所有文档
- 结果输出:
- 每份文档的详细摘要
- 技术要点对比表格
- 发现竞争对手的共同趋势和差异化点
这是处理后的输出示例:
# 生成的对比分析(简化版)
competitor_analysis = {
"total_documents_processed": 42,
"total_text_length": "约150万字",
"key_findings": [
{
"topic": "云原生架构",
"mentioned_by": ["公司A", "公司B", "公司C", "公司D"],
"common_features": ["容器化", "微服务", "DevOps"],
"differentiation": {
"公司A": "强调安全隔离",
"公司B": "注重自动化运维",
"公司C": "主打混合云支持"
}
},
{
"topic": "AI集成",
"mentioned_by": ["公司A", "公司E", "公司F"],
"common_features": ["机器学习平台", "模型部署"],
"differentiation": {
"公司A": "提供预训练行业模型",
"公司E": "强调低代码AI开发",
"公司F": "专注实时推理优化"
}
}
],
"recommendations": [
"建议加强在云原生安全方面的宣传",
"考虑增加低代码AI开发功能",
"需要更突出的差异化定位"
]
}
5.2 案例:学术文献综述
如果你是研究生,需要写文献综述,要阅读上百篇论文。
传统做法:
- 下载PDF,手动阅读
- 做笔记,整理引用
- 写综述时反复翻看笔记
- 容易遗漏重要论文或观点
用我们的方案:
- 批量下载:从学术网站批量下载论文(注意版权)
- PDF转文本:用工具把PDF转成纯文本
- 智能分析:用ChatGLM3提取每篇论文的核心贡献、方法、结论
- 自动综述:让模型帮你写初步的文献综述草稿
6. 性能优化与实用技巧
在实际使用中,我总结了一些优化技巧,能让整个流程跑得更顺畅。
6.1 处理速度优化
ChatGLM3-6B-128K处理长文本确实需要时间,特别是没有GPU的情况下。这些方法可以帮你提速:
class PerformanceOptimizer:
@staticmethod
def optimize_processing(config):
"""根据硬件配置优化处理参数"""
optimizations = {
"high_end_gpu": { # RTX 4090等高端GPU
"batch_size": 4, # 可以尝试批量处理
"max_tokens": 32000, # 每次处理的最大token数
"temperature": 0.3,
"num_predict": 1500
},
"mid_range_gpu": { # RTX 3060等中端GPU
"batch_size": 2,
"max_tokens": 16000,
"temperature": 0.3,
"num_predict": 1000
},
"cpu_only": { # 纯CPU环境
"batch_size": 1, # 不要批量处理
"max_tokens": 8000, # 减少每次处理量
"temperature": 0.2, # 更低温度,减少重复生成
"num_predict": 500 # 生成更短的回复
}
}
# 自动检测配置
import torch
if torch.cuda.is_available():
gpu_memory = torch.cuda.get_device_properties(0).total_memory / 1e9 # GB
if gpu_memory >= 16:
return optimizations["high_end_gpu"]
else:
return optimizations["mid_range_gpu"]
else:
return optimizations["cpu_only"]
@staticmethod
def parallel_process_chunks(chunks, analyzer, max_workers=2):
"""并行处理多个文本块(谨慎使用)"""
from concurrent.futures import ThreadPoolExecutor
results = []
with ThreadPoolExecutor(max_workers=max_workers) as executor:
# 提交任务
future_to_chunk = {
executor.submit(analyzer.analyze_single_chunk, chunk): i
for i, chunk in enumerate(chunks)
}
# 收集结果
for future in concurrent.futures.as_completed(future_to_chunk):
chunk_index = future_to_chunk[future]
try:
result = future.result()
results.append((chunk_index, result))
except Exception as e:
print(f"块 {chunk_index} 处理失败: {e}")
results.append((chunk_index, {'success': False, 'error': str(e)}))
# 按原始顺序排序
results.sort(key=lambda x: x[0])
return [r[1] for r in results]
6.2 内存管理
处理大量长文本时,内存管理很重要:
class MemoryManager:
def __init__(self, max_memory_usage=0.8):
self.max_memory_usage = max_memory_usage
def check_memory(self):
"""检查内存使用情况"""
import psutil
memory = psutil.virtual_memory()
return {
'total': memory.total,
'available': memory.available,
'percent': memory.percent,
'used': memory.used
}
def should_pause_processing(self):
"""判断是否需要暂停处理"""
memory_info = self.check_memory()
if memory_info['percent'] > self.max_memory_usage * 100:
return True
return False
def cleanup_memory(self):
"""清理内存"""
import gc
gc.collect()
# 如果有GPU,清理GPU缓存
try:
import torch
if torch.cuda.is_available():
torch.cuda.empty_cache()
torch.cuda.ipc_collect()
except:
pass
def process_with_memory_control(self, data_chunks, process_func):
"""带内存控制的数据处理"""
results = []
for i, chunk in enumerate(data_chunks):
# 检查内存
if self.should_pause_processing():
print(f"内存使用过高,暂停处理...")
self.cleanup_memory()
import time
time.sleep(5)
print(f"处理块 {i+1}/{len(data_chunks)}")
result = process_func(chunk)
results.append(result)
# 定期清理
if i % 10 == 0:
self.cleanup_memory()
return results
6.3 错误处理与重试
网络请求可能失败,模型可能出错,好的错误处理能让流程更稳定:
class RobustProcessor:
def __init__(self, max_retries=3, retry_delay=2):
self.max_retries = max_retries
self.retry_delay = retry_delay
def retry_on_failure(self, func, *args, **kwargs):
"""失败重试装饰器"""
import time
for attempt in range(self.max_retries):
try:
return func(*args, **kwargs)
except Exception as e:
if attempt == self.max_retries - 1:
raise e
print(f"尝试 {attempt + 1} 失败: {e}, {self.retry_delay}秒后重试...")
time.sleep(self.retry_delay)
def process_with_retry(self, analyzer, text_chunk, analysis_type="summary"):
"""带重试的处理"""
def process():
return analyzer.analyze_single_chunk(text_chunk, analysis_type)
result = self.retry_on_failure(process)
# 如果还是失败,尝试简化请求
if not result['success'] and len(text_chunk) > 10000:
print("长文本处理失败,尝试缩短文本...")
simplified_chunk = text_chunk[:5000] + "\n[文本过长,已截断]"
result = analyzer.analyze_single_chunk(simplified_chunk, analysis_type)
return result
7. 总结与建议
折腾了这么一大套,从爬虫抓数据到用ChatGLM3分析长文本,我觉得最关键的是找到适合自己需求的平衡点。ChatGLM3-6B-128K的长文本处理能力确实很强,但也不是万能的。
用下来的感受是,对于技术文档、研究报告、长篇文章这类需要理解上下文关系的文本,这个组合效果很好。它能抓住文章的逻辑脉络,提取的关键点也比较准确。但对于特别专业或者需要深度推理的内容,可能还需要人工复核一下。
部署方面,Ollama确实让事情变简单了,一行命令就能跑起来。如果你的数据量不大,用CPU也能凑合,就是慢点。有GPU的话体验会好很多,特别是处理几十上百页的文档时。
爬虫部分要注意合规性,别给人家网站造成压力。我一般会设置比较长的延迟,晚上跑批量任务,一次性别抓太多。
这套流程最适合的场景是那些需要处理大量长文本,但又不想完全依赖人工的场合。比如市场调研、文献整理、竞品分析这些。它能帮你快速从海量文本里提取出有价值的信息,节省大量时间。
如果你刚开始尝试,建议从小规模开始,先处理几篇文章看看效果,熟悉了整个流程再扩大规模。遇到问题也别急,长文本处理本来就有挑战性,多调试几次就好了。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。
更多推荐

所有评论(0)