大模型应用班-第2课 DeepSeek使用与提示词工程课程重点 学习ollama 安装 用deepseek-r1:1.5b 分析PDF 内容
DeepSeek使用与提示词工程课程重点
Homework:ollama 安装 用deepseek-r1:1.5b 分析PDF 内容
python 代码建构:
1.小模型 1.5b 可以在 笔记本上快速执行
2.分析结果还不错
3. 重点是提示词 prompt 的写法
一、DeepSeek模型创新与特点
1. DeepSeek-V3模型特点
- 采用MoE架构(61个专家模块),总参数量671B但仅激活37B参数
- 引入MLA(Multi-Head Latent Attention)注意力机制,显著减小KV缓存
- 使用混合精度框架(FP8)降低训练计算量
- 在主流榜单中与顶级闭源模型性能相当
2. DeepSeek-R1模型突破
- 基于V3模型通过GRPO强化学习训练
- 思维链长度可达数万字,支持复杂推理
- 性能对标OpenAI o1模型
- 提供API调用(deepseek-reasoner)
二、模型部署与使用
1. 私有化部署选项
模型类型 | 参数量 | 显存需求 | 适用场景 |
---|---|---|---|
1.5B-14B | 小模型 | 1-12GB | 轻量级任务 |
32B | 中模型 | 24-48GB | 专业领域 |
70B | 大模型 | 96-128GB | 高精度任务 |
671B | 满血版 | 496GB | AGI研究 |
2. 部署方式
Ollama部署:支持macOS/Linux/Windows
ollama pull deepseek-r1:1.5b ollama run deepseek-r1:1.5b
vLLM高速推理框架: 公司使用
vllm serve deepseek-r1-distill-qwen-32b --tensor-parallel-size 2
三、提示词工程核心原则
1. 提示词组成要素(重要性排序)
- 任务:明确动词开头的目标
- 上下文:提供背景信息
- 示例:展示期望输出格式
- 角色:指定AI扮演的身份
- 格式:定义输出结构
- 语气:设定回答风格
2. 通用模型vs推理模型提示策略
模型类型 | 提示特点 | 适用场景 |
---|---|---|
通用模型 | 需要分步引导,依赖Few-shot示例 | 创意写作、常规问答 |
推理模型 | 简洁指令,信任内化能力 | 数学、编程等逻辑任务 |
四、Prompt实战技巧
1. 核心技巧
限制输出格式:如JSON结构化返回
"以JSON格式输出包含名称、价格、流量的套餐信息"
使用分隔符:清晰区分输入部分
'''请总结以下三个引号内的文本'''
CoT思维链:分步解决复杂问题
"请按步骤计算:1.加1000 2.减500 3.乘1.2"
2. 优化方法
- 迭代测试:根据输出持续调整Prompt
- 角色扮演:明确AI身份(如"你是一名专业客服")
- 示例引导:提供输入输出对示范
五、典型应用案例
1. 小球碰撞模拟
- 使用DeepSeek-R1生成HTML/JavaScript代码
- 通过多次交互优化物理效果
- 最终实现包含重力、弹力等参数的完整模拟
2. 客服场景Prompt优化
"""
你是一名电信客服"小瓜",需:
1. 保持礼貌官方口吻
2. 准确提及套餐名称、价格、流量
3. 不可使用网络用语
已知套餐:
- 经济套餐:50元/10G
- 畅游套餐:180元/100G
"""
Ollama 运用代码
流程说明
PDF解析阶段
1. 代码功能概述
该代码实现了一个课程大纲分析系统,主要功能包括:
2.2 学习路径生成
2.3 输出处理
3. 关键技术点
4. 扩展应用场景
5. 改进建议
- PDF文本提取:使用
pdfplumber
库解析PDF文件,提取文本内容和章节结构 - 章节识别:通过正则表达式匹配多级标题(如"第X章"、"1.1"等格式)
- 学习路径生成:调用DeepSeek-R1模型(通过Ollama API)生成结构化学习建议
- 结果输出:
2. 核心模块解析
2.1 PDF解析与章节识别
- 文本提取:
使用pdfplumber.open()
逐页读取PDF,通过extract_text()
获取文本内容,并标注页码信息。 - 标题识别逻辑:
- 正则匹配多级标题(如
r'^第[一二三四五六七八九十\d]+章'
匹配中文章节) - 辅助规则:全大写文本、含"学习"/"知识"等关键词的短文本也被视为标题
- 层级判定:
- 一级标题:
第X章
或1. 标题
- 二级标题:
1.1 标题
或一、标题
- 三级标题:
1.1.1 标题
- 一级标题:
- 正则匹配多级标题(如
- 模型交互:
- 构建结构化提示词,包含章节树状结构和课纲前8000字符
- 调用DeepSeek-R1时启用
temperature=0.2
和top_p=0.9
,平衡创造性与稳定性 - 响应解析优先提取JSON块(兼容模型可能附加的解释文本)
- 错误处理:
- JSON解码失败时保留原始响应
- 捕获API超时等异常
- 控制台展示:
格式化输出学习阶段、核心概念、练习顺序等,使用符号图标(如📖
、🎯
)增强可读性 - JSON持久化:
按时间戳生成文件名,确保ASCII转义关闭(ensure_ascii=False
)以支持中文 PDF解析优化
- 混合正则规则与启发式判断,提升标题识别准确率
- 记录页码+行号,便于人工校验
大模型工程化应用
- 两阶段生成:先提取章节结构,再填充细节(如学习目标、练习类型)
- 通过
num_predict=2000
确保长文生成完整性
结构化输出设计
{"learning_stages": [{"stage_number": 1,"key_concepts": ["核心概念1", "核心概念2"],"practice_order": ["练习类型1", "练习类型2"]}] }
字段覆盖教学设计的核心要素(时间预估、预习要求等)
- 教育自动化:适配在线教育平台的课程规划自动化
- 文档分析:扩展支持EPUB、Word等格式(需调整解析逻辑)
- 多模型支持:替换Ollama接口为其他LLM(如GPT-4)
- 性能优化
- 使用多线程处理PDF分页解析(注意
pdfplumber
的线程安全性) - 缓存模型响应,减少重复请求
- 使用多线程处理PDF分页解析(注意
- 错误恢复
- 添加PDF解析失败时的备用文本提取方案(如
PyMuPDF
)
- 添加PDF解析失败时的备用文本提取方案(如
- 交互增强
- 支持用户手动修正误识别的章节标题
- 支持控制台格式化展示和JSON文件保存
6.完整代码
try:import pdfplumber
except ImportError:print("❌ 请安装pdfplumber: pip install pdfplumber")exit(1)import ollama
from typing import List, Dict, Tuple
import re
import json
import os
from datetime import datetimeclass SyllabusAnalyzer:def __init__(self, model_name="deepseek-r1:1.5b"):self.model_name = model_namedef extract_pdf_content(self, pdf_path: str) -> Tuple[str, List[Dict]]:"""提取PDF内容并识别章节结构"""if not os.path.exists(pdf_path):raise FileNotFoundError(f"PDF文件不存在: {pdf_path}")full_text = ""sections = []with pdfplumber.open(pdf_path) as pdf:for page_num, page in enumerate(pdf.pages):# 提取页面文本text = page.extract_text()if text:full_text += f"\n=== 第{page_num+1}页 ===\n{text}\n"# 按行分析文本,识别章节标题lines = text.split('\n')for line_num, line in enumerate(lines):clean_line = line.strip()if clean_line and self._is_section_title(clean_line):level = self._determine_section_level(clean_line)sections.append({"title": clean_line,"level": level,"page": page_num + 1,"line": line_num + 1})return full_text, sectionsdef _is_section_title(self, text: str) -> bool:"""判断是否为章节标题"""# 匹配各种章节标题格式patterns = [r'^第[一二三四五六七八九十\d]+章', # 第X章r'^第[一二三四五六七八九十\d]+节', # 第X节r'^\d+\.\s+.+', # 1. 标题r'^\d+\.\d+\s+.+', # 1.1 标题r'^[一二三四五六七八九十]+、', # 一、标题r'^([一二三四五六七八九十\d]+)', # (一)标题]for pattern in patterns:if re.match(pattern, text):return True# 检查是否为全大写标题或特殊格式return len(text) < 50 and (text.isupper() or '学习' in text or '知识' in text)def _determine_section_level(self, text: str) -> int:"""确定章节层级"""if re.match(r'^第[一二三四五六七八九十\d]+章', text):return 1elif re.match(r'^\d+\.\s+', text):return 1elif re.match(r'^\d+\.\d+\s+', text):return 2elif re.match(r'^\d+\.\d+\.\d+\s+', text):return 3else:return 2def generate_learning_path(self, pdf_text: str, sections: List[Dict]) -> Dict:"""使用deepseek-r1模型生成学习路径"""# 构建章节结构section_structure = self._build_section_structure(sections)# 构建详细的提示词prompt = self._build_analysis_prompt(section_structure, pdf_text)try:response = ollama.chat(model=self.model_name,messages=[{"role": "user", "content": prompt}],options={"temperature": 0.2,"top_p": 0.9,"num_predict": 2000})# 尝试解析JSON响应content = response['message']['content']# 提取JSON部分(如果响应包含其他文本)json_match = re.search(r'\{.*\}', content, re.DOTALL)if json_match:json_str = json_match.group()return json.loads(json_str)else:# 如果没有找到JSON,尝试直接解析return json.loads(content)except json.JSONDecodeError as e:return {"error": f"JSON解析失败: {str(e)}","raw_response": response['message']['content']}except Exception as e:return {"error": f"生成学习路径时出错: {str(e)}","raw_response": str(e)}def _build_section_structure(self, sections: List[Dict]) -> str:"""构建章节结构字符串"""structure_lines = []for i, section in enumerate(sections[:30]): # 限制章节数量indent = " " * (section['level'] - 1)structure_lines.append(f"{indent}{section['title']} (第{section['page']}页)")return "\n".join(structure_lines)def _build_analysis_prompt(self, section_structure: str, pdf_text: str) -> str:"""构建分析提示词"""return f"""你是一名专业的教学设计师和课程规划专家。请根据以下课纲内容,设计一份详细的学习路径指南。## 课纲章节结构:
{section_structure}## 分析要求:
1. 将整个课程合理划分为3-5个学习阶段
2. 每个阶段建议学习2-4个章节
3. 为每个阶段标注建议学习时长(以小时为单位)
4. 明确指出每个阶段需要预习的知识点
5. 推荐每个阶段的练习顺序和类型
6. 提取每个章节的核心知识点(3-5个)## 输出格式(严格按照JSON格式):
{{"course_title": "课程名称","total_estimated_hours": 总学习时长,"learning_stages": [{{"stage_number": 1,"stage_name": "阶段名称","chapters": ["章节1", "章节2", "章节3"],"suggested_hours": 学习时长数字,"prerequisites": ["预习知识点1", "预习知识点2"],"key_concepts": ["核心概念1", "核心概念2", "核心概念3"],"practice_order": ["练习类型1", "练习类型2", "练习类型3"],"learning_objectives": ["学习目标1", "学习目标2"]}}],"study_tips": ["学习建议1", "学习建议2", "学习建议3"]
}}## 课纲内容:
{pdf_text[:8000]}请严格按照上述JSON格式输出,确保所有字段都包含有意义的内容。"""def save_results(self, learning_path: Dict, output_file: str = None):"""保存分析结果到文件"""if output_file is None:timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")output_file = f"learning_path_{timestamp}.json"with open(output_file, 'w', encoding='utf-8') as f:json.dump(learning_path, f, ensure_ascii=False, indent=2)print(f"学习路径已保存到: {output_file}")def display_learning_path(self, learning_path: Dict):"""格式化显示学习路径"""if "error" in learning_path:print("❌ 生成学习路径时出错:")print(learning_path["error"])if "raw_response" in learning_path:print("\n原始响应:")print(learning_path["raw_response"])returnprint("📚 课程学习路径分析")print("=" * 60)print(f"课程名称: {learning_path.get('course_title', '未知课程')}")print(f"预计总时长: {learning_path.get('total_estimated_hours', '未知')} 小时")print()for stage in learning_path.get('learning_stages', []):print(f"🎯 阶段 {stage.get('stage_number', '?')}: {stage.get('stage_name', '未知阶段')}")print(f" ⏱️ 建议时长: {stage.get('suggested_hours', '?')} 小时")print(f" 📖 包含章节: {', '.join(stage.get('chapters', []))}")print(" 🔍 核心知识点:")for concept in stage.get('key_concepts', []):print(f" • {concept}")print(" 📋 预习要求:")for prereq in stage.get('prerequisites', []):print(f" • {prereq}")print(" 🏃 练习顺序:")for i, practice in enumerate(stage.get('practice_order', []), 1):print(f" {i}. {practice}")print(" 🎯 学习目标:")for objective in stage.get('learning_objectives', []):print(f" • {objective}")print("-" * 60)if 'study_tips' in learning_path:print("💡 学习建议:")for tip in learning_path['study_tips']:print(f" • {tip}")def main():"""主函数"""# 初始化分析器analyzer = SyllabusAnalyzer()# PDF文件路径 - 请修改为你的实际路径pdf_path = input("请输入课纲PDF文件路径: ").strip().strip('"')if not pdf_path:print("❌ 请提供有效的PDF文件路径")returntry:print("📖 正在提取PDF内容...")pdf_text, sections = analyzer.extract_pdf_content(pdf_path)print(f"✅ 成功提取 {len(sections)} 个章节")print("🤖 正在使用 deepseek-r1:1.5b 分析课纲...")learning_path = analyzer.generate_learning_path(pdf_text, sections)print("📊 分析完成,正在显示结果...")analyzer.display_learning_path(learning_path)# 保存结果save_option = input("\n是否保存结果到文件?(y/n): ").strip().lower()if save_option == 'y':analyzer.save_results(learning_path)except FileNotFoundError:print(f"❌ 找不到PDF文件: {pdf_path}")except Exception as e:print(f"❌ 处理过程中出错: {str(e)}")if __name__ == "__main__":main()