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 datetime
class SyllabusAnalyzer:
def __init__(self, model_name="deepseek-r1:1.5b"):
self.model_name = model_name
def 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, sections
def _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 1
elif re.match(r'^\d+\.\s+', text):
return 1
elif re.match(r'^\d+\.\d+\s+', text):
return 2
elif re.match(r'^\d+\.\d+\.\d+\s+', text):
return 3
else:
return 2
def 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"])
return
print("📚 课程学习路径分析")
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文件路径")
return
try:
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()