# 基本概念

# NLP 和 LLM 的区别

NLP 自然语言处理 和 LLM 大语言模型 有一定关联,但也存在明显区别,主要体现在以下几个方面:

  • 定义与范畴
# NLP:
# 是人工智能的一个重要分支领域,研究如何让计算机理解、处理和生成人类自然语言
# 涵盖了从文本分析、信息检索、机器翻译到情感分析等众多任务和技术
# 旨在使计算机能与人类进行自然语言交互

# LLM:
# 是一种基于深度学习的人工智能模型,属于 NLP 中的一个特定技术类型
# 以 Transformer 架构为基础,通过学习大量文本数据中的语言模式和知识
# 具备处理和生成自然语言文本的能力
  • 研究目的
# NLP:
# 目标广泛,包括实现人机自然交互、文本信息的自动化处理与利用、语言相关问题的智能解决等
# 致力于让计算机像人类一样理解和运用自然语言,提升信息处理效率和智能化水平

# LLM:
# 主要聚焦于学习语言的统计规律和语义知识,通过海量数据训练
# 能根据输入文本生成连贯、合理的自然语言文本
# 旨在模拟人类语言生成能力,为各种 NLP 任务提供语言理解和生成基础
  • 技术方法
# NLP:
# 使用多种技术方法,包括基于规则的方法、统计方法、机器学习方法等
# 早期基于规则的方法依赖人工编写语法和语义规则,后来统计和机器学习方法利用数据进行模型训练
# 如支持向量机用于文本分类

# LLM:
# 主要基于深度学习技术,特别是 Transformer 架构,通过堆叠多层 Transformer 块
# 并行计算和自注意力机制捕捉文本长序列依赖关系
# 利用大规模无监督学习从海量文本中自动学习语言特征和模式
  • 应用场景
# NLP:
# 应用场景多样,如机器翻译、智能客服、文本摘要、信息抽取、语音识别与合成等
# 涉及多个领域,为不同行业提供自然语言处理解决方案

# LLM:
# 在文本生成、知识问答、对话系统等方面表现出色,为智能写作助手、聊天机器人等提供核心支持
# 还可用于阅读理解、推理计算等任务,为各种 NLP 应用提供语言生成和理解基础能力

# 关于 agent

在人工智能中,agent 通常指智能体,是一种能够感知环境做出决策并且采取行动的一个系统,以下从其特点和类型等方面详细介绍:

  • 特点
# 自主性:
# agent 能在没有人类直接干预的情况下,根据自身的内部状态和对环境的感知,自主地决定和执行行动
# 如智能家居系统中的智能温控 agent,可根据室内温度和用户设定自主调节空调温度

# 感知能力:
# agent 具备感知环境信息的能力,通过传感器等设备获取环境中的数据
# 如自动驾驶汽车中的 agent,依靠摄像头、雷达等感知路况和周边车辆、行人等信息

# 交互性:
# agent 可以与环境中的其他实体进行交互,包括其他 agent、人类用户或外部系统
# 如智能客服 agent,能与用户进行对话交互,解答问题和提供帮助

# 目标导向性:
# agent 具有明确的目标,其行动和决策都是为了实现这些目标
# 如物流调度 agent,目标是优化货物配送路线和时间,以提高物流效率
  • 类型
# 软件 agent:
# 是运行在计算机系统中的软件程序,可在网络环境或特定软件平台上执行任务
# 如邮件客户端中的垃圾邮件过滤 agent,能自动识别和过滤垃圾邮件

# 硬件 agent:
# 是基于硬件设备实现的智能体,通常具有物理形态和实际的操作能力
# 如机器人 agent,可在现实世界中进行移动、抓取物体等操作

# 混合 agent:
# 结合了软件和硬件的特点,既有软件部分进行数据处理和决策,又有硬件部分实现物理操作和与环境的交互
# 如一些智能穿戴设备中的 agent,既通过软件分析用户的运动和健康数据,又通过硬件传感器收集生理信息
  • 应用
# 智能交通:交通流量控制 agent 可根据实时路况调整交通信号灯时长,优化交通流量
# 医疗保健:医疗诊断 agent 能分析患者的病历和检查数据,辅助医生进行疾病诊断
# 工业制造:生产调度 agent 可根据订单需求、设备状态等因素,合理安排生产任务和设备调度

虽然 DeepSeek 可用于构建智能体(agent)或为智能体提供语言处理能力等支持,但它本身不是agent。智能体是基于各种技术构建,能感知环境、采取行动以实现目标的实体或系统,比如长城汽车的 Coffee Agent 是基于大模型技术构建的智能体,而 DeepSeek 是被其融合利用来提升自身能力的大语言模型。

# Hugging face、Ollama、modelscope 的区别

  • 功能定位
# Hugging Face 是个综合性的AI平台,提供大量预训练模型,如自然语言处理/计算机视觉/语音识别等多领域
# 还有模型微调、评估和部署工具,以及丰富的数据集和开发者社区
# Ollama 专注于在本地运行大型语言模型,让用户能在自己计算机上下载和运行模型
# 如 Hugging Face 的语言模型格式为 gguf
  • 使用场景
# Hugging Face 适可利用其预训练模型和工具进行各种模型开发、研究实验、构建AI应用等
# Ollama 适合在本地探索语言模型,对隐私和数据安全要求高、追求低延迟和高性能,不依赖外部服务的用户
  • 生态系统
# Hugging Face 有庞大的开发者社区,有模型库、数据集、开源产品矩阵等,便于开发者交流合作
# Ollama 生态围绕本地部署和使用语言模型展开,与 Hugging Face Hub 结合可获取更多模型资源

modelscope 是中国版的 Hugging face,支持多种模型格式,如 Safetensor 等。Safetensor 格式常用于模型的微调和其他操作,它在存储和传输模型数据时提供了更高的安全性和稳定性

# Langchain(长链) Transformer(模型)和PyTorch 的区别

Transformer是模型结构,PyTorch是实现工具,Long chain是特定应用场景

  • Transformer与PyTorch
Transformer
# 是一种基于自注意力机制的深度学习模型,广泛用于自然语言处理(如BERT、GPT)、计算机视觉等领域

PyTorch 
# 是Facebook开发的深度学习框架,提供了灵活的张量运算和自动求导功能,支持快速构建和训练神经网络

PyTorch是实现Transformer模型的常用工具之一
# 可以用PyTorch的API搭建Transformer的核心组件(如多头注意力),并进行训练和部署
  • Langchain与Transformer/PyTorch
Langchain 
# 通常指处理长序列数据的场景(如长文本、长视频帧)

Transformer模型
# 在处理长序列时存在计算复杂度高(与序列长度平方成正比)的问题
# 因此研究者会基于Transformer改进出适用于长链的模型(如Sparse Transformer、Longformer)

PyTorch作为框架
# 为长链模型的实现提供支持,如通过稀疏矩阵运算、滑动窗口注意力等优化,帮助开发者高效处理长序列数据

# 模型蒸馏

蒸馏(Distillation)指的是组织发布的原始模型的蒸馏版本。蒸馏模型基本上是更小更高效的模型,旨在复制大型模型的行为,同时降低资源需求。具体步骤:

数据准备 # 准备一个能代表目标任务的数据集。数据增强技术可进一步提高训练示例的多样性
选择教师模型 # 选择一个性能良好、经过预先训练的教师模型。教师的质量直接影响学生的表现

蒸馏过程
  训练设置 # 初始化学生模型并配置训练参数(如学习率、批量大小)
  知识传输 # 使用教师模型生成软目标(概率分布)和硬目标(地面实况标签)
  训练循环 # 训练学生模型,使其预测与软/硬目标之间的综合损失最小

模型蒸馏和模型微调的区别:

# 微调(Fine-tuning)就像学生发现自己数学不好,找个家教补习一下,专门提高某块短板
# 它不像蒸馏那样从头教,也不需要外挂,就是在大模型的基础上"精修"一下

# 模型介绍

# deepseek三部曲

以下是 DeepSeek 大语言模型的模型部署、模型微调、投喂数据相关内容:

# 模型部署

本地部署 # 可以借助 LM Studio 或 Ollama 等工具
云端部署 # 腾讯云和阿里云提供了对 DeepSeek 全系模型的支持,可以快速接入 API 并实现一键部署

# 模型微调

加载预训练模型
# 利用 Hugging Face Transformers 等框架加载 DeepSeek 预训练模型
# 如使用 Python 的 AutoModelForCausalLM 和 AutoTokenizer 进行加载
# 使模型具备基础的语言理解和生成能力,为微调做准备

数据预处理
# 对用于微调的数据集进行处理,将文本转换为模型可理解的 token 序列
# 确保每个样本的输入和输出都被正确编码,并按照模型要求进行填充或截断

配置微调参数
# 包括学习率:通常设为较小值如 5e-5
# 批量大小:根据硬件资源选 8 或 16
# 训练周期:一般 3-5 个周期
# 防止破坏预训练权重和过拟合

开始微调
# 使用 PyTorch 或 TensorFlow 框架启动微调过程
# 通过训练循环在训练集上进行微调,并定期保存检查点,以便评估和后续使用

# 投喂数据

选择工具
# 可结合 AnythingLLM 等工具来投喂数据
# AnythingLLM 支持多种文档格式的上传和解析,并能与 DeepSeek 模型无缝对接

数据准备
# 收集与目标任务相关的各种格式数据,如 PDF、Word、Markdown 等文档,还可以是对话记录等文本数据

上传与处理
# 以 AnythingLLM 为例,先创建工作区,点击 “上传文件” 按钮选择文档完成上传
# 对于 PDF 文件,工具会自动提取关键信息并生成摘要
# Word 文件可按章节或段落进行拆分和整理,以便模型更好地理解和学习

# Qwen3-Coder

# 是一款混合专家(MoE)模型,最强大的版本,名为 Qwen3-Coder-480B-A35B-Instruct
# 编程能力登顶全球开源模型阵营,并超越GPT4.1等闭源模型,比肩全球最强的编程模型Claude4
# 总参数量高达4800亿,激活参数为350亿,原生支持256K token的上下文,支持358种编程语言

# Qwen3-4B-A3B

Qwen3-4B-Instruct-2507(非思考版)
# 推理能力媲美中尺寸模型,其Agent能力超越Qwen3-30B-Thinking

Qwen3-4B-Thinking-2507(思考版)
# 在知识、推理、编程、对齐和agent能力上全面超越GPT-4.1-nano,与Qwen3-30B-A3B性能接近

# Qwen3-30B-A3B

  • Qwen3-30B-A3B-Instruct(非思考版)
  • Qwen3-30B-A3B-Thinking(思考版)

是一款经过精细指令微调的混合专家(MoE)模型,其设计的核心目标是在遵循复杂指令的同时,实现高效、高质量的文本生成。

全方位的能力跃升
# 相较于前代,该模型在各项基础能力上均实现了显著飞跃
# 无论是需要严谨逻辑的推理、精细入微的文本理解,还是复杂的数学、科学和代码生成任务,它都表现出色

广博的多语言知识
# 模型的一大亮点是其在多语言能力上的突破,大幅扩展了对超过100种语言及方言的长尾知识覆盖
# 这使其不仅能流利沟通,更能理解和运用不同文化背景下的细微差别

卓越的长上下文处理
# 模型原生支持高达256K(262,144个token)的超长上下文窗口
# 使其在处理长篇文档分析、复杂代码库理解以及多源信息推理等任务时不会因文本过长而丢失关键信息

深度用户对齐与高质量生成
# 通过监督微调(SFT)和人类反馈强化学习(RLHF)的深度淬炼,模型能更精准地捕捉和对齐用户的真实意图
# 尤其在处理主观和开放性问题时,能生成更有帮助、更符合人类偏好的高质量回复

强大的工具调用与智能体潜力
# 该模型在工具调用(Tool Calling)方面展现了卓越的性能,使其成为构建强大智能体(Agent)的理想核心
# 官方推荐使用Qwen-Agent框架来充分释放其作为自动化助手的潜力

# dots.ocr 文档解析器

dots.ocr (opens new window) 是一款功能强大的多语言开源文档解析器,它将布局检测和内容识别功能统一在一个视觉语言模型中,同时保持良好的阅读顺序。尽管其 LLM 基础紧凑,拥有 1.7B 参数,但它仍达到了最佳 (SOTA) 性能。

# Hunyuan 3D-2.1

混元生3D开源模型 (opens new window)可以将任何平面图像转换为工作室品质的 3D 模型,混元3D AI创作引擎 (opens new window)

# Prompt Optimizer 提示词优化工具

Github仓库 (opens new window)

  • 主要功能:
智能优化 # 一键优化提示词,支持多轮迭代改进,提升 AI 回复的准确度和相关性
双模式优化 # 支持系统提示词和用户提示词的优化,满足不同使用场景
实时对比 # 支持原始提示词和优化后提示词的实时对比,直观展示优化效果
多模型集成 # 支持 OpenAI、Gemini、DeepSeek、智谱 AI、SiliconFlow 等主流 AI 模型
安全架构 # 纯客户端处理,数据直接与 AI 服务商交互,不经过中间服务器,确保数据安全
多端支持 # 提供 Web 应用、桌面应用、Chrome 插件和 Docker 部署等多种使用方式
访问控制 # 支持密码保护功能,保障部署安全
MCP 协议支持 # 支持 MCP 协议,可与 Claude Desktop 等 MCP 兼容应用集成
  • 如何使用:
使用在线版本 # 直接访问 https://prompt.always200.com 使用,所有数据存储在浏览器本地,安全可靠
Vercel 部署 # 可以一键部署到自己的 Vercel,也可以 Fork 项目后在 Vercel 中导入
            # 需配置环境变量如 ACCESS_PASSWORD 和各 AI 服务商的 API 密钥等
下载桌面应用 # 从 GitHub Releases 下载最新版本,有安装程序和压缩包两种格式,安装程序支持自动更新
安装 Chrome 插件 # 从 Chrome 商店安装,点击图标即可打开提示词优化器
Docker 部署 # 通过 Docker 命令运行容器,可配置 API 密钥和访问密码等环境变量
Docker Compose 部署 # 克隆仓库后,创建.env文件配置 API 密钥等,再使用 docker compose up -d 启动
MCP Server 使用 # 当通过 Docker 运行时,MCP Server 会自动启动,可通过 http://ip:port/mcp 访问
                # 需配置环境变量如 MCP_DEFAULT_MODEL_PROVIDER 等
				# 可在 Claude Desktop 等支持 MCP 的应用中集成使用
本地开发 # 克隆项目后,安装依赖并运行开发命令即可开始本地开发

# Text2SQL

将自然语言查询转为 SQL 的任务,经历了基于规则、神经网络、预训练语言模型、大语言模型四个阶段。当前面临提示优化、模型训练、推理时增强三大难题,研究基于 BIRD 数据集展开。

# llm-engineer-toolkit 综合资源库

llm-engineer-toolkit (opens new window) 一个按功能分类的综合资源库。该仓库收集了超过 120 个库,涵盖 LLM 的各个开发阶段,包括训练、微调、应用开发、推理、检索增强生成(RAG)、代理、评估、监控、安全性等。

# MaxKB 企业级智能体平台

MaxKB (opens new window)它把 RAG(检索增强生成)、工作流编排、MCP 工具调用、多模型对接等关键能力整合到一套“开箱即用”的系统中,帮助企业在最短时间内把大模型接入真实生产场景,实现智能客服、内部知识库、学术助手、教育辅导等多种应用。

docker run -d --name=maxkb --restart=always -p 8080:8080 -v ~/.maxkb:/opt/maxkb 1panel/maxkb
# 默认账号:admin  默认密码:MaxKB@123..

30 分钟上线流程

1. 创建知识库 # 上传 PDF / Word / 网页链接
2. 选择模型 # 支持本地私有化或云端 API
3. 调试问答 # 内置 Playground 一键测试
4. 集成发布 # 复制 <iframe> 或调用 REST 接口即可嵌入现有系统
5. 权限体系 # 多租户、SSO、LDAP企业级安全合规,开箱即用

# 模型微调

# 全量微调可对模型的能力进行深度改造,但要带入全部参数进行训练,消耗大量的算力且有一定的技术门槛
# 相比之下,在绝大多数场景中,如果我们只想提升模型某个具体领域的能力,那高效微调会更加合适
# 2020年前后,深度学习领域诞生了很多高效微调的方法,但现在最主流的高效微调方法只有一种——LORA

# LORA 与 QLORA

# 旨在通过引入低秩矩阵来减少微调时需要调整的参数数量,从而显著降低显存和计算资源的消耗
# 具体来说,LoRA微调并不直接调整原始模型的所有参数,而是通过在某些层中插入低秩的适配器层来进行训练
  • LORA的原理
# 在标准微调中,我们会修改模型的所有权重,而在LoRA中,只有某些低秩矩阵(适配器)被训练和调整
# 这意味着原始模型的参数保持不变,只是通过少量的新参数来调整模型的输出
# 低秩矩阵的引入可以在显存和计算能力有限的情况下,依然有效地对大型预训练模型进行微调
# 从而让LoRA成为显存较小的设备上的理想选择
  • LORA的优势
# 显存优化:只需要调整少量的参数(适配器),显著减少了显存需求,适合显存有限的GPU
# 计算效率:微调过程中的计算负担也更轻,因为减少了需要调整的参数量
# 灵活性:可以与现有的预训练模型轻松结合使用,适用于多种任务,如文本生成、分类、问答等
  • QLoRA(Quantized Low-Rank Adaptation)
# 是LoRA的一个扩展版本,它结合了LoRA的低秩适配器和量化技术,进一步优化了计算效率和存储需求
# 与LoRA不同的是,QLoRA会将插入的低秩适配器层的部分权重进行量化(通常量化为INT4或INT8)
# 在保持性能的同时显著降低模型的存储和计算需求
# 核心思想: 在LoRA的基础上加入量化技术,减少权重表示的位数,从而降低显存和计算需求

# 主流微调工具

# unsloth是一个专为大型语言模型(LLM)设计的微调框架,旨在提高微调效率并减少显存占用
# 它通过手动推导计算密集型数学步骤并手写GPU内核,实现了无需硬件更改即可显著加快训练速度
# unsloth 与 HuggingFace 生态兼容,可以很容易地与 transformers、peft、tr 等库结合
# 以实现模型的监督微调(SFT)和直接偏好优化(DPO),仅需型的加载方式,无需对现有训练代码进行修改
# LLaMA-Factory 是一个统一且高效的微调框架
# 旨在为超过 100种大型语言模型(LLMS)和视觉语言模型(VLMS)提供便捷的微调支持
# 用户能够灵活地定制型以适应各种下游任务,封装程度没有unsloth高
# 由魔搭社区开发的高效微调和部署框架,主要针对Qwen系列
# 旨在提供一站式的大模型与多模态大模型的训练、推理、评测、量化和部署方案
# 支持超过450种大型模型(LLMS)和150多种多模态大模型(MLLMs)的训练和部署
# 包括最新的模型版本,如 Qwen2.5、InternLM3、GLM4、Llama3.3、DeepSeek-R1、Yi1.5 等
# 以及多模态模型如 Qwen2.5-VL、Qwen2-Audio、Llama3.2Vision、Llava、InternVL2.5 等

# 操作系统选择

由于绝大多数工业场景下微调会涉及多卡微调,目前只有Linux系统对Deepspeed和其他多卡并行加速库支持较好,因此绝大多数工业场景下都会使用Ubuntu操作系统或CentOS操作系统,若想体验更加真实的工业场景下的微调流程,也可以考虑在AutoDL (opens new window)上租赁显卡。

# 使用 unsloth 微调过程

  • 安装部署 unsloth
# 安装部署
pip install unsloth
pip install --force-reinstall --no-cache-dir --no-deps /
git+https://github.com/unslothai/unsloth.git

若是AutoDL (opens new window)服务器,且Github网速不稳,则可以使用如下命令开启AutoDL学术加速:

source /etc/network_turbo
# 在大规模模型训练中,我们往往需要监控和分析大量的训练数据,而WandB可以帮助我们实现这一目标

# 实时可视化:
# WandB可以实时展示训练过程中关键指标的变化,如损失函数、学习率、训练时间等
# 通过这些可视化数据,我们能够直观地了解模型的训练进展,快速发现训练中的异常或瓶颈

# 自动记录与日志管理:
# WandB会自动记录每次实验的参数、代码、输出结果,确保实验结果的可追溯性
# 无论是超参数的设置,还是型的架构调整,WandB都能够帮助我们完整保留实验记录,方便后期对比与调优

# 支持中断与恢复训练:
# 在长时间的预训练任务中,系统中断或需要暂停是常见的情况
# 通过WandB的checkpoint功能,我们可以随时恢复训练,从上次中断的地方继续进行,避免数据和时问的浪费

# 多实验对比:
# 当我们尝试不同的模型配置或超参数时
# WandB允许我们在多个实验之间轻松进行对比分析,帮助我们选择最优的模型配置

# 团队协作:
# WandB还支持团队协作,多个成员可以共同查看实验结果,协同调试模型
# unsloth 和 wandb 已高度集成,只需提供 wandb key即可
# 安装部署
pip install wandb
  • DeepSeek-R1-Distill-Llama-8B-GGUF 模型下载
# 安装 modelscope,下载的模型为 Safetensor 格式
pip install modelscope
# 下载 Safetensor 格式的模型
modelscope download --model deepseek-ai/DeepSeek-R1-Distill-Llama-8B \
--local_dir D:\DeepSeek\Model\modelscope\8B
  • 使用 unsloth 加载本地模型
# 查看显卡信息
nvidia-smi

# 一定要安装支持cuda的pytorch
pip install torch==2.3.0+cu121 torchvision==0.18.0+cu121 torchaudio==2.3.0+cu121 /
-f https://mirror.sjtu.edu.cn/pytorch-wheels/torch_stable.html

# windows上通过whl文件安装triton模块,whl文件:
# whl文件下载:https://hf-mirror.com/madbuda/triton-windows-builds
pip install triton-3.0.0-cp310-cp310-win_amd64.whl
from unsloth import FastLanguageModel

max_seq_length = 2048 
dtype = None
# 若显存不足,则可以load in_4bit=True,运行4 bit量化版
# 设置为false,则使用模型原本的精度进行推理
load_in_4bit = False

# 加载模型和分词器(文本和数字的转换)
model, tokenizer = FastLanguageModel.from_pretrained(
    model_name = "./DeepSeek-R1-Distill-Llama-8B",
	# 模型会将输入文本按此长度进行截断或补齐操作
    max_seq_length = max_seq_length,
    dtype = dtype,
	# 计算机通常使用 32 位(float32)或 16 位(float16)来表示浮点数以进行计算和存储数据
	# 而load_in_4bit意味着将模型的参数从原本较高的精度(如 32 位)量化为 4 位来进行存储和计算
    load_in_4bit = load_in_4bit,
	# 如果使用Hugging Face 则设置其 token,model_name为其地址
    # token = hf_token
)

# 将模型调整为推理模式
FastLanguageModel.for_inference(model) # 推理模式
# FastLanguageModel.for_training(model)  # 训练模式

# 定义一个系统提示,并在其中包含问题和回答生成的占位符
prompt_style = """请写出一个恰当的回答来完成当前对话任务。

### Instruction:
你是一个爱助人为乐的好同志. 

### Question:
{}

### Response:
<think>{}"""

# 和模型对话
question = "你还好吗,好久不见了" # 可以设置多个 question
# 首先需要借助分词器,将输入的问题转化为标记索引:
inputs = tokenizer([prompt_style.format(question,"")], return_tensors="pt").to("cuda")
# 再带入inputs进行对话
outputs = model.generate(
    input_ids = inputs.input_ids,
    max_new_tokens = 1200,
    use_cache = True,
)
# 此时得到的回复也是词索引,同样需要分词器将其转化为文本
response = tokenizer.batch_decode(outputs, skip_special_tokens=True)[0]
print(response.split("### Response:")[1])
  • 推理模型微调数据集下载
# DeepseekR1 模型组回复结构与微调数据集结构要求:
# DeepSeekR1及其蒸馏模型,推理过程的具体体现就是在回复内容中,会同时包含推理部分<think>和回复部分
# 因此,在微调的时候,微调数据集的回复部分文本也需要是包含推理和最终回复两部分内容(COT数据集)
# 使用 datasets 进行数据集下载
pip install datasets

# medical-o1-reasoning-SFT 医学推理数据集
# 该数据集专为微调 HuatuoGPT-o1 这一医学大语言模型而设计,旨在提升其在复杂医学推理任务中的表现
# 直接从huggingface上下载medical-o1-reasoning-SFT数据集
https://huggingface.co/datasets/Freedomintelligence/medical-o1-reasoning-SFT

由于huggingface网络受限,若是AutoDL服务器,可以按照如下方式开启学术加速:

# 学术资源加速 https://www.autodl.com/docs/network_turbo/
import subprocess
import os

result = subprocess.run('bash -c "source /etc/network_turbo && env | grep proxy"', 
                         shell=True, capture_output=True, text=True)
output = result.stdout
for line in output.splitlines():
    if '=' in line:
        var, value = line.split('=', 1)
        os.environ[var] = value

或者通过魔塔社区 modelscope 下载

modelscope download --dataset FreedomIntelligence/medical-o1-reasoning-SFT --local_dir ./dir

默认情况下数据集保存在主目录下.cache文件夹中,数据文件格式如下所示:

/root/.cache/huggingface/datasets/autodl-tmp/en/0.0.0/8883d72e8b332269

数据文件格式

  • 小数据量微调
import wandb
from unsloth import FastLanguageModel

from trl import SFTTrainer
from transformers import TrainingArguments
from unsloth import is_bfloat16_supported

max_seq_length = 2048
dtype = None
load_in_4bit = True

# 读取模型和分词器
model, tokenizer = FastLanguageModel.from_pretrained(
    model_name = "D:/DeepSeek/Model/ModelScope/8B",
    max_seq_length = max_seq_length,
    dtype = dtype,
    load_in_4bit = load_in_4bit,
)

# 定义一个系统提示,并在其中包含问题和回答生成的占位符。该提示将引导模型逐步思考,并提供一个逻辑严谨、准确的回答。
train_prompt_style = """Below is an instruction that describes a task, paired with an input that provides further context. 
Write a response that appropriately completes the request. 
Before answering, think carefully about the question and create a step-by-step chain of thoughts to ensure a logical and accurate response.

### Instruction:
You are a medical expert with advanced knowledge in clinical reasoning, diagnostics, and treatment planning. 
Please answer the following medical question. 

### Question:
{}

### Response:
<think>{}"""

# 设置文本生成结束的标记
EOS_TOKEN = tokenizer.eos_token  # <|end_of_sentence|>

# 用于对medical-o1-reasoning-SFT数据集(Question、Complex_CoT、Response)进行修改
# 将Complex_CoT列和Response列进行拼接,并加上文本结束标记
def formatting_prompts_func(examples):
    inputs = examples["Question"]
    cots = examples["Complex_CoT"]
    outputs = examples["Response"]
    texts = []
    for input, cot, output in zip(inputs, cots, outputs):
        text = train_prompt_style.format(input, cot, output) + EOS_TOKEN
        texts.append(text)
    return {
        "text": texts, # "text" 列包含了系统提示、指令、思维链和答案
    }

# 将从 Hugging Face Hub 加载 FreedomIntelligence/medical-o1-reasoning-SFT 数据集的前 500个 样本
from datasets import load_dataset
dataset = load_dataset("FreedomIntelligence/medical-o1-reasoning-SFT","en", split="train[0:500]",trust_remote_code=True)
# 或者通过魔塔社区 modelscope 下载后加载
# dataset = load_dataset("/root/autodl-tmp","en", split="train[0:500]",trust_remote_code=True)
# 进行结构化处理,处理后的数据集默认保存再主目录下的 .cache 文件夹中
dataset = dataset.map(
    formatting_prompts_func,
    batched=True,
)
print(dataset["text"][0])

# 微调模式,通过使用目标模块,我们将通过向模型中添加低秩适配器(low-rank adopter)来设置模型
model = FastLanguageModel.get_peft_model(
    model,
    r=16,
    target_modules=[
        "q_proj",
        "k_proj",
        "v_proj",
        "o_proj",
        "gate_proj",
        "up_proj",
        "down_proj",
    ],
    lora_alpha=16,
    lora_dropout=0,
    bias="none",
    use_gradient_checkpointing="unsloth",  # True or "unsloth" for very long context
    random_state=3407,
    use_rslora=False,
    loftq_config=None,
)

# 设置训练参数和训练器,通过提供模型、tokenizer、数据集以及其他重要的训练参数,来优化我们的微调过程。
# 使用 SFTTrainer 进行监督微调,适用于transformers 和 Unsloth 生态中的模型微调
trainer = SFTTrainer(
    model=model, # 需要进行微调的预训练模型
    tokenizer=tokenizer, # 用于将文本转换为模型可以理解的标记索引的分词器
    train_dataset=dataset, # 用于训练的数据集
    dataset_text_field="text", # 用于训练的文本字段
    max_seq_length=max_seq_length, # 输入序列的最大长度
    dataset_num_proc=2, # 用于预处理数据集的进程数
    # 用于定义训练超参数
    args=TrainingArguments(
        per_device_train_batch_size=2, # 每次训练几条数据
        gradient_accumulation_steps=4, # 梯度累积几个后更新一次
        # num_train_epochs = 1, # 训练几轮,训练所有数据
        warmup_steps=5, # 学习率预热步数
        max_steps=60, # 训练步数,总共使用 max_steps * per_device_train_batch_size * gradient_accumulation_steps 480步
        learning_rate=2e-4, # 学习率(2e-4=0.0002 控制权重更新幅度)
        fp16=not is_bfloat16_supported(), # 如果GPU不支持bfloat16,则使用fp16
        bf16=is_bfloat16_supported(), # 如果支持bfloat16,则启用bfloat16(训练更稳定)
        logging_steps=10, # 每10步打印一次训练日志
        optim="adamw_8bit", # 使用8位Adam优化器,减少显存占用
        weight_decay=0.01,  # 权重衰减系数,用于防止过拟合
        lr_scheduler_type="linear", # 学习率调度器类型(线性衰减)
        seed=3407,  # 随机种子,用于保证结果可重复性
        output_dir="outputs", # 输出目录,用于保存训练结果
    ),
)
wandb.login(key="121212121212")

# 开始训练
trainer_stats = trainer.train()

# 使用微调后的模型推理,model是参与完训练的模型
FastLanguageModel.for_inference(model) # 将模型调整为推理模式
question = "A 61-year-old woman with a long history of involuntary urine loss during activities like coughing or sneezing but no leakage at night undergoes a gynecological exam and Q-tip test. Based on these findings, what would cystometry most likely reveal about her residual volume and detrusor contractions?"
# 首先需要借助分词器,将输入的问题转化为标记索引:
inputs = tokenizer([train_prompt_style.format(question,"")], return_tensors="pt").to("cuda")
# 再带入inputs进行对话
outputs = model.generate(
    input_ids = inputs.input_ids,
    attention_mask=inputs.attention_mask,
    max_new_tokens = 1200,
    use_cache = True,
)
# 此时得到的回复也是词索引,同样需要分词器将其转化为文本
response = tokenizer.batch_decode(outputs, skip_special_tokens=True)[0]
print(response.split("### Response:")[1])
  • 模型合并,此时本地保存的模型在 outputs 文件夹中

模型合并

new_model_local = "DeepSeek-R1-Medical-COT-Tiny" # 创建保存的地址
model.save_pretrained(new_model_local) 
tokenizer.save_pretrained(new_model_local)

model.save_pretrained_merged(new_model_local, tokenizer, save_method = "merged_16bit",)

训练后的模型文件,如果使用unsloth继续推理调用需要删除 adapter 的2个文件

训练后的模型文件

  • 将模型推送到 Hugging Face Hub
new_model_online = "sylone/DeepSeek-R1-Medical-COT" # Hugging Face Hub地址
model.push_to_hub(new_model_online)
tokenizer.push_to_hub(new_model_online)

model.push_to_hub_merged(new_model_online, tokenizer, save_method = "merged_16bit")
# 将其推送到huggingface上并保存为GGUF格式文件并进行调用
model.save_pretrained_gguf("dir", tokenizer,quantization_method="g4km")

# prompt 提示词

# Prompt Engineering 提示词工程

通过设计结构化输入(指令/示例/上下文)引导模型生成目标输出,合适的格式能显著提升模型的理解能力和输出质量。以下是几种高效且常用的格式方案:

  • 基础推荐格式(清晰分段式)
# 角色与目标
你是一位[资深营养师],需要为用户设计健康食谱。

# 背景与上下文
用户是一位[素食主义者,有乳糖不耐症],目标是[减重5公斤],时间周期为[1个月]# 任务要求
1. 生成一份[7]的晚餐食谱清单
2. 每餐热量<500卡路里
3. 标注主要营养素比例
4. 避免使用豆制品(用户过敏)

# 输出规范
- 使用表格形式呈现
- 附采购清单(按食材分类)
- 添加烹饪难度提示(⭐~⭐⭐⭐)
  • 技术型任务(代码生成专用)
## 系统指令
你是一位Python数据科学家,使用pandas和sklearn。

## 用户需求
请编写代码完成以下任务:
1. 从CSV文件`data.csv`加载数据
2. 对`price`列进行Z-score标准化
3. 用KMeans将数据聚为3类
4. 可视化聚类结果(使用matplotlib)

## 约束条件
- 代码必须包含异常处理
- 添加详细注释
- 输出保存为PNG格式

## 示例格式
···python
# 你的代码从这里开始...
···
  • 创意生成(多元素控制)
<creative-brief>
  <genre>科幻悬疑短篇小说</genre>
  <protagonist>
    <name>埃利亚斯</name>
    <traits>记忆删除症患者、前神经黑客</traits>
  </protagonist>
  <setting>2097年上海悬浮城邦</setting>
  <key-elements>
    <element>量子记忆黑市</element>
    <element>会说话的机械乌鸦</element>
  </key-elements>
  <tone>冷峻中带黑色幽默</tone>
  <constraints>
    <constraint>包含三次剧情反转</constraint>
    <constraint>结尾留悬疑</constraint>
  </constraints>
</creative-brief>
  • 复杂任务(思维链CoT增强)
## 问题分析
用户查询:“比较光伏发电与风电在青藏高原的适用性”

### 需要覆盖维度:
1. 地理条件适配性(海拔/日照/风力)
2. 基础设施挑战(输电/维护)
3. 环境影响对比
4. 投资回报周期

## 执行步骤
[Step 1] 提取青藏高原气象数据特征 → 
[Step 2] 计算两种能源效率公式 → 
[Step 3] 对比衰减率曲线 → 
[Step 4] 生成风险矩阵图

## 输出要求
- 用Markdown表格呈现核心参数
- 绘制决策树结论图(文字描述)
- 标注数据来源可信度

最佳实践原则:

分层结构化 # 用标题/符号分割:角色 → 任务 → 约束 → 输出格式
关键元素显性化 # [重要变量]用方括号标注,避免歧义
示例驱动 #(Few-shot)
防御性提示 # 追加:如遇信息缺失,请明确说明而非猜测

核心缺陷:

脆弱性 # 微调措辞导致输出剧变
扩展瓶颈 # 难以应对高并发场景
无状态性 # 无法处理多轮对话

# Context Engineering 上下文工程

动态上下文构建(RAG)、工作流编排(LangGraph)、资源优化(向量数据库)

# Ollama 的使用

官网 (opens new window) 国内镜像 (opens new window)

# 常用命令

# 查看版本
ollama -v
ollama --version

# 下载模型
ollama pull qwen3:4b

# 运行模型
ollama run qwen3:4b

# 从魔搭(modelscope)拉取GGUF框架的模型
ollama run modelscope.cn/Qwen/Qwen3-8B-GGUF

# 查看运行的大模型是用的cpu还是gpu,还是混合的
ollama ps

# 查看已安装模型
ollama list

# 查看模型信息
ollama show qwen3:4b

# 删除指定模型
ollama rm qwen3:4b

# 启动服务
systemctl start ollama

# 关闭服务
systemctl stop ollama

# 重启服务(如果模型下载失败可重启服务,ollama会自动清理垃圾数据,否则一直下载失败)
systemctl restart ollama

# 开机启动
systemctl enable ollama

# 禁止开机启动
systemctl disable ollama

# 重载配置
systemctl daemon-reload

# 会话管理

# 加载会话或模型
/load <model>:加载一个特定的模型或会话。可以指定一个模型的名称或路径来加载它

# 保存会话
/save <model>:保存当前的会话状态或模型。可以将当前会话或模型的配置保存为一个文件,以便以后使用

# 清除会话上下文
/clear:清除会话上下文。这将删除当前会话中的所有历史记录或对话内容

# 退出会话
/bye:退出会话。这个命令将结束当前与模型的对话,并退出程序

# 修改默认模型下载位置

可以通过设置环境变量OLLAMA_MODELS来修改模型存储位置

‌Windows系统‌:
# 默认位置:C:\Users\<用户名>\.ollama/models
# 设置环境变量OLLAMA_MODELS,例如E:\ollama\models。重启Ollama或PowerShell,使设置生效

‌Linux系统‌:
# 默认位置:/usr/share/ollama/.ollama/models
# 创建新目录并设置权限,例如sudo mkdir /path/to/ollama/models
# 编辑ollama.service文件,添加环境变量OLLAMA_MODELS。重启ollama服务
# 此路径需要有对应的权限:(例如我的路径是/home/ollama/models/)
sudo chown -R ollama:ollama /home/ollama/models/
sudo chmod -R 777 /home/ollama/models/

# Linux 离线安装

  • 下载脚本 install.sh
# 浏览器打开直接打开 https://ollama.com/install.sh下载脚本,或者复制粘贴
# 对应版本的 install.sh 脚本在 github -> Source code(tar.gz) -> ollama-0.6.8 -> scripts 中
  • 修改脚本 install.sh
# 1、把脚本中所有的这几行都注释掉。注释掉的地方是不需要下载安装包的代码,因为下载的过程会很慢。

# curl --fail --show-error --location --progress-bar \
#    "https://ollama.com/download/ollama-linux-${ARCH}.tgz${VER_PARAM}" | \
#    $SUDO tar -xzf - -C "$OLLAMA_INSTALL_DIR"


#curl --fail --show-error --location --progress-bar \
#    "https://ollama.com/download/ollama-linux-${ARCH}-jetpack6.tgz${VER_PARAM}" | \
#    $SUDO tar -xzf - -C "$OLLAMA_INSTALL_DIR"
        

#curl --fail --show-error --location --progress-bar \
#    "https://ollama.com/download/ollama-linux-${ARCH}-jetpack5.tgz${VER_PARAM}" | \
#    $SUDO tar -xzf - -C "$OLLAMA_INSTALL_DIR"

#curl --fail --show-error --location --progress-bar \
#    "https://ollama.com/download/ollama-linux-${ARCH}-rocm.tgz${VER_PARAM}" | \
#    $SUDO tar -xzf - -C "$OLLAMA_INSTALL_DIR"

# 2、在install_success()函数的上面添加一个命令:
$SUDO tar -xzf ollama-linux-amd64.tgz -C "$OLLAMA_INSTALL_DIR"
# tgz文件是在github上下载的,需要按照自己的操作系统找到对应的
  • 运行安装脚本
# 修改权限
chmod +x ./install.sh

# 运行脚本
./install.sh
  • 启动文件:/etc/systemd/system/ollama.service
[Unit]
Description=Ollama Service
After=network-online.target

[Service]
ExecStart=/usr/bin/ollama serve
User=root
Group=root
Restart=always
RestartSec=3
Environment="PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin"
Environment="OLLAMA_HOST=0.0.0.0:11434" # 默认绑定在127.0.0.1上,远程就没法访问
Environment="OLLAMA_MODELS=/mnt/data/ollama/models"
Environment="OLLAMA_CONTEXT_LENGTH=8192" # 0.5.13版本后新增

[Install]
WantedBy=default.target
  • 重载配置
systemctl daemon-reload
systemctl restart ollama

# 导入本地模型

# 创建模型配置文件 Modelfile,不要添加注释
FROM ./模型名称.gguf

# 模型导入
ollama create 自定义模型名称 -f ./Modelfile

# 导入后执行
ollama list

# 运行模型
ollama run model-name

# 默认参数

Ollama默认参数

num_ctx 
# 模型可以一次记住的最大 token 数量,默认配置 2048
# 相当于一次只能向模型输入 2k token,超过 2k 模型就无法记住。当 prompt 特别长时往往会出现问题

num_predict 
# 模型最大可以生成的 token 数量,默认配置 128
# 相当于每次模型只能生成小于 128 token 回复。无法生成长回复

# 配置优化

当我们使用 ollama 安装本地大模型,并且使用 openai 的 api 去调用本地大模型的时候,发现无论我们的输入多长的内容,最终返回的提示词 prompt_tokens 长度只有2048。

  • 方法一:修改模型配置参数
# 1、获取模型默认 Modelfile 配置
ollama show llama3.1:8b --modelfile

# 2、将其中默认的 Modelfile 内容复制出来,在本地创建一个 Modelfile 文件,将内容粘贴进去
# 3、查询模型 context length:131072,相当于 128k token
ollama show llama3.1:8b
# 4、在本地 Modelfile 最后,插入两行配置
PARAMETER num_ctx 131072
PARAMETER num_predict -1
# 5、创建新模型,新模型命名 xxxx-max-context
ollama create llama3.1:8b-max-context -f Modelfile

注意

ollama 在0.5.13版本后可以直接在配置文件中启动设置:OLLAMA_CONTEXT_LENGTH=8192

  • 方法二:修改请求配置参数

调用ollama自己的的api(/api/chat),不使用openai的api(/v1)去调用时可以在请求配置中调整

import requests
 
# ollama的api,而非openai的请求方式
url = "http://localhost:11434/api/chat"
 
payload = {
    "model": "deepseek-r1:1.5b",
    "stream": False,
    "messages": [
        {"role": "user", "content": content + "\n\n小说讲了什么内容"},
    ],
    "options": {"num_ctx": 8192} # 上下文参数
}
 
response = requests.post(url, json=payload)
print(response.text)

# 模型转换

大部分模型不提供 GGUF 格式的模型文件,需要将 safetensors 格式的模型文件转换为 GGUF 格式

# 1、从 https://github.com/ggml-org/llama.cpp/releases 下载对应自己系统的包,并解压到特定目录
# 2、下载 https://github.com/ggml-org/llama.cpp 源代,并和上面下载的编译好的文件放到同一目录中
# 3、进入 llama.cpp 目录下,执行命令安装所有依赖库:pip install -r requirements.txt
# 4、执行命令模型转换:python convert_hf_to_gguf.py [模型文件夹位置]

# API 说明

/api/generate
# 用途: 用于生成单个文本片段。通常不考虑历史消息历史或对话上下文
# 功能: 用于各种生成任务,如文章创作、代码生成、故事编写等,每次请求不依赖前一次请求的结果

/api/chat
# 用途: 用于对话式的交互。通常需要一个消息列表作为输入,以维护对话的历史和上下文
# 功能: 适合创建聊天机器人、问答系统或任何需要多轮对话的应用场景

基于ollama 的流式聊天:

import json
import requests

# NOTE: ollama must be running for this to work, start the ollama app or run `ollama serve`
model = "qwen2:latest"  # TODO: update this for whatever model you wish to use
def chat(messages):
    r = requests.post(
        # "http://127.0.0.1:11434/api/generate",
        "http://127.0.0.1:11434/api/chat",
        json={"model": model, "messages": messages, "stream": True},
    )
    r.raise_for_status()
    output = ""
    for line in r.iter_lines():
        body = json.loads(line)
        if "error" in body:
            raise Exception(body["error"])
        if body.get("done") is False:
            message = body.get("message", "")
            content = message.get("content", "")
            output += content
            # the response streams one token at a time, print that as we receive it
            print(content, end="", flush=True)

        if body.get("done", False):
            message["content"] = output
            return message


def main():
    messages = []
    while True:
        user_input = input("Enter a prompt: ")
        if not user_input:
            exit()
        messages.append({"role": "user", "content": user_input})
        message = chat(messages)
        messages.append(message)
        print("\n\n")

if __name__ == "__main__":
    main()

# OpenAI 介绍

# OpenAI API

  • Chat Completions 接口,适用于多轮对话,需构造 messages 列表
from openai import OpenAI

client = OpenAI(api_key="YOUR_API_KEY")

# 定义对话历史(包含系统指令、用户和AI的过往消息)
messages = [
    {"role": "system", "content": "你是一个专业的技术助手,用简洁的语言回答。"},
    {"role": "user", "content": "解释一下递归函数"},
    {"role": "assistant", "content": "递归函数是调用自身的函数,需有终止条件防止无限循环。"},
    {"role": "user", "content": "举一个Python例子"}
]

# 调用Chat接口
response = client.chat.completions.create(
    model="gpt-3.5-turbo",
    messages=messages,
    temperature=0.7
)

# 提取最新回复
reply = response.choices[0].message.content
print(reply)
  • Completions (Generate) 接口,适用于单次文本生成
from openai import OpenAI

client = OpenAI(api_key="YOUR_API_KEY")

# 直接输入prompt
prompt = "将以下英文翻译成中文:\n\n'Artificial intelligence is transforming the world.'"

response = client.completions.create(
    model="text-davinci-003",  # 经典文本生成模型
    prompt=prompt,
    max_tokens=50,
    temperature=0
)

result = response.choices[0].text.strip()
print(result)
  • Batch 接口,支持以文件方式批量提交任务并异步执行
import os
from pathlib import Path
from openai import OpenAI
import time

# 初始化客户端
# 阿里百炼平台介绍:
# https://help.aliyun.com/zh/model-studio/batch-interfaces-compatible-with-openai
client = OpenAI(
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"  # 阿里云百炼服务的base_url
)

def upload_file(file_path):
    print(f"正在上传包含请求信息的JSONL文件...")
    file_object = client.files.create(file=Path(file_path), purpose="batch")
    print(f"文件上传成功。得到文件ID: {file_object.id}\n")
    return file_object.id

def create_batch_job(input_file_id):
    print(f"正在基于文件ID,创建Batch任务...")
    # 请注意:此处endpoint参数值需和输入文件中的url字段保持一致
	# 测试模型(batch-test-model)填写/v1/chat/ds-test
	# Embedding文本向量模型填写/v1/embeddings,其他模型填写/v1/chat/completions
    batch = client.batches.create(input_file_id=input_file_id, 
	                              endpoint="/v1/chat/ds-test", 
								  completion_window="24h")
    print(f"Batch任务创建完成。 得到Batch任务ID: {batch.id}\n")
    return batch.id

def check_job_status(batch_id):
    print(f"正在检查Batch任务状态...")
    batch = client.batches.retrieve(batch_id=batch_id)
    print(f"Batch任务状态: {batch.status}\n")
    return batch.status

def get_output_id(batch_id):
    print(f"正在获取Batch任务中执行成功请求的输出文件ID...")
    batch = client.batches.retrieve(batch_id=batch_id)
    print(f"输出文件ID: {batch.output_file_id}\n")
    return batch.output_file_id

def get_error_id(batch_id):
    print(f"正在获取Batch任务中执行错误请求的输出文件ID...")
    batch = client.batches.retrieve(batch_id=batch_id)
    print(f"错误文件ID: {batch.error_file_id}\n")
    return batch.error_file_id

def download_results(output_file_id, output_file_path):
    print(f"正在打印并下载Batch任务的请求成功结果...")
    content = client.files.content(output_file_id)
    # 打印部分内容以供测试
    print(f"打印请求成功结果的前1000个字符内容: {content.text[:1000]}...\n")
    # 保存结果文件至本地
    content.write_to_file(output_file_path)
    print(f"完整的输出结果已保存至本地输出文件result.jsonl\n")

def download_errors(error_file_id, error_file_path):
    print(f"正在打印并下载Batch任务的请求失败信息...")
    content = client.files.content(error_file_id)
    # 打印部分内容以供测试
    print(f"打印请求失败信息的前1000个字符内容: {content.text[:1000]}...\n")
    # 保存错误信息文件至本地
    content.write_to_file(error_file_path)
    print(f"完整的请求失败信息已保存至本地错误文件error.jsonl\n")

def main():
    # 文件路径
    input_file_path = "test_model.jsonl"  # 可替换为您的输入文件路径
    output_file_path = "result.jsonl"  # 可替换为您的输出文件路径
    error_file_path = "error.jsonl"  # 可替换为您的错误文件路径
    try:
        # Step 1: 上传包含请求信息的JSONL文件,得到输入文件ID
		# 如果您需要输入OSS文件,可将下行替换为:input_file_id ="实际的OSS文件URL或资源标识符"
        input_file_id = upload_file(input_file_path)
        # Step 2: 基于输入文件ID,创建Batch任务
        batch_id = create_batch_job(input_file_id)
        # Step 3: 检查Batch任务状态直到结束
        status = ""
        while status not in ["completed", "failed", "expired", "cancelled"]:
            status = check_job_status(batch_id)
            print(f"等待任务完成...")
            time.sleep(10)  # 等待10秒后再次查询状态
        # 如果任务失败,则打印错误信息并退出
        if status == "failed":
            batch = client.batches.retrieve(batch_id)
			# 错误码文档: 
			# https://help.aliyun.com/zh/model-studio/developer-reference/error-code
            print(f"Batch任务失败。错误信息为:{batch.errors}\n")
            return
        # Step 4: 下载结果:如果输出文件ID不为空,则打印请求成功结果的前1000个字符内容
		# 并下载完整的请求成功结果到本地输出文件;
        # 如果错误文件ID不为空,则打印请求失败信息的前1000个字符内容
		# 并下载完整的请求失败信息到本地错误文件
        output_file_id = get_output_id(batch_id)
        if output_file_id:
            download_results(output_file_id, output_file_path)
        error_file_id = get_error_id(batch_id)
        if error_file_id:
            download_errors(error_file_id, error_file_path)
    except Exception as e:
        print(f"An error occurred: {e}")

if __name__ == "__main__":
    main()

# 参数说明

max_tokens
# 指令生成的回答中包含的最大token数。如果设置为100,那么模型中生成的回答中token数不会超过100个

temperature
# 控制文本生成的随机性和创意性。在0到1之间。值越大生成文本越随机;值越小生成文本越确定,一般0.7-1

n # 生成多个回答供选择。返回的数组结果

top_p(控制采样)
# 通过概率控制生成内容的多样性。确定生成本文时考虑的token累计概率。值在0-1之间,常用来替代温度设置

presence_penalty(出现惩罚\阻止调整)
# 鼓励生成新内容,避免出现重复内容。影响模型生成新主题内容的倾向,值在-2.0到2.0之间。
# 较高的值鼓励模型生成前面未出现过的新内容

frequency_penalty(频率惩罚、短语效应)
# 减少重复词语,提高输出的流畅度和多样性。值在-2.0到2.0之间
# 较高的值会减少模型重复使用某些词或短语的频率

stream
# 用于控制参数是否以流式方式接收生成的文本,流式输出意味着生成的文本会逐步发送,而不是一次性发送

# SSE 流式数据

  • FastAPI 流式数据返回
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
import json
import time
from typing import Generator

app = FastAPI()

def generate_json_data() -> Generator[str, None, None]:
    # 模拟生成大量数据的过程
    for i in range(10):
        # 每次返回一个 JSON 对象作为字符串
        data = {"index": i, "message": f"Data chunk {i}"}
        yield json.dumps(data) + "\n"
        time.sleep(1)  # 模拟延迟,表示流式数据的生成过程

@app.get("/stream-data")
async def stream_data():
    return StreamingResponse(generate_json_data(), media_type="application/json")

注意

不要开启中间件压缩功能:add_gzip_middleware(app)

  • 前端使用 Fetch
try {
    let response = await fetch('/api/admin/common/testStream');
    console.log(response);
    
    if (!response.ok) {
      throw new Error('Network response was not ok');
    }

    const reader = response.body.getReader();
    const textDecoder = new TextDecoder();
    let result = true;
    let output = ''

    while (result) {
      const { done, value } = await reader.read();

      if (done) {
        console.log('Stream ended');
        result = false;
        break;
      }

      const chunkText = textDecoder.decode(value);
      output += chunkText;
      console.log('Received chunk:', chunkText);
    }
} catch (e) {
  console.log(e);
}
  • 前端使用 Axios





 























try {
	await service.post('/abc', input, {
		responseType: 'stream',
		adapter: 'fetch',
	}).then(async(response)=>{
		// 经过响应拦截器service.interceptors.response后返回的 response是 response.data
		const reader = response.getReader();
		const textDecoder = new TextDecoder();
		let result = true;
		let output = ''

		while (result) {
		  const { done, value } = await reader.read();

		  if (done) {
			console.log('Stream ended');
			result = false;
			break;
		  }

		  const chunkText = textDecoder.decode(value);
		  output += chunkText;
		  console.log('Received chunk:', chunkText);
		}
	}
} catch (e) {
  console.log(e);
}

# RAG 的介绍

在大模型中,RAG 即检索增强生成,是一种将检索技术与语言模型生成能力相结合的技术

RAG架构

  • 原理
# 检索:RAG 首先会根据输入的问题或提示,从一个庞大的外部知识数据库或语料库中检索相关的信息片段
# 融合:将检索到的相关信息与语言模型已有的知识和上下文信息进行融合
# 生成:利用融合后的信息,语言模型生成更加准确、丰富和有针对性的回答或文本内容

# Embedding模型:核心作用是将文本、图像、音频等非结构化数据,转化为计算机可理解的向量数据,
                # 这些向量能保留原始数据的语义信息或特征关系
  • 优点
# 提高准确性:通过引入外部准确的知识,能有效纠正语言模型可能出现的错误,使生成的内容更符合事实
# 增强时效性:可以及时获取最新的信息并融入生成过程,让生成的文本能够反映最新的事件和知识
# 减少幻觉问题:语言模型有时会生成一些看似合理但实际上错误或无根据的内容
  • 应用
# 信息检索与问答系统:用户提问时 RAG 可以快速检索相关知识并生成准确回答,提供更优质的服务
# 内容创作:辅助写作者获取相关资料并生成更有深度和广度的文章、报告等,提高创作效率和质量
# 智能客服:使客服系统能够结合最新的产品信息、常见问题等知识,为用户提供更精准、有效的服务
  • 缺点
检索精度不足
# 首先,RAG 最核心的就是先将知识转换成"向量",导入"向量数据库"
# 然后在将用户输入的信息也转换成"向量",然后再去向量数据库匹配出相似的"向量"
# 最后再由大模型去总结检索到的内容
# 大模型仅仅起到了总结的作用,而检索到信息的精准度大部分情况下取决于向量的相似度匹配
# 检索结果可能包含无关内容(低精确率)或遗漏关键信息(低召回率)

生成内容不完整
# 由于 RAG 处理的是文档的切片,而切片的局部性注定了它无法看到整篇文档的信息
# 因此在回答诸如"列举XXX"、"总结XXX"等问题时,一般回答是不完整的

缺乏大局观
# RAG 无法判断需要多少个切片才能回答问题,也无法判断文档间的联系
# 例如,在法律条文中,新的解释可能覆盖旧的解释,但 RAG 无法判断哪个是最新的

多轮检索能力弱
# RAG 缺乏执行多轮、多查询检索的能力,而这对推理任务来说是必不可少的

注意

deepseek 不支持向量搜索(RAG),需要使用单独的向量模型

# MCP 的介绍

官网 (opens new window)

# Function Call 函数调用

# 以前的大模型像一个知识丰富但被困在屋里的人,只能靠已有知识回答问题,无法获取实时数据或与外界交互
# 比如不能直接访问数据库里的最新信息,也不能使用一些外部工具来完成特定任务

# Function Call 本质上就是提供了大模型与外部系统交互的能力,类似于给大模型安装一个 “外挂工具箱”
# 当大模型遇到自己无法回答的问题时,它会主动调用预设的函数(如查询天气、计算数据、访问数据库等)
# 获取实时或精准信息后再生成回答

# 虽然后续很多模型也支持了 Function Call 的调用,但是各自实现的方式都不太一样
# 如果要发开一个 Function Call 工具,需要对不同的模型进行适配,比如参数格式、触发逻辑、返回结构等

# MCP 模型上下文协议 Model Context Protocol

是由 Anthropic 公司(也就是开发 Claude 模型的公司)推出的一个开放标准协议,目的就是为了解决 AI 模型与外部数据源、工具交互的难题。

# MCP Host,比如 Claude Desktop、Cursor 这些工具,在内部实现了 MCP Client
# 然后 MCP Client 通过标准的 MCP 协议和 MCP Server 进行交互
# 由第三方开发者提供 MCP Server 负责实现各种资源交互的逻辑,比如访问数据库、浏览器、本地文件
# 最终再通过 标准的 MCP 协议返回给 MCP Client,最终在 MCP Host 上展示

MCP

# MCP 客户端(client)

支持了 MCP 协议的一些客户端/工具列表 (opens new window)里我们可以看到,MCP 对支持的客户端划分了五大能力

Tools  # 服务器暴露可执行功能,供 LLM 调用以与外部系统交互
Resources  # 服务器暴露数据和内容,供客户端读取并作为 LLM 上下文
Prompts  # 服务器定义可复用的提示模板,引导 LLM 交互
Sampling  # 让服务器借助客户端向 LLM 发起完成请求,实现复杂的智能行为
Roots  # 客户端给服务器指定的一些地址,用来告诉服务器该关注哪些资源和去哪里找这些资源

目前最常用,并且被支持最广泛的就是 Tools 工具调用

# MCP Server

就是通过标准化协议与客户端交互,能够让模型调用特定的数据源或工具功能,常见的 MCP Server 有:

文件和数据访问类 # 让大模型能够操作、访问本地文件或数据库,如 File System MCP Server
Web 自动化类 # 让大模型能够操作浏览器,如 Pupteer MCP Server
三方工具集成类 # 让大模型能够调用三方平台暴露的 API,如 高德地图 MCP Server

查找 MCP Server 的途径:

# 服务器通信机制

标准输入输出 stdio:# 用于 Server 和 Client 在同一台服务器,不支持远程连接
基于HTTP的服务器推送事件 SSE:# 用于 Server 和 Client 不在同一台服务器,支持远程连接

# 在 Cline 中测试使用

  • 内置的 MCP Server # 点击上方工具栏的 MCP Server 图标
  • 自己安装 MCP Server
# 点击 installed 按钮,然后点击下方的 Configure MCP Servers
# 打开了一个 JSON 文件,这就是 Cline 用于存放 MCP 配置的地方,里面只有一个空对象
# 每个 MCP Server 都会提供这份配置的写法,比如我们选择的 mcp-mongo-server
# 这里所说的在 Claude Desktop 中使用,其实在任何支持了 MCP 的客户端中都可以这样配置
{
  "mcpServers": {
    "mongodb": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-mongo-server",
        "mongodb://muhammed:kilic@mongodb.localhost/sample_namespace"
      ]
    },
    "mongodb-readonly": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-mongo-server",
        "mongodb://muhammed:kilic@mongodb.localhost/sample_namespace",
        "--read-only"
      ]
    },
    "mongodb-github": {
      "command": "npx",
      "args": [
        "-y",
        "github:kiliczsh/mcp-mongo-server",
        "mongodb://muhammed:kilic@mongodb.localhost/sample_namespace",
        "--read-only"
      ]
    }
  }
}
  • 配置看着挺复杂的,但实际上它提供了三种配置不同的写法,其实每个配置中只包含两个关键参数:
command # 指定在命令行中通过什么命令进行执行,此例中所有配置都使用 npx 命令,也就是 Node.js 环境
args    # 是一个数组,包含传递给 command 的参数

# 这三个配置的意思分别是:
mongodb # 运行 mcp-mongo-server npm 包,并且使用指定的 MongoDB 连接字符串,默认是读写模式
mongodb-readonly # 同样使用相同的 MongoDB 连接字符串,但这个配置会以只读模式运行
mongodb-github # 从 GitHub 上获取包来运行,而不是 npm 包,使用相同的连接字符串,并且也设置了只读
  • 我们使用其最简单的配置,本地 mongo 一般不会设置用户名密码,可以直接到客户端查看这个数据库的连接地址:
{
    "mongodb": {
      "command": "npx",
      "args": [
        "mcp-mongo-server",
        "mongodb://localhost:27017/studentManagement?authSource=admin"
      ]
    }
  }
}
  • 这个配置粘贴到 Cline 的 MCP 配置文件,然后我们发现左侧的 mongodb 绿灯亮起,说明配置成功
  • 最后测试使用,提问问题

# 通过 Prompt 优化查询效果

# MCP Server 为模型提供了访问数据库的能力,但是数据库的表结构对于模型还是完全黑盒的,模型只能靠猜
# 或者去先获取一下表结构,再进行后续操作,多获取一次表结构也会让回答速度变慢,以及消耗更多的 Token

# 所以这里有个优化技巧,我们直接在全局提示词里将表结构的关键信息,和我们的明确要求告诉模型
# 就能让模型更准确、高效的响应了,关于表结构的说明大家可以去用 DeepSeek 来生成

# 目前的局限性

# 切忌让 AI 检索过大的数据,因为这种方式不像 RAG,每次只检索一小部分需要的内容
# 它是真正的会执行 SQL,你要多少数据,就查多少数据
# 如果一次查询数据量过大,会让你消耗大量 Token,甚至让 MCP 客户端卡死

# 很多 MCP 客户端是依靠大量系统提示词来实现与 MCP 工具的通信
# 所以一旦使用 MCP,Token 的消耗量一定会大幅增长

# OpenSPG

# 知识图谱(Knowledge Graph)

是一种以图结构形式组织和表示知识的技术,它将现实世界中的实体(如人、地点、事件、概念等)以及它们之间的复杂关系以节点(实体)和边(关系)的形式构建成网络化的知识库。其核心目标是让机器能够理解和推理人类知识。

  • 核心组成
实体(Entities)
# 表示现实中的具体对象或抽象概念,例如“爱因斯坦”“北京”“量子力学”

关系(Relationships)
# 描述实体之间的联系,例如“爱因斯坦-出生地-德国”“北京-是-中国首都”

属性(Attributes)
# 实体的附加信息,例如“爱因斯坦-出生日期-1879年3月14日”
  • 典型应用
搜索引擎 # 直接展示答案而非链接,例如搜索“马斯克的公司”会显示特斯拉、SpaceX等
智能问答 # 通过图谱关系回答“姚明的妻子是谁?”
推荐系统 # 利用用户、商品、兴趣的关系网络实现精准推荐(如电商、影视平台)
金融风控 # 分析企业股权关系、担保网络识别风险
医疗诊断 # 链接疾病、症状、药物等知识辅助医生决策

# OpenSPG 简介

OpenSPG (opens new window) 是由蚂蚁集团与 OpenKG 社区联合推出的一款基于 SPG(Semantic-enhanced Programmable Graph,语义增强可编程图) 框架的知识图谱引擎。它融合了 LPG(Labeled Property Graph,带标签属性图) 的结构化优势和 RDF(Resource Description Framework,资源描述框架) 的语义表达能力,旨在解决传统知识图谱技术在工业级应用中的不足。

  • 工作原理
知识抽取   # KAG模块通过连接到各种数据源(如CSV文件、API等),使用预定义的提示(prompts)和大语言模型(LLM)进行知识抽取
图构建     # 抽取的知识通过SPG-Schema定义的模式进行结构化,构建为图数据库中的节点和关系
推理与查询 # Reasoner模块支持基于图的逻辑推理和查询,用户可以通过ISO GQL等查询语言进行复杂的图查询