Category Archives: Computer Science

科技是火,但举火把的还得是人—《未来科技大爆炸》

当作者汪诘的签名墨迹凝固在河北科学技术出版社2024年8月出版的《未来科技大爆炸》扉页时,这部360页的著作便属于科普读物的范畴,成为科技人文双重基因的书籍载体。作者以手术刀般的精确解剖量子计算、基因编辑、人工智能等八大前沿领域,却始终让理性的锋芒包裹着人文的温润内核。全书59.8元的定价背后,是多个数学公式与多幅技术原理图的硬核支撑——从薛定谔方程诠释量子机制,到用模型演示碱基编辑的分子剪刀,这种拒绝娱乐化稀释的写作姿态,在当下轻科普泛滥的语境中构筑起知识传播的防波堤。

封面上“洞悉机遇,先人一步看懂未来”的题词,恰是全书思想脉络的微缩图谱。作者以三重架构编织知识网络:基础层用香农定理拆解5G通信的熵增困境,实践层援引Neuralink 2023年脑机接口临床数据剖析神经解码精度,哲思层则提出震动业界的“意识阈值假说”——当算法决策复杂度突破10¹⁵次浮点运算量级时,是否触发道德主体性的质变临界点。这种从技术原理到文明叩问的纵深推演,使豆瓣84%的高星评价(40%五星+44%四星)成为其内容厚度的客观映证。正如书中对LK-99室温超导复现失败的技术归因,真理的沉重永远高于流量的轻盈。

签名本的收藏价值远不止于笔墨痕迹的物质留存。当指尖抚过扉页凸起的墨迹,油墨渗透纸张纤维的过程恰与书中纳米材料“自组装技术”形成微观互文;手写体与印刷字的质感差异,则暗合“人机协同进化”的辩证命题。这种将签名转化为科技隐喻的巧思,使珍藏版成为理解作者科普美学的密钥——他笔下的量子纠缠不仅是量子比特的叠加态,更是爱因斯坦与玻尔思想碰撞的哲学涟漪;对脑机接口的论述既包含运动皮层电极阵列的神经电生理学分析,也追问当意识可被数字化上传时,“我”的边界如何在硅基载体中重构。

书中五大预测已启动验证周期。关于“2026年量子纠错突破50个逻辑量子比特”的预言,谷歌Quantum AI团队在2024年10月宣布实现32量子比特逻辑门操控;对“基因疗法单价降至10万美元”的测算,诺华Zolgensma价格曲线符合其建立的成本模型;最具争议的“2030年强人工智能或引发监管革命”论断,已成为欧盟AI法案修订的核心议题。这种基于严谨模型的预测能力,彰显硬核科普的实践品格。

相较于作者前作《时间的形状—相对论史话》,本书在科技时效性上实现显著跃迁:OpenAI Sora模型的时空扩散原理被拆解为Transformer架构的多模态训练范式,量子霸权章节则更新了谷歌Sycamore处理器2024年最新基准测试。但真正的突破在于思想维度——作者创造性地提出“科技爆炸的熵增悖论”:技术迭代的加速反而增大了系统性崩溃风险,正如核聚变控制与核扩散威胁始终是同一枚硬币的两面。这种将元胞自动机模型应用于文明演化模拟的尝试,使科普写作升格为未来哲学宣言。

当晨光穿透签名页的纤维间隙,碳元素在纸面投射出树影般的微观结构。这部重达612克的平装本,实则是称量人类未来的精神砝码。作者用360页的厚度筑起一道堤坝——左边奔涌着技术乐观主义的洪流,右边沉淀着文明忧患意识的礁石。而那些凝固在扉页的蓝色墨迹,恰似航向未知星海的曲率引擎喷流:在确定性公式与不确定性未来的永恒张力中,为所有敢于直视科技光芒的探索者,刻下属于这个时代的认知坐标。

在算法统治认知的喧嚣时代,这部装载人类智慧火种的平装本恰似对抗信息熵增的“麦克斯韦妖”。当读者凝视扉页签名中凝固的碳基墨水痕迹,或许能听见科技洪流中理性与人文的永恒对位:那些严谨的公式不仅是通向未来的密码,更是文明在星海中航行的罗盘。

《AI Agent 开发与应用:基于大模型的智能体构建》

在人工智能飞速发展的今天,智能体(Agent)无疑是技术前沿的重要组成部分。从个人生活助手到企业智能客服,智能体的应用已经逐步渗透到我们日常工作的方方面面。这本《AI Agent开发与应用:基于大模型的智能体构建》无疑为开发者、技术爱好者和学术研究者提供了一个系统的框架,不仅帮助我们理解智能体的内涵,更提供了从基础到高级的开发技巧与实用案例,是一本不可多得的理论与实践相结合的优秀书籍。

智能体的深远意义

首先,我们不妨从智能体的定义谈起。智能体(Agent)是一种能够自主进行感知、决策和执行任务的系统。无论是在个人层面的虚拟助手,还是在企业层面的自动化服务,智能体都已经成为智能化转型的重要推动力。在个人生活中,AI Agent扮演着无处不在的角色,如语音助手Siri、Alexa,它们能够理解语音命令,执行任务,甚至提供个性化推荐。而在企业层面,智能体同样是企业提升工作效率、降低运营成本的重要工具。例如,企业级智能客服可以通过自动化的方式解答客户咨询,节省了大量人力资源,提高了服务效率。

随着大模型(LLM)的兴起,智能体的能力得到了前所未有的增强。大语言模型赋予了智能体强大的自然语言理解与生成能力,使其能够更精准、更灵活地与用户进行多轮对话,并有效地处理复杂的任务。与此同时,智能体与API、数据库的深度集成,使其可以访问并处理海量的数据,快速响应用户需求。

《AI Agent开发与应用:基于大模型的智能体构建》概览

《AI Agent开发与应用:基于大模型的智能体构建》以深入浅出的方式,从智能体的基础理论出发,逐步引导读者进入智能体开发的世界。全书共分为三个部分,涵盖了智能体的基础原理、开发工具与技术框架、应用案例以及高阶开发技巧,内容丰富而详尽。

第1部分:初见智能体

在第一部分的前几章中,作者首先清晰地定义了智能体的概念,探讨了智能体的核心组件与架构,以及智能体如何与大语言模型(LLM)结合。这一部分的重点在于帮助读者全面理解智能体的工作原理,并掌握智能体的开发流程。通过对智能体类型的介绍,我们得以窥见智能体在各个行业中的广泛应用,尤其是大语言模型赋能智能体的强大能力,带来了更高效的任务自动化和更智能的决策支持。

第2部分:智能体基础应用开发

第二部分的内容主要通过实际的应用案例,帮助读者理解智能体在实际开发中的实现过程。比如,在出行订票系统和智能翻译系统的开发中,作者详细阐述了如何利用LangChain等技术框架构建一个多任务的智能体模型,以及如何处理复杂的多语言、多轮对话场景。通过这些实际案例的剖析,读者不仅能掌握智能体开发的基础,还能获得实际的编程技巧与开发经验。

第3部分:智能体深度开发

第三部分深入探讨了智能体在实际应用中的深度开发技巧。从智能邮件助理到智能面试助手,书中通过具体的功能设计与技术实现,展示了如何构建一个高效的智能体,帮助读者了解如何在智能体中集成LLM、如何优化多轮对话管理、如何进行个性化推送等复杂的应用场景。特别是对于智能体个性化学习与优化的探讨,提供了更高阶的开发技术,帮助开发者在实际工作中提升智能体的智能化水平。

人工智能对生活与工作的重塑

从本书的内容中,我们不难看出,AI Agent的开发不仅仅是为了实现单一任务的自动化,更是在构建一个全面、智能、高效的服务体系。无论是个人日常的智能助手,还是企业后台的自动化决策系统,AI Agent都能通过无缝连接与多任务处理,解放人力,提升效率,推动各行各业的智能化转型。

AI Agent的核心意义,在于其能够解构复杂任务,自动学习与适应用户需求,从而不断提升服务质量。通过自然语言处理、情感分析、行为预测等技术,智能体能够形成个性化、精准的服务方案,满足不同用户的需求。例如,智能面试助手能够通过简历分析与行为数据,自动评估候选人,提供更加客观的面试评价;智能客服则可以在电商平台中自动解答用户咨询,大幅降低人工成本的同时提升客户满意度。

总结

总体来说,《AI Agent开发与应用:基于大模型的智能体构建》不仅为开发者提供了完整的技术框架和实用的开发方法,还深入探讨了AI Agent在实际生活和工作中的应用场景。作者凌峰博士凭借其扎实的学术背景和丰富的开发经验,将这本书写得既富有理论深度,又紧密结合实践,为读者提供了全面的学习指南。

对于那些希望深入了解人工智能、特别是智能体开发的人来说,这本书无疑是一本宝贵的参考资料。它不仅是技术开发者的必读书籍,更适合那些想要进入AI应用领域,尤其是大模型应用的开发人员和研究者。通过本书的学习,读者不仅能掌握AI Agent的基础理论和应用技术,还能拓宽视野,掌握智能体在各行各业中的深度应用,助力实现数字化转型的愿景。

这本书的出版,标志着人工智能技术,尤其是智能体技术的进一步普及与深入,也为未来AI Agent的开发提供了丰富的思想启迪与实践经验,是一本值得反复阅读与实践的好书。

《大模型RAG应用开发:构建智能生成系统》

在人工智能的浪潮中,生成式模型已经从学术研究进入到实际应用的领域。而在这其中,检索增强生成(RAG)技术作为一种创新性的突破性方法,正在逐步改变我们对信息获取与内容生成的理解。对于开发者、数据科学家以及所有致力于人工智能应用开发的人来说,《大模型RAG应用开发:构建智能生成系统》是一本不可或缺的宝贵资源,它不仅深入浅出地解读了 RAG 技术的核心概念、工作原理,还通过细致的案例展示了如何将这一技术应用于各个行业,为智能生成系统的构建提供了丰富的实践指导。

RAG:智能生成的前沿之路

在深入了解这本书之前,我们首先需要清楚什么是 RAG 技术。RAG,全称“Retrieval-Augmented Generation”,是将传统生成模型与信息检索技术结合的一种新型架构。与传统的纯生成式模型不同,RAG通过检索与生成的协同工作,不仅能够提高生成内容的质量,还能在处理实时、动态的信息时展现出巨大的优势。通过检索相关的外部知识,RAG系统能够在生成内容时引入最新、最相关的上下文信息,极大提升生成模型的实际应用能力。

在传统的生成式AI中,模型主要依赖于预训练时学习到的知识。然而,随着数据的迅速变化和信息的不断更新,预训练模型的固有局限性显而易见。RAG的出现,正是对这一瓶颈的有效突破。通过集成检索模块,RAG不仅能够查询外部知识库,还能根据实时需求生成更为精确和符合时效性的内容,避免了传统生成模型无法处理最新信息的局限。

知识库的重要性

无论是个人知识库还是企业知识库,它们在RAG系统中都占据着至关重要的位置。在 RAG 的应用场景中,知识库不仅是信息检索的源泉,更是生成内容质量的保障。个人知识库可以帮助用户通过简洁、智能的方式快速获取自己曾经积累的知识,而企业知识库则通过整合全公司范围内的文档、报告、邮件等内容,为企业决策者提供可靠的信息支持,帮助企业提高工作效率。

对于开发者而言,理解和构建一个高效的知识库是开发RAG应用系统的基石。书中对如何构建与优化向量数据库进行了深入的阐述,特别是在数据向量化与FAISS开发方面,提供了极为详细的步骤与技术细节。从数据清洗、向量化到向量检索的实现,每一步都紧密结合RAG应用中的实际需求。这些内容不仅帮助读者更好地理解向量数据库的构建过程,还为那些需要进行大规模数据处理与检索的应用开发提供了宝贵的经验与方法。

书籍内容的深入解读

《大模型RAG应用开发:构建智能生成系统》一书的第一大亮点,就是其系统全面地讲解了RAG技术的开发流程。书中的第1至第3章,重点介绍了RAG开发的基础内容,包括 Python 开发环境的搭建、Faiss 常用工具与模块的使用以及智能体的基本概念。对于初学者来说,这些内容可以帮助他们从零开始建立 RAG 系统的基本框架,理解其背后的技术原理。

而从第4章开始,书籍进入了 RAG 应用的具体开发过程。如何构建高效的检索增强模型,如何在开发中引入 FAISS 和 Transformer 等工具,以及如何优化检索结果以提高生成内容的准确性和一致性,这些细致的步骤和技术详解无疑为开发者提供了极大的帮助。特别是在第9至第11章,书中通过企业文档问答系统、医疗文献检索系统和法律法规查询助手等实际案例,让读者能够深入理解 RAG 技术在不同领域的具体应用,为今后的开发与实践提供了极为宝贵的参考。

对行业的深远影响

随着大模型的不断演进,RAG 技术的应用场景也在不断扩展。从企业内部知识管理,到医疗、法律等专业领域的智能辅助,RAG 系统正在成为一种新的行业标准。在医疗文献检索系统的开发过程中,RAG 不仅帮助医生更快地获取准确的医学文献,还通过生成模块提供精确的答案,节省了大量的查询和信息处理时间;在法律法规查询助手的开发中,RAG 通过对法规文本的向量化处理,帮助用户快速查找到相关法规条款,并结合上下文生成具有法律效力的解释,极大提升了法律工作者的工作效率。

随着大模型和 RAG 技术的不断普及,未来更多行业可能会在知识检索与生成内容的结合上产生革命性的变化。RAG不仅能帮助企业高效管理知识库,还能实现实时信息检索与智能内容生成,为企业提供精准、及时的决策支持。

总结

《大模型 RAG 应用开发:构建智能生成系统》是一本既具备理论深度,又具备实践操作性的技术书籍。它不仅详细讲解了 RAG 技术的基础概念和开发流程,还通过丰富的案例和具体的技术实现,帮助读者深入理解RAG 在各行各业中的应用价值。对于 RAG 技术初学者、大模型研发人员,以及数据分析和挖掘工程师等读者来说,这本书无疑是一本不可多得的指导书。

无论是在个人知识库的建设,还是在企业级智能生成系统的开发中,RAG 技术都展示了其巨大的潜力。随着 AI 技术的快速发展,未来的应用场景将更加广泛,RAG 将继续为智能生成和知识检索的结合开辟新的天地,而这本书,则为我们提供了走向这一未来的最强指南。

时间序列新范式:通过合成数据将时间序列与大语言模型对齐,以增强理解和推理

1. ChatTS概述

ChatTS: Aligning Time Series with LLMs via Synthetic Data for Enhanced Understanding and Reasoning 这篇文章是清华大学、字节跳动与必示科技三方共同创作而成。

在实际的工作中,时间序列在运维领域中占据着非常重要的地位,尤其是近些年大语言模型(LLM)的发展,极大地推动了时间序列这一领域的发展。这篇论文介绍了一个叫做ChatTS的模型,它是专为时间序列分析设计的新型多模态大语言模型(MLLMs)。为缓解训练数据稀缺问题,作者们提出基于属性的合成时间序列生成方法,可自动生成具有详细属性描述的时序数据。同时,作者们创新性地提出时间序列演化式指令生成方法(Time Series Evol-Instruct),通过生成多样化时序问答对来增强模型的推理能力。ChatTS是首个以多元时间序列作为输入,并进行理解和推理的时间序列多模态大语言模型,且完全基于合成的数据集微调。作者们在包含真实数据的基准数据集上开展评估,涵盖6项对齐任务和4项推理任务。

实验结果表明,ChatTS在对齐任务中提升46.0%,在推理任务中提升25.8%,其代码的官方链接是: https://github.com/NetManAIOps/ChatTS,HuggingFace的官方链接是:https://huggingface.co/bytedance-research/ChatTS-14B/tree/main ,模型的权重都可以在HuggingFace上面直接下载并使用。

用一个实际的例子来说明这个情况,那就是用户可以针对某个KPI曲线进行提问,并咨询是否有其他曲线存在了波动,然后并提问根因,大语言模型(LLM)进行了回答。

从图2的描述来看,如果要将多条时间序列进行输入,其实可以至少有四种方法可以执行:

  1. Text-Based:将多条时间序列整理成具体的数值,然后一次性输入给大模型进行分析和输出;
  2. Agent-Based:不同的时间序列输入给不同的大模型,然后一次性汇总之后进行汇总大模型LLM的处理和输出;
  3. Multimodal Vision-Based:将时间序列处理成图片信息,然后通过多模态大模型进行处理和分析,然后输出结果;
  4. Multimodal TS-Based:将多条时间序列的数值直接输入大模型,开发一个Time Series Multimodal LLM并做输出。

ChatTS的亮点是将多维时间序列直接作为输入,然后进行推理和分析。目前是一个14B的模型,它是在QWen2.5-14B-Instruct的基础上进行微调的,其开源代码使用也很简单,可以参考下面的代码:

from transformers import AutoModelForCausalLM, AutoTokenizer, AutoProcessor
import torch
import numpy as np

# Load the model, tokenizer and processor
model = AutoModelForCausalLM.from_pretrained("./ckpt", trust_remote_code=True, device_map=0, torch_dtype='float16')
tokenizer = AutoTokenizer.from_pretrained("./ckpt", trust_remote_code=True)
processor = AutoProcessor.from_pretrained("./ckpt", trust_remote_code=True, tokenizer=tokenizer)
# Create time series and prompts
timeseries = np.sin(np.arange(256) / 10) * 5.0
# 构造异常的时间序列取值
timeseries[100:] -= 10.0
prompt = f"I have a time series length of 256: <ts><ts/>. Please analyze the local changes in this time series."
# Apply Chat Template
prompt = f"<|im_start|>system\nYou are a helpful assistant.<|im_end|><|im_start|>user\n{prompt}<|im_end|><|im_start|>assistant\n"
# Convert to tensor
inputs = processor(text=[prompt], timeseries=[timeseries], padding=True, return_tensors="pt")
# Move to GPU
inputs = {k: v.to(0) for k, v in inputs.items()}
# Model Generate
outputs = model.generate(**inputs, max_new_tokens=300)
print(tokenizer.decode(outputs[0][len(inputs['input_ids'][0]):], skip_special_tokens=True))

如果是使用vLLM推理的话,可以参考这份代码:

import chatts.vllm.chatts_vllm
from vllm import LLM, SamplingParams
# Load the model
language_model = LLM(model="./ckpt", trust_remote_code=True, max_model_len=ctx_length, tensor_parallel_size=1, gpu_memory_utilization=0.95, limit_mm_per_prompt={"timeseries": 50})
# Create time series (np.ndarray) and prompts (chat_templated applied)
ts1, ts2 = ...
prompt = ...
# Model Inference
outputs = language_model.generate([{
      "prompt": prompt,
      "multi_modal_data": {"timeseries": [ts1, ts2]}
  }], sampling_params=SamplingParams(max_tokens=300))

2 ChatTS方法论

2.1 模块划分

从论文的介绍来看,ChatTS的数据模块大概可以分成以下几个情况:

  1. Attribute Selector:属性选择器,主要用于精准的属性选择,方便生成满足这些属性的时间序列;属性包括趋势类(稳定趋势、上升趋势、下降趋势等),周期类(三角函数、正方形、无周期等),局部波动类,是否存在噪声等类别。
  2. Attribute-Based Time Series Generator:基于属性的时间序列生成器,可以使用规则的方法进行生成;
  3. Time Series Evol-Instruct:时间序列演化式指令,用于生成大量的、多样的、精准的时间序列,并且有相应的文本回答,属于一个(time series,text question-answer)的信息;
  4. 模型设计(model design):使用了多维时间序列作为数据的输入;
  5. 模型训练(model training):使用了监督微调(SFT,Supervised Fine-Tuning)的方法,在已有模型的基础上进行了微调;

整体的流程可以参考下图的方法:通过选择不同的属性,生成不同的样本数据,以及相应的问题和答案。

同样的,时间序列的相应指令可以参考下图:

2.2 模型微调

而在模型微调的时候,需要将时间序列和文本进行分别输入,按照一定的格式进行编码,其中包括对时间序列的解释,以及相应的问题和答案。

而ChatTS的样本训练大约是万这个量级,在现有模型的基础上即可微调出不错的结果。

ChatTS的训练可以在QWen2.5-14B-Instruct的基础上进行两阶段的微调,包括大尺度的微调训练(large-scale alignment training)和监督微调(SFT)。具体的问答案例可以参考图8的内容。

模态对齐训练阶段

在第一阶段,我们使用基于属性的合成时间序列数据进行大规模对齐训练,以建立大语言模型中文本与时序模态的初步对齐。此阶段使ChatTS能够有效实现文本描述与时序属性的语义映射。在模态对齐阶段,通过手工设计模板和LLM精炼构建了三个训练数据集:

  • UTS(单变量时间序列)数据集 :包含单变量时序基础属性描述任务(涵盖全局与局部属性分析);
  • MTS-Shape(多元形态)数据集 :由具有全局趋势相关性的多元数据构成,旨在增强模型分析多元相关性的能力;
  • MTS-Local(多元局部)数据集 :包含局部波动相关的多元数据,重点提升模型对多元时序局部特征的分析能力;

鉴于多元时序(MTS)具有更复杂的特征组合,我们将MTS与UTS的训练数据规模设定为约2:1的比例(具体训练数据规模对模型性能的影响详见第4.5节的数据集扩展研究)。

监督微调阶段

在第二阶段,通过监督微调(SFT)开发模型执行复杂问答与推理任务的能力。该阶段主要使用两类训练数据:

  • TSEvol生成数据集 :通过时间序列演化式指令生成方法(Time Series Evol-Instruct)构建,用于增强模型对时序问题的问答推理能力;
  • 指令遵循(IF)数据集 :基于预定义模板构建,专门训练模型遵循特定响应格式;

对于TSEvol方法,我们使用对齐训练阶段的数据集配合LLM生成的问答对作为种子数据。通过联合训练,使多模态大语言模型能够精准响应时序领域查询,并强化其处理上下文驱动的复杂推理任务的能力。在模态对齐和监督微调阶段,我们通过系列数值任务系统提升ChatTS的数值分析能力,包括:极值识别、分段均值计算、局部特征提取(如尖峰位置/幅度)、季节性与趋势振幅分析、以及单点原始数值解析。实验结果中的数值评估指标验证了ChatTS在时序数值分析方面的卓越性能。

训练配置

  • 数据格式:两阶段均采用问答对格式。在模态对齐阶段混入少量IF数据以缓解指令遵循能力退化;
  • 防止过拟合策略:SFT阶段混30%对齐训练数据集;
  • 时序长度覆盖:训练数据包含64-1024长度的时序序列,确保模型处理变长时序的能力;
  • 训练框架:基于DeepSpeed和LLaMA-Factory [65]进行全参数监督微调,基础模型选用Qwen2.5-14B-Instruct;
  • 推理环境:Qwen与ChatTS均采用DeepSpeed框架部署。

3 ChatTS评估方法

3.1 数据的评估

本节通过回答以下研究问题(research questions)全面评估ChatTS的性能:

  • RQ1:ChatTS与时序数据的对齐效果如何?
  • RQ2:ChatTS在时序推理任务中的表现如何?
  • RQ3:基于属性的合成数据与TSEvol方法是否有效?
  • RQ4:训练集规模如何影响模型性能?
  • RQ5:ChatTS的时序模态设计是否真正发挥作用?
  • RQ6:ChatTS的原生时序多模态能力是否优于代理型方法?

参照多模态大语言模型通用评估范式,我们将评估任务分为两类:

  1. 对齐任务(验证文本-时序语义映射):(1)单变量任务:趋势识别、季节性检测、噪声分析、局部波动分析(含分类与数值子任务)(2)多元任务:相关性分析、聚类分析(均为分类任务)
  2. 推理任务(验证时序逻辑推演能力) (1)归纳推理:问答任务,对单/多元时序物理意义进行归纳总结(2)演绎推理:判断题(T/F),基于预设条件与单变量时序进行逻辑推演(3)因果推理:选择题,根据单变量时序选择最可能诱因(4)比较推理(MCQ2):选择题,对比两组时序选择正确答案

评估指标可以使用相对准确率:

验证数据集采用以下数据:

从模型的数据效果来看,相对其他开源模型和API的使用结果来看,ChatTS都获得了不错的数据表现:

3.2 实战的评估

除了理论上的应用之外,ChatTS还可以用于各种实际的场景,例如形状与统计值分析:

可以进行数据库的失效分析:

还支持时间序列数据的细节分析:

4 ChatTS论文总结

针对时间序列理解与推理领域长期存在的跨模态数据稀缺难题,本文提出首个支持多元时序输入的多模态大语言模型ChatTS,开辟了基于合成数据的时序语义对齐新模式,核心贡献体现在三个维度:

  1. 首创属性驱动的时序合成引擎,通过参数化建模生成兼具多样性和精确标注的时序-文本对,突破真实数据标注成本限制;
  2. 开发时序演化式指令生成框架(TSEvol),融合属性组合推理与Evol-Instruct机制,构建出覆盖复杂推理场景的20.8万高质量QA对;
  3. 建立多维度评估体系,在包含真实场景的跨领域数据集上验证模型性能,在时序对齐任务(F1=0.823)和因果推理任务(Acc=78.4%)上分别实现46.0%和25.8%的绝对性能提升,显著超越GPT-4o等基线模型。本研究不仅证实了合成数据在跨模态学习中的可行性,更为时序分析范式从传统特征工程向语义理解跃迁提供了技术基础设施,相关代码、模型及数据集已在GitHub开源。

这些成果验证了该方法在弥合时间序列数据与自然语言理解鸿沟方面的有效性。作者们已开源源代码、训练模型权重及评估数据集以供复现和后续研究:https://github.com/NetManAIOps/ChatTS。

LangChain核心技术与LLM项目实践

作为一名正在学习大语言模型(LLM)技术的开发者,我一直在寻找能够帮助我深入理解并高效运用这些前沿技术的书籍。幸运的是,最近我偶然得到了《LangChain核心技术与LLM项目实践》这本书以及相应的其他书籍,经过一段时间的阅读,我发现这本书不仅内容丰富、技术全面,而且从基础到高级的层次设计让我在学习过程中逐渐从理论走向实战,真正收获颇丰。

从基础到高级,逐步推进

这本书以零基础为起点,循序渐进地展开内容。第一章通过对大语言模型的基本概念及其应用场景的介绍,为我打下了扎实的理论基础,尤其是对于LangChain的优势和广泛应用做了清晰的说明。作为初学者,能够从这里开始,逐步接触到模型的基本架构和其潜力,感受到了学习的信心。

随后的章节则将LangChain的各个功能模块一一拆解,层层推进。从如何导入模型、优化Prompt模板,到如何设计任务链、管理内存模块等,每一章都配有详实的代码示例和详细的应用场景分析。特别是第3章到第6章,通过提示词工程等大量的实战案例,我能够在动手实践中逐渐掌握如何将这些技术应用到实际的开发中,真正理解每一个核心技术的背后原理。

 

核心技术的深入剖析

本书的亮点之一是对LangChain核心技术的深入剖析。例如,第7章深入讲解了LangChain的表达式语言和并行处理技巧。通过代码示例,我学会了如何通过简洁的语法提高数据处理效率,这对处理大规模数据任务来说至关重要。而第8章则让我对Agent系统有了更深的理解,书中详细分析了不同类型的Agent系统及其如何处理多任务,使我能够构建更加智能化、自动化的应用。

尤其是在回调机制的讲解上,书中通过真实的案例帮助我掌握了如何自定义回调函数,实时监控任务进展并处理异常情况。这样的技术不仅提升了系统的灵活性,也使得开发过程中更加可控。通过这些深入的技术分析,我对LangChain的内在机制有了更为清晰的认识,也为将来在项目中的应用奠定了坚实的基础。

企业级智能应用的构建与优化

本书的第10章和第11章,更是让我看到了LangChain在企业级应用中的巨大潜力。特别是在模块化开发与系统集成领域,书中详细讲解了如何利用LangChain的模型I/O和数据检索技术来提升企业级解决方案的效率和可靠性。结合实际的企业应用场景,作者还提出了如何进行性能优化、复杂查询处理和任务链设计的高级技术,这对我来说无疑是一次眼界大开的技术洗礼。

从实践中获得真知灼见

《LangChain核心技术与LLM项目实践》的最大亮点在于最后的第12章,它将前11章的知识点与实战相结合,带领读者实现一个完整的企业级智能问答系统。通过这个完整的项目案例,我不仅学会了如何进行需求分析、架构设计,还从代码实现中感受到了如何将理论知识落地到实际应用。这个实战环节是我学习过程中最有价值的一部分,因为它不仅帮助我巩固了所学的技术,更让我从实践中发现了不少开发中的问题和解决方案。

一本不可多得的学习宝典

整体来说,《LangChain核心技术与LLM项目实践》是一本无论是对初学者还是对有一定经验的开发者都非常有价值的书籍。它系统地讲解了LangChain的核心技术,并通过大量的代码示例和实际场景,帮助读者将知识转化为实践能力。尤其是本书的章节安排十分合理,既注重理论的讲解,又兼顾了项目的实操,非常适合像我一样想深入学习并实践LangChain技术的开发者。如果你对大语言模型和LangChain有兴趣,或者正在从事相关技术的开发工作,那么这本书绝对是一本不容错过的佳作。通过它,你可以在学习过程中积累丰富的实践经验,为未来的智能化应用开发打下坚实的基础。

Pytest:Python测试的利器

在Python的测试生态中,pytest无疑是一颗耀眼的明星。它以简洁、灵活和强大的功能深受开发者喜爱。无论是小型项目的单元测试,还是大型系统的集成测试,pytest 都能提供良好的支持。本文将从多个方面介绍pytest的特性,并总结其优势与常见用法。

1. 为什么选择 pytest?

在 Python 标准库中,unittest提供了基本的单元测试功能,符合 xUnit 测试架构风格。然而,随着项目复杂度的提升和测试需求的增长,开发者往往希望有一个更加轻量、直观并易于扩展的测试工具。pytest 正是在这种背景下应运而生,它以其更简洁的语法、更人性化的断言机制和强大的插件支持,逐渐成为 Python 测试的主流选择。

相比 Python 自带的 unittest 模块,pytest 提供了更简洁的语法、更丰富的断言能力以及强大的插件系统。例如,使用 pytest 可以直接编写函数式测试,不必将测试代码包装成类。其断言语句也更加直观,不需要调用 assertEqual、assertTrue 等繁琐方法,直接使用 assert 语句即可自动生成详细的错误报告。

1.1 语法简洁,测试函数式写法更直观

假设现在使用的脚本的名称叫做 learn_pytest_1.py。在 unittest 中,编写测试必须继承 unittest.TestCase 并将测试方法命名为 test_ 开头,形式如下:

# 使用 unittest 的写法
import unittest

def add(x, y):
    return x + y

class TestAdd(unittest.TestCase):
    def test_add(self):
        self.assertEqual(add(1, 2), 3)
        self.assertEqual(add(-1, 1), 0)

这段代码在 PyCharm 中的运行结果就是:

而在 pytest 中,可以直接写函数式的测试,不需要类结构,语法更加自然:

# 使用 pytest 的写法
def add(x, y):
    return x + y

def test_add():
    assert add(1, 2) == 3
    assert add(-1, 1) == 0

这种简化不仅减少了模板代码,也更贴近 Python 的编程风格,其结果展示如下:

1.2 断言机制更强大

在 unittest 中,必须使用专门的断言方法,如 assertEqual、assertTrue 等,每种判断场景都需要一个对应的方法:

self.assertIn(item, container)
self.assertIsInstance(obj, SomeClass)
self.assertAlmostEqual(a, b, places=2)

而 pytest 只需要使用 Python 原生的 assert 语句。最关键的是,pytest 会在断言失败时自动分析表达式内容,生成详细的错误信息。例如:

def test_example():
    a = 5
    b = 3
    assert a + b == 10

如果失败,pytest 输出类似如下信息:

>       assert a + b == 10
E       assert 8 == 10
E        +  where 8 = (5 + 3)

而 unittest 仅提示 AssertionError: 8 != 10,缺乏上下文,调试成本更高。

1.3 测试发现机制更灵活

unittest 通常需要手动添加测试套件或使用 python -m unittest discover 来运行,而 pytest 则具有自动发现功能,只需执行 pytest 命令即可自动查找所有以 test_ 开头的函数或方法,并运行之。无需配置即可开箱即用。

2. 安装与基本用法

2.1 安装 pytest

pytest 支持 Python 3.7 及以上版本,可以通过 pip 一键安装:

pip install pytest

如果你希望安装测试覆盖率工具等附加功能,可以使用组合命令:

pip install pytest pytest-cov

建议在虚拟环境中安装以避免依赖冲突。创建虚拟环境的方法如下:

python -m venv venvsource venv/bin/activate  # Windows 下为 venv\Scripts\activatepip install pytest

2.2 测试文件与函数命名规范

为了让 pytest 自动发现测试文件和函数,需遵循以下命名规则:

测试文件名:以 test_ 开头或 _test.py 结尾,如:

  • test_math.py

  • calculator_test.py

测试函数名:以 test_ 开头,如:

  • def test_add():

  • def test_subtract():

示例代码:

# 文件名:test_sample.py

def multiply(x, y):
    return x * y

def test_multiply():
    assert multiply(2, 3) == 6
    assert multiply(-1, 5) == -5

运行的结果如下所示:

2.3 运行测试

只需在包含测试文件的目录下执行 pytest 命令,pytest 会递归扫描所有子目录中的符合规范的测试文件并运行。

pytest

运行后,你会看到类似以下输出。

============================= test session starts ==============================
collected 2 items

test_sample.py ..                                                     [100%]

============================== 2 passed in 0.01s ===============================

其中,. 表示有一个测试通过,.. 表示有两个测试通过。

2.4 常用命令选项

pytest 提供了丰富的命令行参数,可以灵活控制测试行为:

运行指定文件或目录

pytest tests/            # 运行 tests 目录下所有测试pytest test_math.py      # 运行指定文件

运行指定测试函数

pytest test_math.py::test_add

显示更详细的输出信息

pytest -v

只运行上次失败的测试

pytest --lf

生成覆盖率报告(需要安装 pytest-cov):

pytest --cov=my_package tests/

停止在第一个失败的测试

pytest -x

2.5 测试结构推荐(项目组织)

对于中小型项目,可以采用以下结构:

my_project/
├── src/
│   └── my_module.py
├── tests/
│   ├── __init__.py
│   └── test_my_module.py
└── requirements.txt

可以在 tests/ 目录中编写所有测试脚本,通过 pytest tests/ 来集中运行。

2.6 测试失败时的调试

pytest 提供了失败断点和调试钩子,可以在测试失败时立即进入调试模式:

pytest --pdb

或者,在测试代码中显式加入 import pdb; pdb.set_trace() 进行调试。

3. 进阶功能

3.1 Fixtures:高效的测试准备与清理

在实际的测试中,往往需要对某些资源(如数据库连接、文件操作、网络请求等)进行初始化,并在测试完成后清理这些资源。pytest 提供了 Fixtures 来帮助我们管理这些过程,尤其在多次运行的测试中,可以有效避免重复代码。

3.1.1 基本用法

使用 @pytest.fixture 装饰器可以创建一个 Fixture。Fixture 通常返回一个资源或对象,供测试函数使用。

import pytest

# 定义一个 fixture,提供测试用的字典
@pytest.fixture
def sample_data():
    return {"name": "Alice", "age": 30}

# 测试函数通过参数使用 fixture
def test_user_name(sample_data):
    assert sample_data["name"] == "Alice"

def test_user_age(sample_data):
    assert sample_data["age"] == 30

在这个例子中,sample_data 是一个 Fixture,它提供一个字典对象,供测试函数 test_user_name 和 test_user_age 使用。pytest 会自动将 sample_data 传递给测试函数。

3.1.2 Fixture 作用域

Fixture 支持不同的作用域,这意味着可以控制 fixture 生命周期的长短,具体有四种作用域:

  • function:函数级,每个测试函数都会调用一次该 fixture(默认值)。
  • class:类级别,每个测试类调用一次该 fixture。
  • module:模块级别,每个测试模块调用一次该 fixture。
  • session:会话级别,整个测试会话只调用一次该 fixture。
import pytest

@pytest.fixture(scope="module")
def db_connection():
    print("\nSetting up database connection")
    conn = create_db_connection()
    yield conn
    print("\nTearing down database connection")
    conn.close()

在这个示例中,db_connection fixture 会在模块级别共享,且只会在整个模块执行前后各调用一次。这对于需要在多个测试函数间共享的资源非常有用。

3.1.3 自动化 Fixture

如果不想显式地在每个测试函数中传入 fixture,可以通过 pytest 的自动化机制来实现。例如,可以通过 autouse=True 参数让 pytest 自动注入 fixture,而无需在测试函数中显式引用:

import pytest

@pytest.fixture(autouse=True)
def setup_env():
    print("\nSetting up test environment")
    yield
    print("\nTearing down test environment")

3.2 参数化测试:一行代码跑遍所有情况

pytest 提供了强大的参数化功能,使得我们可以一次性测试多个输入组合,从而避免编写大量重复的测试代码。

3.2.1 基本用法:@pytest.mark.parametrize

使用 @pytest.mark.parametrize 装饰器,我们可以在一个测试函数中传入多个不同的参数组合,pytest 会为每一组数据运行一次测试。

import pytest

@pytest.mark.parametrize("a,b,expected", [
    (1, 2, 3),
    (2, 3, 5),
    (10, 20, 30)
])
def test_add(a, b, expected):
    assert a + b == expected

在这个例子中,test_add 会被执行三次,分别使用 (1, 2, 3)、(2, 3, 5) 和 (10, 20, 30) 这三组参数来验证加法操作。

3.2.2 参数化与 Fixtures 结合

你还可以将 pytest.mark.parametrize 与 Fixtures 结合,进行更加灵活的测试设计。例如,你可以使用一个 fixture 来准备数据,再对不同数据组合进行测试:

import pytest

@pytest.fixture
def input_data():
    return [1, 2, 3]

@pytest.mark.parametrize("x, y", [(1, 2), (2, 3), (3, 4)])
def test_add(input_data, x, y):
    assert x + y in input_data

这里,input_data fixture 提供了一个列表,pytest.mark.parametrize 会让测试用例分别使用 (1, 2)、(2, 3) 和 (3, 4) 进行测试,同时验证结果是否在 input_data 列表中。只有第一个案例 (1, 2) 通过了测试。

3.2.3 参数化测试与预期异常

pytest.mark.parametrize 同时支持测试预期的异常。例如,某个函数在特定输入下会抛出异常,可以通过 pytest.raises 配合 @pytest.mark.parametrize 来进行验证:

import pytest

@pytest.mark.parametrize("input_value", ["a", "", None])
def test_invalid_string(input_value):
    with pytest.raises(ValueError):
        process_string(input_value)

在这个例子中,test_invalid_string 会测试不同的无效输入,检查是否会抛出 ValueError 异常。

3.2.4 参数化大数据集

如果需要测试一个非常大的数据集,pytest 支持通过数据驱动的方式快速生成多个测试用例,而不会让每个数据都显式地写出来。可以结合生成器来实现:

import pytest

@pytest.mark.parametrize("num", range(100))
def test_large_dataset(num):
    assert num % 2 == 0  # 示例断言:测试数字是否为偶数

上面的测试将会对 0 到 99 之间的数字逐一进行验证。

4. 插件生态与工具集成

pytest 之所以成为 Python 社区主流的测试框架,不仅在于其核心功能强大,更重要的是拥有一个活跃、丰富的插件生态系统,几乎可以适配所有常见的测试场景。同时,它也具备极强的兼容性,可以轻松与主流的 CI/CD 工具集成,实现自动化测试流水线。

pytest 拥有丰富的插件生态,常用插件包括:

  • pytest-cov:测试覆盖率报告;
  • pytest-mock:与 unittest.mock 的集成;
  • pytest-xdist:并行测试,加快执行速度;
  • pytest-django、pytest-flask:与 Web 框架集成。

此外,pytest 与 CI/CD 工具(如 GitHub Actions、GitLab CI、Jenkins)结合良好,是自动化测试的重要组成部分。

4.1. 常用插件介绍

4.1.1 pytest-cov:测试覆盖率分析

pytest-cov 是基于 coverage.py 的插件,用于生成测试覆盖率报告。使用方式如下:

pip install pytest-covpytest --cov=my_module tests/

它可以输出命令行摘要,也可以生成 HTML 报告:

pytest --cov=my_module --cov-report=html

生成的 htmlcov/index.html 可在浏览器中打开,直观查看哪些代码行未被测试覆盖,是测试优化的重要工具。

4.1.2 pytest-mock:更便捷的 mock 工具

虽然 Python 的标准库 unittest.mock 功能很强,但书写稍显繁琐。pytest-mock 提供了 mocker fixture,可以更简洁地进行打桩和模拟:

pip install pytest-mock

示例:

def get_user_name():
    return external_api.get_name()

def test_mock_name(mocker):
    mock = mocker.patch("external_api.get_name", return_value="Alice")
    assert get_user_name() == "Alice"

无需手动清理 mock,pytest-mock 会自动恢复原状,避免副作用。

4.1.3 pytest-xdist:并行化测试执行

在测试用例较多或测试时间较长的项目中,使用 pytest-xdist 可以显著加快测试执行速度。它支持多核并发运行测试,还可以分布式运行。

pip install pytest-xdist
pytest -n auto      # 根据 CPU 核心数自动并发
pytest -n 4         # 指定使用 4 个 worker 并行

它还能结合缓存机制和失败重试,提高测试效率和稳定性。

4.1.4 与 Web 框架集成:pytest-django、pytest-flask 等

对于 Web 项目,pytest 有专门的插件与主流框架深度集成:

  • pytest-django:为 Django 提供 fixture(如 db、client)、命令行选项(如 –reuse-db)和数据库隔离支持。
  • pytest-flask:提供 client、app 等内置 fixture,方便进行 HTTP 请求测试。
  • pytest-fastapi:结合 Starlette 的测试客户端,对 FastAPI 路由和中间件进行端到端测试。

安装方式也很简单,例如:

pip install pytest-django

配置示例(pytest.ini):

[pytest] DJANGO_SETTINGS_MODULE = myproject.settings 然后在测试中即可使用 Django 的测试数据库:

def test_homepage(client):
    response = client.get("/")
    assert response.status_code == 200

4.2 与 CI/CD 工具集成

pytest 与持续集成工具(CI/CD)天然兼容,支持标准输出、退出码和测试报告格式,使其易于与各类流水线对接。

4.2.1 GitHub Actions

GitHub Actions 是一种流行的 CI/CD 工具,可以通过 YAML 配置文件轻松集成 pytest 测试流程:

# .github/workflows/test.yml
name: Run Tests

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.11'
      - run: pip install -r requirements.txt
      - run: pytest --cov=my_project --cov-report=xml

也可结合 codecov 插件上传测试覆盖率报告到云端展示。

4.2.2 GitLab CI

在 GitLab 中,使用 .gitlab-ci.yml 文件配置测试流程:

test:
  image: python:3.11
  script:
    - pip install -r requirements.txt
    - pytest --junitxml=report.xml
  artifacts:
    paths:
      - report.xml

配合 GitLab 的测试报告视图,可以直观展示测试结果和失败原因。

4.2.3 Jenkins、CircleCI、Travis CI 等

这些工具也都支持运行 pytest 测试脚本,只需配置对应的构建步骤即可。同时,pytest 的插件生态与这些平台兼容性好,支持输出 XML、HTML 等报告格式,便于集成持续部署、邮件通知等功能。

pytest 的强大不仅来自本身的灵活性和易用性,更在于其生态系统的完善。有助于扩展功能(如 mock、并行、覆盖率等),可与各种 Web 框架无缝集成;易于对接主流 CI/CD 工具链,助力自动化测试。得益于这些特性,pytest 能满足从简单脚本测试到大型项目持续交付的一整套需求,是构建现代 Python 测试体系的核心工具。

5.  Pytest 最佳实践总结

随着项目规模和复杂度的增加,良好的测试习惯不仅能提升开发效率,还能显著提高代码质量。以下是使用 pytest 过程中积累的一些实用经验和最佳实践建议。

5.1 测试代码要易读、结构清晰

  • 将测试文件和源代码分别组织在 tests/ 和 src/(或 my_project/)目录下;
  • 每个模块应有对应的测试文件,测试函数的命名应具有描述性;
  • 使用一致的命名风格,如:test_functionName_condition_expectedResult();
  • 对复杂测试场景,适当拆分多个小测试函数,而非写一个超长的测试用例。

示例结构:

project_root/
├── src/
│   └── calculator.py
├── tests/
│   └── test_calculator.py
├── pytest.ini
└── requirements.txt

 

5.2 充分利用 fixtures 管理上下文和资源

  • 避免在每个测试中重复初始化数据;
  • 利用 fixture 的作用域(function、module、class、session)优化资源复用;
  • 多个 fixture 之间可以组合使用;
  • 使用 yield 语法处理前置设置和清理逻辑;
  • 将常用 fixture 抽取到 conftest.py 中,供所有测试共享。

示例(conftest.py):

import pytest

@pytest.fixture(scope="module")
def temp_file(tmp_path_factory):
    file = tmp_path_factory.mktemp("data") / "test.txt"
    file.write_text("example")
    return file

5.3 用参数化减少重复测试代码

  • @pytest.mark.parametrize 能显著减少样板代码;
  • 如果数据量大、来源复杂,可以结合生成器或外部数据源(如 CSV、JSON);
  • 测试函数的参数顺序和数据格式需保持一致,避免位置混乱;
  • 参数组合时可以使用笛卡尔积或 pytest_cases 插件进一步优化。

5.4 灵活使用标记(markers)组织测试

使用 @pytest.mark 可以对测试用例分组、打标签、控制运行策略:

  • @pytest.mark.slow:标记为慢测试;
  • @pytest.mark.api:标记为 API 测试;
  • @pytest.mark.skipif(…):基于条件跳过测试;
  • @pytest.mark.xfail:标记预期失败的用例(用于待修复 Bug);

并通过命令行选择运行特定标记:

pytest -m "slow"

可以在 pytest.ini 中注册自定义标记:

[pytest] markers = slow: marks tests as slow api: marks API-related tests

5.5 编写失败时易于调试的断言

  • 避免模糊的布尔断言(如 assert foo),应写清楚期望结果;
  • 利用 assert 的详细错误消息功能;
  • 对复杂结构(如字典、对象、JSON)断言时尽量分步检查;
  • 使用 pytest.raises 明确断言异常及异常类型。

例子:

with pytest.raises(ValueError, match="Invalid input"):
    func_that_should_fail("bad input")

5.6 保持测试原子性和无副作用

  • 每个测试用例应独立运行,不依赖其他测试的运行结果;
  • 测试应可重复运行,避免全局状态污染;
  • 对外部依赖(如数据库、网络)应使用 mock 或 fixture 隔离;
  • 临时文件、目录应使用 tmp_path、tmpdir 等内置 fixture 管理。

5.7 与覆盖率和静态分析工具配合

  • 每次运行测试时附带覆盖率统计:
pytest --cov=my_project --cov-report=term-missing
  • 使用 pytest-cov 生成 HTML 或 XML 报告,配合 CI 展示;
  • 搭配 flake8、mypy、pylint 等工具进行代码静态检查。

5.8 集成 CI/CD 流水线自动执行测试

  • 在 push、pull request 或 merge 操作时自动触发 pytest;
  • 将测试失败作为构建失败条件,确保代码质量;
  • 可结合 coverage、pytest-html、junitxml 输出结果报告供平台读取。

5.9 编写测试计划和测试用例文档

虽然 pytest 本身不要求文档化测试,但良好的测试设计仍然重要:

  • 为复杂功能设计测试矩阵(输入、输出、边界、异常);
  • 维护每个模块的测试用例说明,便于团队协作;
  • 对关键路径(核心算法、接口调用)优先覆盖。

5.10 善用社区资源和插件

  • 官方插件列表:https://docs.pytest.org/en/stable/plugins.html;
  • 第三方插件如:
    • pytest-randomly:打乱测试顺序,发现隐藏依赖;
    • pytest-html:生成测试 HTML 报告;
    • pytest-sugar:美化命令行输出;
  • 经常关注插件更新,可能会有意想不到的提升。

6. 总结

pytest 是一个功能强大、使用方便的 Python 测试框架。它不仅适合初学者快速入门,也能满足专业团队在大型项目中的复杂测试需求。借助其清晰的语法、丰富的扩展能力和良好的工具支持,pytest 成为现代 Python 开发中不可或缺的一环。如果你还在使用冗长的 unittest 写测试,不妨尝试一下 pytest,它可能会改变你对测试的看法。

7.  参考资料

  1. 官方文档:https://docs.pytest.org/en/stable/index.html
  2. GitHub链接:https://github.com/pytest-dev/pytest

用 ima 搭建你的 AI 大脑:职场、创作、学习、教学的效率提升利器

在信息爆炸时代,真正的竞争力在于如何将碎片知识转化为可调用的智慧。使用 AI 智能工作台  ima.copilot,正以“个人知识库”为核心,重塑打工人和学生人群的工作流。ima 知识库不仅仅是存储,更是让知识流动、协作与增值的智能引擎,重塑信息时代的核心竞争力。

💼  一、职场人:告别文件沼泽,打造高效决策引擎

  • 痛点:职场人最常见的一种情况就是项目文档散落聊天工具/邮箱/本地/云盘,每次到使用的时候就找不到相关文件,同时关键信息在短时间内找不到也想不起来放在哪里了,然后每次不想找的时候,文件又再次自动出现了。
  • ima解法
    ✅ 一键聚合:微信公众号的文章、聊天文件、本地 PDF、Word、PPT 直接入个人知识库,自动解析摘要和核心内容;
    ✅ 智能问答:输入“2023年Q4商业报告核心结论”,ima 秒调知识库内容生成答案,并且根据知识库进行精确回答内容,有理有据;
    ✅ 团队协作:一个小的团队可以构建共享知识库,在同一个共享知识库中同步项目资料,通过严格的权限管理确保信息安全。

✨ 案例:某产品经理将竞品分析/用户反馈存入知识库,需求评审时直接提问调用数据,效率提升50%。

✍️ 二、自媒体人:从素材堆积到灵感喷发

  • 痛点:笔者已经写了数十年的博客,但是博客都散落在知乎、微信公众号、个人网站甚至 GitHub 上面。每次要想找某一篇博客的时候,都需要去各个平台上去看一眼,并且十年前写的知识并没有做很好的知识扭转,没有那种常见常新的感觉,就像是写完了之后就放在那里了而已。同时,对于自媒体创作者人而言,很容易出现的情况就是写作思路的枯竭,同时还收藏百篇爆文,在写作时仍无头绪。
  • ima 解法
    ✅ AI盘活素材:通过 ima 入库的公众号文章自动打标签,输入搜索主题自动关联案例,并会给出相应的答案和链接;
    ✅ 创作加速器:基于知识库生成提纲、润色文案,支持多语言翻译功能;
    ✅ 爆款分析:提问“标题技巧”,ima 从知识库中提炼方法论,自媒体创作人可以在现有的知识库中进行提炼和二次开发。

✨ 案例:博主将100+爆文存入 ima,创作时调用“金句库”,选题耗时减少70%。

🎓 三、学生党:把文献海洋变成结构化知识

  • 痛点:学生党的学习资料和论文资料杂乱,逻辑梳理耗神,而且文件夹的管理会混乱,很多时候也会出现找不到学习资料的情况。
  • ima 解法
    ✅ 文献秒读:上传 PDF 自动生成脑图/摘要,外文文献即时翻译;
    ✅ 精准问答:“对比AB测试理论差异”直接定位知识库相关内容;
    ✅ 复习利器:错题集存入知识库,考前智能生成测验题,可以有效地提升复习的效率和质量。

✨ 案例:研究生用 ima 管理文献,论文写作时提问调取关联观点,效率翻倍。

👩‍🏫 四、教师:从重复答疑到智慧教学

  • 痛点:每一个学生都是独立的个体,存在重复提问的现象,备课资料难共享。
  • ima 解法
    ✅ 教学资源库:课件/试卷/论文/外网资料统一入库,按标签进行合理的分类;
    ✅ AI助教:将知识库嵌入公众号,学生提问自动答疑(如“奖学金政策”、“考试准备技巧”、“错题库整理”);
    ✅ 集体备课:共享知识库同步教研资料,AI 自动生成教案/习题。

✨ 案例:高校教师用 ima 搭建课程知识库,学生咨询量下降 80%,备课时间节省 40%。


🔑 为什么 ima 能成为“越用越聪明”的 AI 大脑?

  • 动态进化:通过用户对个人知识库或者团队持续更新,AI 回答精准度随使用提升;
  • 跨端联动:PC 客户端深度创作 + 小程序碎片收集 + App 随时调用;
  • 双核驱动:混元大模型 + DeepSeek-R1 双引擎策略,专业与通用场景兼顾。

🌟 现在行动
1️⃣ 访问 ima.qq.com 下载客户端; 
2️⃣ 微信搜索“ima知识库”小程序,5秒导入微信收藏;
3️⃣ 创建你的第一个知识库,开启“提问即得答案”的智能时代!

《时间序列与机器学习》出版一周年:开启数据分析新篇章

在这个数据泛滥的时代,如何从海量信息中提炼出真正有价值的知识,成为了企业、机构以及科学研究的核心命题。而时间序列数据,作为一种随时间推移而变化的数据类型,因其在互联网、金融、气象等领域的广泛应用,逐渐成为数据科学的明星。无论是金融市场的波动预测,还是气象变化的趋势分析,时间序列数据无时无刻不在影响着我们的决策与生活。而在这些数据的背后,隐藏着无穷的宝藏,等待着我们通过有效分析与深度挖掘来释放其潜力。

在过去的几年里,随着计算能力的飞速提升、数据量的急剧增长以及学习算法的不断成熟,人工智能,尤其是机器学习技术,迅速崛起,成为了各行业发展的驱动力。无论是自动化预测、异常检测,还是数据挖掘与分析,机器学习都展现出了巨大的潜力。而在这个浪潮中,像 ChatGPT 这样的大语言模型更是为人们打开了人工智能的新天地,令技术发展进入了一个新的热潮。

正因如此,两年前我们决定将我们多年的技术积淀与实践经验,编纂成书,分享给更多对时间序列与机器学习充满兴趣的读者。作者们在多个一线机器学习项目中,积累了大量关于时间序列的经验,涉及的应用领域包括异常检测、趋势预测、根因分析等。平时,我们也将一些心得和技术总结发布为帖子,与大家分享。然而,写书的过程远比我们想象中的要艰难。机器学习和深度学习的技术更新日新月异,每一次技术的进步都可能让我们感到内容的滞后。此外,日常工作繁忙也让我们很难抽出足够的时间来全身心投入创作。尽管如此,最终,我们还是克服了重重困难,完成了这本书的编写,希望能为广大读者提供一份理论与实践并重的参考资料。

《时间序列与机器学习》是一本系统梳理与总结时间序列分析及机器学习应用的著作,旨在帮助读者全面了解这一领域。书中共分为八个章节,内容覆盖从时间序列分析的基础知识,到高阶的异常检测、预测、聚类分析,再到智能运维和金融领域的具体应用。每一章不仅深入讲解了相关的理论知识,还通过案例分析,展示了这些技术如何在实际场景中得以应用。无论是对刚刚接触时间序列分析的初学者,还是在这一领域已有一定经验的研究人员,本书都能提供启发与指导。

作为时间序列分析与机器学习的爱好者和实践者,我们深知这一领域的复杂与挑战,但也正是这种挑战,激发了我们在知识积累和实践探索中的无限动力。通过本书的编写,我们不仅希望帮助读者掌握时间序列分析的技巧,更希望能够激发更多人投身到这个充满创新与机遇的领域。虽然这本书可能并不完美,但我们诚恳地希望,它能为大家提供一份系统的知识结构和实践的参考,也期待各位专家和读者给予批评与建议,帮助我们不断进步。

过去的一年,是充满挑战与收获的一年,也是我们对人工智能、时间序列与机器学习领域理解不断深化的一年。今天,站在书籍出版一周年的节点上,我们满怀感激与期待,诚挚地邀请您一同踏上这段学习之旅。让我们一起探索数据背后的规律,发掘隐藏在时间序列中的智慧,开启属于我们的数据分析新时代。

希望这本书能够成为您通往更高领域的桥梁,成为您走向数据科学深处的指南。

提示词工程(Prompt Engineering)

1.  提示词工程简介

1.1 提示词工程的定义

提示词工程(Prompt Engineering)主要围绕如何有效地与人工智能(AI)模型进行互动,尤其是在生成式人工智能(如ChatGPT、GPT-4、DeepSeek等大语言模型)中的应用。简单来说,提示词工程是指如何设计、优化、调整输入给AI模型的提示词(Prompt),从而获得最有效、最准确的输出。对于AI模型来说,提示词就像是一把钥匙,它打开了模型的思维,帮助引导模型生成特定类型的回应或解决方案。

随着人工智能技术,尤其是自然语言处理(Natural Language Processing,NLP)领域的快速发展,提示词工程逐渐成为技术工作者、产品经理和研究人员需要掌握的技能之一。在实践中,优秀的提示词能够帮助用户更好地引导模型,获得高质量、符合需求的输出,从而提升工作效率,解决复杂的问题。

1.2 提示词工程的核心内容

提示词工程的核心内容包括但不限于以下几个方面:

  1. 提示词的设计与优化: 提示词工程的核心任务是设计出能够引导AI模型生成特定输出的有效提示词。不同的提示词结构、用词、语境都会对AI模型的输出产生不同影响。为了使AI模型生成准确、符合需求的内容,提示词设计需要精确、简洁,并尽可能涵盖输入内容的所有关键要素。例如,在询问一个开放式问题时,提示词应该包含足够的背景信息和问题的方向;而在进行任务指令时,提示词则需要明确告诉AI该做什么。通过不断地优化提示词,可以提高输出结果的质量和相关性。
  2. 语境和意图: 理解并传达问题的语境和意图是提示词工程中非常重要的一部分。AI模型的理解能力在很大程度上取决于用户提供的背景信息和上下文。因此,设计提示词时要确保其能够清晰地传达问题的意图,并提供相关的背景信息。例如,假如你希望AI生成一篇关于人工智能的文章,你应该在提示词中明确说明文章的主题、风格、长度等要求,而不仅仅是简单地说“写一篇人工智能的文章”。
  3. 语言模型的特性: 不同的语言模型有不同的特点和限制。例如,GPT-4在处理长文本时具有较强的能力,但它也可能在复杂的逻辑推理任务中出现一定的偏差。因此,提示词工程不仅仅是要清楚地定义任务,还要根据AI模型的特点进行调整和优化,以便获得最好的结果。
  4. 模型训练与迭代: 在实际应用中,提示词工程并非一蹴而就的任务。随着AI技术的发展,模型不断得到改进和更新,因此,提示词的设计和使用也需要不断地迭代和调整。这是因为新的AI模型可能对提示词的响应方式发生变化,原有的设计方式可能不再有效。

1.3 提示词工程的应用场景

  1. 内容创作: 提示词工程可以帮助内容创作者生成各种类型的文本,例如博客文章、社交媒体内容、产品文案等。通过优化提示词,创作者可以更精准地引导AI生成符合品牌风格、语气和受众需求的内容。比如,你希望生成一篇关于“未来科技”的博客文章,可以通过提供详细的提示词(例如文章的结构、重点、受众群体)来帮助AI提供更具创意的内容。
  2. 数据分析与报告生成: 数据科学家和分析师常常使用AI模型来快速生成报告、分析摘要或趋势预测。通过设计清晰明确的提示词,分析师可以让AI快速从大量数据中提取出关键信息,并生成相关的分析报告。
  3. 教育与培训: 在教育领域,提示词工程可以用于生成练习题、教材内容和解题思路等。例如,教师可以根据学生的学习进度和需求,设计提示词来生成个性化的学习材料和辅导内容,帮助学生巩固知识、提高理解力。
  4. 客户服务与支持: 在客服领域,提示词工程可以帮助AI生成精准的客户支持回答。企业可以根据常见问题和服务需求,设计适合的提示词,从而使AI能够快速提供精准的解决方案,提升客户体验。在客服场景下,AI 大语言模型可以给用户一些解决方案,相对之前检索问题的方式已经优化了很多。
  5. 代码生成与开发: 对于程序员而言,可以在开发过程中利用提示词工程来生成代码片段、调试方案、撰写测试用例和完善技术文档。例如,开发者可以通过提供详细的提示词(例如编程语言、功能需求)来帮助AI生成特定的代码,减少程序员的重复劳动,提高个人的开发效率。在某些场景下,程序员甚至可以跨界编程,例如前端程序员去撰写一部分后端代码,后端程序员来处理一些数据分析,数据分析工程师还可以来撰写简单地前端代码。但这只是特殊情况下的特殊处理方式,还是专业的人士干专业的事情会比较好。

1.4 提示词工程的发展历程

从提示词工程的发展历程来看,AI 模型经历过结构化的输入等一系列过程,直到现在的提示词工程的样式。

2.  提示词工程的使用

提示词工程的方法有很多,包括但不限于零样本学习、少样本学习、思维链、思维树、RAG、ReAct等内容。本文将介绍其中的部分知识,以启发大家在与大模型交互的过程中的提示词工程方法。

2.1 简单使用

如今的提示词工程的入门也十分简单,直接就可以通过对话的方式与 AI 进行沟通和交流。形如下述格式,用户写一段文本信息或者一句简短的话,模型就可以输出相应的内容。

如果用户觉得上述内容不够完善,有两种常见的方式进行解决。第一种是提供更多的信息(A clearer and more precise prompt),包括上下文的消息、网站最新消息和更加精确的指令,当 AI 接收到这些消息和指令的时候,输出的内容就会更加完善与精确;第二种方法是角色扮演(Role prompting example),就是假设你是一个某某方向的专家,并且在输入的时候告知 AI 模型,AI 模型就会自动承担这个专家的角色并进行内容的输出。

2.2 Zero-shot、One-shot、Few-shot

Zero-shot学习指的是模型在没有见过任何与特定任务相关的示例数据的情况下,直接执行该任务。简单来说,就是零样本学习。在Zero-shot学习中,模型依赖其在预训练阶段获得的知识,能够根据输入的指令或描述,完成没有直接训练过的任务。

One-shot学习指的是模型在处理任务时,仅需一个示例来理解任务并进行执行。换句话说,模型通过一个示例就能“学会”如何完成任务,并可以在此基础上继续进行类似任务的推理,就是单样本学习。

Few-shot学习指的是模型通过少量的训练示例来完成任务。通常,few-shot学习会提供比One-shot更多的示例(通常在3到10个之间),使得模型能够更好地理解任务的规律和要求,就是少样本学习

学习方式示例数任务依赖适用场景
Zero-shot无示例无需任何任务特定的训练数据适用于任务描述明确且模型具备足够语言理解能力的情况。常见于机器翻译、情感分析等任务。
One-shot1个示例只需要一个任务相关示例适用于能够通过单个示例就能明白任务要求的情境,适合小规模示例或人脸识别等任务。
Few-shot少量示例(3-10个)需要少量示例来理解任务适用于需要一些实例来更好推理的任务,适合文字分类、图像识别等问题。

下图表示了zero-shot和one-shot的提示词工程,AI 模型输出的答案是不一样的。

2.3 思维链Chain of Thought

2.3.1 思维链的定义

Chain of Thought(思维链) 是一种在人工智能尤其是大语言模型中使用的推理方法,目的是在通过逐步展开的推理过程来帮助模型解决复杂问题,特别是需要逻辑推理或多步骤计算的问题。传统的语言模型通常依赖于直接输入问题,并立即给出回答,但这有时会导致回答不够精确或存在错误。Chain of Thought方法则通过引导模型分步骤思考,逐渐推导出答案,从而提高推理的准确性和透明度。思维链(Chain of Thought)可以理解为逐步推理,它是通过将复杂问题拆解成多个小步骤,让模型逐步生成每个步骤的思考过程,最终得出正确的结论。这个过程类似于人类在解决问题时的思维过程:首先分析问题,考虑各种可能性,然后逐步推理出答案。

2.3.2 思维链的工作原理

  1. 问题分解:Chain of Thought方法要求模型将一个复杂问题分解成多个较为简单的子问题或推理步骤。每个步骤都帮助模型理清思路,逐步逼近最终答案。
  2. 逐步推理:每一步推理的结果会作为下一步推理的依据。这种逐步展开的推理过程能帮助模型减少直接回答时可能遇到的错误或遗漏。
  3. 最终输出:通过逐步推理,模型最终得出一个合理的答案,这个答案通常更符合逻辑,也更有说服力。

2.3.3 思维链的案例

假设我们有一个数学问题,我们用思维链的方式进行输入:

问题:如果今天是星期三,那么五天后是星期几?

传统的语言模型可能会直接给出“星期一”的答案,但它的推理过程可能并不清晰。使用Chain of Thought方法时,模型会像这样逐步推理:

  1. 第一步:今天是星期三。
  2. 第二步:明天是星期四。
  3. 第三步:后天是星期五。
  4. 第四步:再过两天是星期六。
  5. 第五步:再过一天是星期天。

最终,模型得出结论:五天后是星期一

通过这种逐步推理,模型的思维过程变得更加透明,也更容易让人理解。

下面是一个标准的提示词输入模式:

下面是一个思维链(Chain of Thought)的提示词输入模式,在提示词中明确输入按步骤思考和解决

2.4 思维树Tree of Thought

2.4.1 思维树的定义

Tree of Thought(思维树) 是一种新的推理方法,它在传统的Chain of Thought(思维链)基础上进一步扩展,旨在帮助大语言模型进行更复杂的推理和决策。与线性逐步推理的Chain of Thought不同,Tree of Thought通过将推理过程分支化,允许模型在多个可能的推理路径中进行探索,并根据不同的分支选择最佳路径,从而得到更加准确和丰富的答案。

Tree of Thought可以理解为一个多分支的推理过程,它在一个问题的解决过程中产生多个并行的推理路径,并通过评估这些路径来选择最优解。这种方法特别适合于复杂的决策问题、长时间推理过程或需要考虑多个可能性的问题。

相比之下,Chain of Thought是一种线性推理方法,每一步推理依赖于前一步的结果。而Tree of Thought通过“树形”结构,在推理过程中创建多个分支,允许模型在不同的路径中进行探索和评估。这种多路径的推理方式更贴近人类解决问题时的思维过程,人类在面对复杂问题时,往往会考虑多个解决方案,并根据实际情况选择最佳的路径。

2.4.2 思维树的工作原理

  1. 分支化推理: 在Tree of Thought中,模型会为每个推理步骤生成多个候选答案或路径。例如,在解决一个问题时,模型可能会产生不同的推理路径,每个路径代表着一种不同的推理思路。
  2. 路径评估: 一旦模型生成了多个推理路径,它会评估这些路径的有效性和正确性。评估可以基于已有的知识库、上下文信息或者特定的评价标准来进行。
  3. 选择最优路径: 在所有可能的推理路径中,模型会选择最符合问题要求的路径,从而得到最终的解答。这个过程类似于“树形搜索”,通过遍历不同的路径并根据评估进行选择。
  4. 输出结果: 最终,模型会根据选择的最佳路径输出问题的解答。

2.4.3 思维树的案例

假设我们有一个问题:

问题:一个农场有20只羊和30只鸡。每只羊有4条腿,每只鸡有2条腿。农场一共有多少条腿?

使用Chain of Thought的方法,模型可能会按以下步骤逐步推理:

  1. 每只羊有4条腿,20只羊一共是20 * 4 = 80条腿。
  2. 每只鸡有2条腿,30只鸡一共是30 * 2 = 60条腿。
  3. 80 + 60 = 140条腿。

这是一个线性推理的过程,步骤是顺序进行的。

但使用Tree of Thought时,模型可能会通过多个不同的推理路径来解决问题。比如:

  • 路径一:计算所有羊的腿数:20 * 4 = 80。计算所有鸡的腿数:30 * 2 = 60。最终加总得到腿数:80 + 60 = 140。
  • 路径二:计算每种动物的腿数,并进行逐步分组:羊有20只,每只羊有4条腿,总腿数为80。鸡有30只,每只鸡有2条腿,总腿数为60。结合不同的动物类型,总结出腿数为140。

Tree of Thought方法能够同时处理多个推理路径,然后比较这些路径的效果,最终选择一个最合适的答案。在复杂的推理任务中,模型可能会根据不同的推理方向探索多个分支,最终确定最佳解答。

2.5 知识的生成和RAG技术

LLM 继续得到改进,其中一种流行的技术是能够融合知识或信息,以帮助模型做出更准确的预测。

知识生成的案例,需要明确说出2个关键分析和3个关键影响因子等指令,AI模型就可以生成以下的对话内容:

而在知识生成的过程中,提供一个知识库在很多时候就是一种必要的措施。通过构建个人或者团队的知识库,可以有效地提升回答的能力,而检索信息增强(RAG)就是一种非常有效的方式,用一句话来总结就是:

RAG(中文为检索增强生成) = 检索技术 + LLM 提示

与通用的生成式AI最大的区别,就是RAG增加了知识库的检索技术,通过检索的方式极大地提升了回答的准确率。

而RAG常见的运作方式就包括以下几步,其中资料的质量就是非常关键的一步。

Step 1:资料收集,为AI检索奠定基础:首先,收集AI所需的学习资料,例如FAQ、产品型录、新人训练手册等,为后续的资料处理和检索打好基础。

Step 2:文本分块与向量化,资料转换为AI可读格式:当资料被汇入RAG系统后,会进行文字分块(Chunk),将长文本拆分为更小的单位(如段落或句子)。接着,这些文字区块透过嵌入模型(Embedding Model)转换成向量格式,使得AI能够理解资料的语意结构。

Step 3:问题分析与检索,精准找到关联资料:当用户在应用程式中提出问题时,AI会先分析搜索意图,再从向量资料库中检索与该问题高度相关的文字区块。

Step 4:生成回答,几秒内完成资讯传递:最后,生成式 AI 根据检索到的资料生成回答,并将答案回传到应用程式中,几秒内即可提供使用者所需的资讯。

2.6 自我一致性

自我一致性本质上是一种集成学习方法,通过多次执行 CoT 得到多个推理路径,然后在多个结果中投票选择最一致的答案。Xuezhi Wang等人后来又对其进行了优化,提出了推理增强集成(Rationale-Augmented Ensembles) 方法,通过改变示例顺序或使用模型生成的思维链(CoT)来替换人工编写的推理链,在多个样本试验中引入随机性,然后通过多数投票来聚合模型输出,得到最终答案。

从上图可以看出自我一致性方法整体包括三个步骤:

  1. 构造 CoT 示例数据;
  2. 通过大模型生成多个不同的推理路径(reasoning path);
  3. 使用多数投票(majority vote)的方法选出最一致的答案;

虽然这种方式有点大力出奇迹的感觉,但是它确实可以提高思维链在算术和常识推理等任务中的性能。在具体的使用过程中,还有两个问题值得注意:

  1. 在生成多个推理路径时,一般将模型的温度值设置为0.5,因为这个值如果设置过小会导致答案基本都一样,过大又会导致答案全都不一样,都会影响到最终的效果;
  2. 需要生成多少个推理路径(也就是采样次数)也是一个问题,从论文结果来看,候选样本数越多,最终效果越好,论文中一共采样了40次,但在实际应用中不可能这做,一般采样5次以上就能超过普通的思维链提示;

2.7 自动推理并使用工具(ART)

在大模型使用的时候,如果进行数据分析或者网页分析,可能会涉及到外部工具的使用。在这种时候,交替使用思维链和工具则是一种强大且稳健的方法。因为使用程序或者查询工具可以让结果更加精准,有效避免让大模型产生幻觉的情形。

ART(Automatic Reasoning and Tool-use)的工作原理如下:

  • 接到一个新任务的时候,从任务库中选择多步推理和使用工具的示范。
  • 在测试中,调用外部工具时,先暂停生成,将工具输出整合后继续接着生成。

ART引导模型总结示范,将新任务进行拆分并在恰当的地方使用工具。ART 采用的是零样本形式。ART还可以手动扩展,只要简单地更新任务和工具库就可以修正推理步骤中的错误或是添加新的工具。这个过程如下:

下面的例子充分展示了编程、思维链推理、搜索、算数、字符串操作的全部流程,在此期间使用了搜索引擎、大模型、Python等工具来完成任务。

2.8 ReAct(Reason+Act)

ReAct是Reasoning and Acting(Reason Act)缩写,意思是LLM可以逻辑推理(Reason),构建完成系列行动(Act),从而达成期望目标。ReAct框架允许大模型与外部工具交互获取额外的信息,从而给出更可靠和实际的行动。

大模型Agent功能,大模型会自己分析问题,选择合适的工具,最终解决问题。这个功能背后的原理是ReAct框架。ReAct方式的作用就是协调LLM模型和外部的信息获取,与其他功能交互。如果说LLM模型是大脑,那ReAct框架就是这大脑的手脚和五官。同时具备帮助LLM模型获取信息、输出内容与执行决策的能力,对于一个指定的任务目标,ReAct框架会自动补齐LLM应该具备的知识和相关信息,然后再让LLM模型做成决策,并执行LLM的决策。

ReAct流程里,关键是思维、行动、观察这三个概念:

  1. Thought:由LLM模型生成,是LLM产生行为和依据。可以根据LLM的思考,来衡量他要采取的行为是否合理。这是一个可用来判断本次决策是否合理的关键依据。相较于人类,thought的存在可以让LLM的决策变得更加有可解释性和可信度。
  2. Act:Act是指LLM判断本次需要执行的具体行为。Act一般由两部分组成:行为和对象。用编程的说法就是API名称和对应的入参。LLM模型最大的优势是,可以根据Thought的判断,选择需要使用的API并生成需要填入API的参数。从而保证了ReAct框架在执行层面的可行性。
  3. Obs:LLM框架对于外界输入的获取。它就像LLM的五官,将外界的反馈信息同步给LLM模型,协助LLM模型进一步地做分析或者决策。

一个完整的ReAct的行为,包含以下3个流程:

  1. 输入目标:任务的起点。可以是用户的手动输入,也可以是依靠触发器(比如系统故障报警)。
  2. 循环(Loop):LLM模型开始分析问题需要的步骤(Thought),按步骤执行Act,根据观察到的信息(Obs),循环执行这个过程。直到判断任务目标达成。
  3. 结束(Finish):任务最终执行成功,返回最终结果。

2.9 自我反思(Reflexion)

自我反思是一个通过语言反馈来强化基于语言的智能体的框架。自我反思是一种‘口头’强化的新范例,它将策略参数化为智能体的记忆编码与 LLM 的参数选择配对。

在高层次上,自我反思将来自环境的反馈(自由形式的语言或者标量)转换为语言反馈,也被称作 self-reflection,为下一轮中 LLM 智能体提供上下文。这有助于智能体快速有效地从之前的错误中学习,进而提升许多高级任务的性能。

下图展示了自我反思的智能体学习迭代优化其行为来解决决策、编程和推理等各种人物的例子。自我反思(Refelxion)通过引入自我评估、自我反思和记忆组件来拓展 ReAct 框架。

如下图所示,自我反思由三个不同的模型组成:

  1. 参与者(Actor):根据状态观测量生成文本和动作。参与者在环境中采取行动并接受观察结果,从而形成轨迹。思维链和ReAct被用作参与者模型。此外,还添加了记忆组件为智能体提供额外的上下文信息。
  2. 评估者(Evaluator):对参与者的输出进行评价。具体来说,它将生成的轨迹(也被称作短期记忆)作为输入并输出奖励分数。根据人物的不同,使用不同的奖励函数(决策任务使用LLM和基于规则的启发式奖励)。
  3. 自我反思(Self-Reflection):生成语言强化线索来帮助参与者实现自我完善。这个角色由大语言模型承担,能够为未来的试验提供宝贵的反馈。自我反思模型利用奖励信号、当前轨迹和其持久记忆生成具体且相关的反馈,并存储在记忆组件中。智能体利用这些经验(存储在长期记忆中)来快速改进决策。

自我反思的关键步骤是:

  1. 定义任务
  2. 生成轨迹
  3. 评估
  4. 执行自我反思
  5. 生成下一条轨迹。

3. 提示词的应用

3.1 生成数据

提示词(Prompt)在数据生成中的应用,极大地扩展了数据资源的灵活性与可获取性。通过精心设计的自然语言提示,大语言模型可以自动合成各类结构化与非结构化数据,例如问答对、用户评论、摘要文本、表格内容等,广泛用于数据增强、少样本学习和训练集扩充等场景。这种方式不仅节省了人工标注成本,还能够模拟罕见场景或边界样本,从而提升模型在实际环境中的泛化能力与鲁棒性。例如,输入“生成一些汽车售后的案例,表格输出即可。”,就可以得到以下的表格内容:

案例编号问题类型客户描述处理过程结果费用承担方
001发动机故障客户反映车辆启动困难,发动机抖动严重。检查点火系统、燃油泵和火花塞,发现点火线圈老化导致缺缸。更换点火线圈和火花塞。车辆恢复正常启动,抖动消失。厂商保修期内,费用全免
002电子系统故障中控屏幕频繁黑屏,倒车影像无法显示。升级车载系统软件并检测线路,确认屏幕主板故障。更换全新中控屏幕。电子系统功能恢复正常。保修期内,厂商承担
003事故维修车辆左前侧碰撞导致保险杠和大灯损坏。拆解检查后更换保险杠、大灯总成,校正前梁。车身结构恢复,外观和功能正常。保险公司理赔
004保养纠纷客户投诉保养后油耗异常升高,怀疑机油型号错误。重新检测机油标号,确认使用符合规格的机油;清洗节气门并重置ECU。油耗恢复正常,客户撤销投诉。4S店承担检测费用
005配件更换延迟订购的进口变速箱配件到货时间超过1个月,客户不满。协调厂商加急发货,提供代步车并补偿两次免费保养。配件更换完成,客户满意度提升。厂商承担物流和补偿费用
006召回服务厂商发布刹车助力泵召回通知。主动联系客户预约检修,免费更换改进版助力泵组件。安全隐患消除,客户对主动服务表示认可。厂商全额承担
007客户投诉服务态度客户投诉售后接待人员态度冷淡,未及时解决问题。核实后向客户道歉,对涉事员工培训,并赠送保养优惠券。客户接受解决方案,后续服务评分提高。4S店承担补偿费用
008保修争议客户车辆过保3天,厂商拒绝免费维修变速箱故障。协商后按保修期延长政策承担70%维修费,客户支付剩余30%。争议解决,客户认可处理方案。厂商与客户按比例分担
009软件升级失败车载系统升级后导致动力模式异常。回滚软件版本并重新升级,同步修复兼容性问题。系统运行正常,动力模式恢复。免费服务(厂商责任)
010混合动力电池故障车辆纯电模式续航骤降,电池组报警。检测确认单体电池损坏,更换整个电池组模块。续航恢复至标准值,故障码消除。电池质保期内,厂商承担

3.2 生成代码

在代码生成方面,提示词技术已成为智能编程助手的核心能力之一。开发者可通过自然语言描述需求,模型生成相应的函数、脚本、接口文档甚至是测试用例。例如,“用 Python 实现快速排序”这样的简单提示词,就能引导模型生成完整、可运行的排序程序。这种能力不仅适用于初学者的学习辅助,也在资深开发者的代码补全与重构工作中提供了高效支持,尤其在 API 使用、跨语言翻译和单元测试生成等任务中效果显著。

例如,我们要求LLM输出一段简单的Python代码,就可以得到如下的案例:

def fibonacci(n):
    # 生成斐波那契数列
    sequence = []
    a, b = 0, 1
    for _ in range(n):
        sequence.append(a)
        a, b = b, a + b
    return sequence

# 输入要生成的项数
n = int(input("请输入斐波那契数列的项数: "))
result = fibonacci(n)

# 打印结果
print(f"前 {n} 项斐波那契数列:")
print(result)

3.3 生成图片

生成图片是多模态提示词应用的典型代表。通过将文本提示转化为视觉内容,模型可以根据语义描述合成风格化或写实的图像。例如,输入“一个在夕阳下奔跑的机器人”,生成模型(如 DALL·E、Stable Diffusion)便能输出与该描述相符的图像。这类技术广泛应用于广告创意、角色设计、虚拟场景构建以及艺术创作等领域,同时也促进了图文协同理解的发展,使文本与图像之间的信息表达更加紧密和高效。

3.4 案例分析

提示词的高效应用往往依赖于上下文、格式和任务目标的精细控制,案例分析是理解其应用机制的重要方法。通过对实际应用场景中的提示词设计策略进行剖析,如 few-shot prompting、chain-of-thought prompting 或 instruction tuning,可以深入理解模型响应的形成逻辑与效果差异。案例往往涵盖从简单任务(如摘要生成)到复杂任务(如法律文书撰写或多轮对话)的提示设计,通过对比实验进一步揭示如何通过微调提示词优化输出质量,是推动提示工程从经验走向系统化设计的关键路径。

例如,输入“写一个简答的案例分析的例子,例如某一个职场人力划分的案例,帮忙写一个分析。”然后就可以得到如下的内容:

4.  参考资料

  1. 提示工程指南:https://www.promptingguide.ai/zh
  2. 提示词工程指南:https://github.com/yunwei37/Prompt-Engineering-Guide-zh-CN
  3. 提示词工程维基百科:https://en.wikipedia.org/wiki/Prompt_engineering
  4. 文生文Prompt指南:https://help.aliyun.com/zh/model-studio/use-cases/prompt-engineering-guide
  5. 提示工程概述:https://docs.anthropic.com/zh-CN/docs/build-with-claude/prompt-engineering/overview
  6. 提示工程指南:https://www.promptingguide.ai/zh
  7. 自动推理并使用工具:Paranjape, Bhargavi, et al. “Art: Automatic multi-step reasoning and tool-use for large language models.” arXiv preprint arXiv:2303.09014 (2023).
  8. ReAct:Yao, Shunyu, et al. “React: Synergizing reasoning and acting in language models.” International Conference on Learning Representations (ICLR). 2023.
  9. Reflexion:Shinn, Noah, et al. “Reflexion: Language agents with verbal reinforcement learning.” Advances in Neural Information Processing Systems 36 (2023): 8634-8652.

从小模型到大模型:算法工程师如何高效转型入门大模型技术

近年来,大语言模型如 GPT、LLaMA、Claude、Gemini、DeepSeek 等在自然语言处理任务中展现出前所未有的能力,已经成为技术界与产业界关注的核心。从算法模型到软件产品,从科研论文到应用落地,大模型不仅改变了人们对人工智能的认知,也正在重塑整个技术生态。在任何行业都面临着这场来自于 AI 的挑战,无论是互联网、新能源汽车还是农业,都有着许多实际的场景等待 AI 的接入。对于有机器学习和深度学习基础,甚至在工业界具备小模型实践经验的算法工程师而言,进入大模型的世界,不仅是一场技术能力的升级,更是一场思维范式的转变,不及时转型大模型的话,可能未来在市场中的就业前景会比较差。

有的人对大模型的理解还停留在“模型更大、训练更贵”这类直观感受上,实际上,大模型的发展远不止于此。它的核心在于能力泛化与范式重塑:过去我们依赖于大量小模型分别完成各类任务,如文本分类、情感分析、命名实体识别等,而如今一个统一的大模型通过预训练加提示学习,便可以泛化执行多个任务。而且使用不同的模型大小,往往会有不同的效果。如果是应对线上耗时极为敏感的业务,选择0.5B这类模型反而可能是较好选择;如果是需要接近人类的问答业务,那自然要选择算法效果最好的模型。这种变化不仅体现在架构设计上,也深刻影响着数据处理、系统部署与业务集成的方式。理解这一点,有助于我们更清晰地把握大模型带来的真正价值,以及入门所需要的新思维方式。

大模型的技术入门可以从实践出发。对于刚开始接触这一领域的工程师,最直接的方式是先从大模型的 API 使用开始,熟悉其基本能力。通过调用 OpenAI 或者国内主流模型服务,可以快速体验大模型在文本生成、问答、摘要、翻译等方面的表现。除此之外,还可以使用 Ollama 进行本地模型的部署和使用,如果本地电脑的配置较好,甚至还可以使用效果较好的模型。更进一步,程序员还可以尝试通过提示词工程(Prompt Engineering)技巧调整模型输出,比如使用 Zero-shot、One-shot、Few-shot、Role Prompting 或思维链(Chain-of-Thought)来提升任务完成效果。在这个过程中,如果有个人或者本地的知识库,则可以使用 LangChainLlamaIndex 等框架可以帮助更高效地构建 LLM 驱动的应用,如智能问答系统、RAG 检索增强模型等。

比如你可以从一个简单的任务开始:用开源模型或者 Ollama 来搭建一个本地的问答机器人。此时,你将面临模型选择(各种大小从0.5B到230B的模型)、环境(Windows、Mac、Linux)的模型部署、RAG 检索增强、对话记忆管理、响应优化等多个模块,每一步都能对应学习一类技术。完成一个完整的端到端的 Demo,所收获的理解深度远比看十篇教程来得扎实。随着项目难度的提升,你可以逐步加入更多工程化的能力,如服务的日志监控、模型热更新、服务的负载均衡、API 的接口设计等,将本地的问答机器人从做出来变成做得稳。

当作为程序员的你对模型应用有一定了解之后,则建议逐步深入底层原理与机制。Transformer 架构是理解大模型的基石,掌握 Attention 机制如何运作,有助于理解模型为何具备强大的上下文理解能力。进一步,可以学习大模型的训练流程,包括预训练、指令微调(Instruction Tuning)、RLHF(基于人类反馈的强化学习)等,这些流程构成了大模型从“会说话”到“懂你在说什么”的核心路径。此外,近年来轻量化微调技术如 LoRA、QLoRA、P-Tuning 等方法也非常值得了解,它们极大降低了模型微调的成本,为个人开发者和中小企业提供了更多地使用大模型的可能性。

在掌握理论和微调技术的基础上,工业部署能力将成为你的核心竞争力之一。大模型的推理开销巨大,因此推理优化至关重要。学习量化、剪枝等优化手段,可以帮助你在不牺牲太多效果的前提下,大幅提升推理效率。同时,vLLMTritonDeepSpeed 等微调和部署工具,能帮助你将大模型高效运行于生产环境。当前已经有不少开源模型,如 DeepSeek、Qwen、Baichuan、Mistral、LAMMA 等,都提供了成熟的推理和部署方案,完全可以在本地尝试构建属于你自己的大模型应用。

随着模型能力的增强,仅仅调用模型已经不能满足复杂的业务场景需求。智能体(Agent)架构成为大模型进一步落地的关键。从调用外部工具、维护任务记忆,到执行多轮推理和状态管理,Agent 模型已经逐步走向工程实用层面。学习 AutoGPTCrewAILangGraph 等框架,将帮助你构建具备任务自主性和长期记忆的复杂智能系统。如果你对前沿感兴趣,也可以探索多模态大模型、长文本处理、Agent 协同等领域,这些都代表着下一阶段技术演进的方向。

对于有小模型研发经验的工程师来说,大模型并不是从零开始的挑战。你原有的数据处理能力、模型评估习惯、工程部署经验,依然在大模型系统中非常有价值。唯一需要转变的,是工程思维的广度和系统设计的复杂度。在大模型时代,更多的是系统级 AI 架构思维,而不仅是模型本身的精调。与此同时,大模型也能反过来助力你的日常开发,从代码生成到接口设计、测试覆盖,模型本身可以成为你高效工作的伙伴。

在这样一个飞速演化的领域中,持续学习显得尤为重要。建议建立一套“输入—实践—输出”的闭环机制:通过订阅高质量技术博客、关注 arXiv 的热门论文和 GitHub 热门项目持续输入,结合业务的实战来做一个实用的小项目或复现案例进行实践,再将实践成果通过博客、文档或开源项目进行输出,这样的闭环能帮助你不断沉淀、持续提升。同时,当前大模型领域更新极快,如果只靠碎片学习(刷一两篇公众号、调试一两个脚本)是很难形成系统认知的。没有实践,就没有深度;没有输出,就没有沉淀。应当通过读论文、复现项目、搭建 Demo、写总结、录视频等方式,形成正向成长闭环,这样才能在快速变动的环境中稳定前进。

从小模型到大模型,是一次从点状技术向整体系统能力的跃迁。虽然学习曲线稍微有点陡峭,但对于有算法经验的你来说,这更是一次站在更高起点的技术升级机会。在 AI 的这次浪潮中,可以选择一个你感兴趣的方向,从实战切入并不断迭代,很快你就会在这场 AI 变革浪潮中找到属于自己的位置。

LlamaIndex:如何在大模型领域构建自己的知识库

LlamaIndex入门

LlamaIndex简介

LlamaIndex(原名 GPT Index)是一个开源的 Python 库,其擅长简化大规模文本数据的索引、存储和查询操作。它将语言模型与文本数据的高效索引结合起来,使得开发者可以轻松地为复杂的文本信息检索和问答任务构建解决方案。通过构建倒排索引或向量索引,LlamaIndex 可以处理大量的文档,并为每个查询提供上下文感知的答案,显著提高了大规模数据的查询效率和准确性。它特别适用于法律、医学、科研、公司内部知识库等领域中需要处理和分析大量文本数据的场景。

LlamaIndex 不仅支持多种数据源,如文本文件、网页和数据库,还能够与先进的向量数据库(如 Milvus或者Pinecone)进行集成,进一步提升查询速度和准确度。通过与大语言模型(如 Ollama、DeepSeek等开源模型或者GPT的API等)结合使用,LlamaIndex能够在复杂的问答系统、自动摘要、个性化推荐等应用中提供强大的文本理解和推理能力。无论是建立企业内部的知识库,还是创建智能客服系统,LlamaIndex 都能有效地处理大量文档,并提供实时、精准的查询结果。

LlamaIndex的安装

LlamaIndex可以通过pip进行安装,其命令是

pip install llama-index

还可以通过源代码进行安装,首先用git clone 代码

git clone https://github.com/jerryjliu/llama_index.git

然后执行:pip install -e . 或者 pip install -r requirements.txt 就可以安装成功。

LlamaIndex的使用

在docs这个文件夹中放入team_structure.txt这个文件,该文件的内容如下所示:

B公司人力资源部(HR)负责公司的招聘、培训、员工关系管理、绩效考核等职能。人力资源部的组织架构分为三个主要小组:招聘组、培训组和员工关系组。
招聘组负责公司各类职位的招聘,筛选候选人,组织面试并安排入职培训。招聘组目前有5名成员,主要负责技术岗位和管理岗位的招聘。
培训组负责公司内部员工的职业发展培训,组织新员工培训、领导力培训和技能提升课程。培训组目前有3名成员,分别负责技术培训、软技能培训和高管培训。
员工关系组负责员工关系的维护,解决员工与公司之间的各类问题,组织公司文化活动,提升员工满意度。员工关系组目前有4名成员。
人力资源部总监为李晓红,负责整体管理,向公司CEO汇报。每月与各小组负责人召开一次会议,评估部门目标和完成情况。
招聘组负责所有岗位的招聘,包括技术岗位、市场岗位、财务岗位等。技术岗位的招聘由王刚负责,市场岗位招聘由张婷负责,财务岗位招聘由刘峰负责。
培训组目前在进行年度员工培训计划,2025年的重点是提升员工的领导力和跨部门协作能力。
员工关系组正在策划一项关于员工福利的提升项目,预计将在2025年初开始实施。

于是,一个简单的搜索功能可以用以下代码来实现,只输出Top2相似的结果。

代码说明:

  1. 文档加载:代码使用 SimpleDirectoryReader 从指定的文件夹(例如 docs)中加载文本文件。这些文本文件可以是任何格式的文本文件(如 .txt)。SimpleDirectoryReader 会自动扫描指定文件夹中的所有文件并加载其内容。
  2. 创建索引:使用 VectorStoreIndex.from_documents(documents) 将加载的文档转化为向量索引。我们还在构造索引时应用了 SentenceSplitter,用于将文档拆分成小块以便更高效的处理。
  3. 查询引擎通过 index.as_query_engine() 创建一个查询引擎,可以在该引擎上执行查询并返回最相关的文档或文本块。
  4. 查询执行:代码通过 query_engine.query(query) 执行用户的查询,并返回与查询最相关的结果。在这个例子中,查询的是 “B公司人力资源部的组织架构是怎样的?”
  5. 输出:最后,代码会打印检索结果。
import logging
import sys
from llama_index.core import PromptTemplate, Settings, SimpleDirectoryReader, VectorStoreIndex
from llama_index.core.node_parser import SentenceSplitter
from llama_index.embeddings.huggingface import HuggingFaceEmbedding

# Step 1 设置日志
# 设置日志记录的最小级别为 WARNING,避免输出 DEBUG 和 INFO 信息
logging.basicConfig(stream=sys.stdout, level=logging.WARNING)  # 只输出 WARNING 及以上级别的日志

# 如果你只想屏蔽来自 llama_index 的日志,也可以使用下面的代码来禁用它
logging.getLogger("llama_index").setLevel(logging.WARNING)  # 设置 llama_index 的日志级别为 WARNING

# Step 2 配置 LlamaIndex 使用本地的嵌入模型(可选)
Settings.llm = None
Settings.embed_model = HuggingFaceEmbedding(
    model_name="/Users/avilazhang/PycharmProjects/models/BAAI/bge-large-zh-v1.5"  # 使用 BGE 中文嵌入模型
)

# Step 3 定义文档路径,假设文档存储在名为 "docs" 的文件夹中
docs_directory = 'docs'

# Step 4 读取文档并构建索引
# 使用 SimpleDirectoryReader 读取文件夹中的所有文本文件
documents = SimpleDirectoryReader(docs_directory).load_data()  # 读取 docs 文件夹中的所有 txt 文件
index = VectorStoreIndex.from_documents(documents, transformations=[SentenceSplitter(chunk_size=256)])

# Step 5 存储向量索引
index.storage_context.persist(persist_dir='doc_emb')  # 保存向量索引到本地目录

# Step 6 构建查询引擎,搜索TopK。
query_engine = index.as_query_engine(similarity_top_k=2)

# Step 7 模拟用户查询并执行检索
query = "B公司招聘组负责什么内容?"
response = query_engine.query(query)

# Step 8 打印检索结果
print("检索结果:", response)

检索的结果如下图所示,只有两个文档信息,因为TopK的值等于2。

除此之外,LlamaIndex还支持在现有索引的基础上读取索引,并且新增索引。

RAG

RAG的整体流程

一个标准的RAG整体流程如下所示,可以从数据库、文档、API中获取数据并形成Index,然后query提问的时候可以通过Index获得相应的数据(relevant data),再把prompt、query和relevant data输入大模型,即可得到优化后的回答(response)。

所以,RAG的主要阶段就包括载入、索引、存储、提问、评估。

Embedding模型

llama_index同样可以存储index,并且llama_index可以读取数据库、pdf、txt等类型文档。可以使用嵌入模型来做数据的嵌入工作,并且计算其数据之间的相似度。

from sentence_transformers import SentenceTransformer

# 模型的本地地址,可以使用以下命令来进行下载到本地的某个地址
# modelscope download --model BAAI/bge-large-zh-v1.5 --local_dir /Users/avilazhang/PycharmProjects/models/BAAI/bge-large-zh-v1.5
# 嵌入模型
embedding_models = '/Users/avilazhang/PycharmProjects/models/BAAI/bge-large-zh-v1.5'

# 方法一:
sentences_1 = ["样例数据-1", "样例数据-2"]
sentences_2 = ["样例数据-3", "样例数据-4"]
model = SentenceTransformer(embedding_models)
embeddings_1 = model.encode(sentences_1, normalize_embeddings=True)
embeddings_2 = model.encode(sentences_2, normalize_embeddings=True)
similarity = embeddings_1 @ embeddings_2.T
print(similarity)
# [[0.8553333  0.8520634 ]
#  [0.87456274 0.8557937 ]]
 
 
# 方法二:
queries = ['query_1', 'query_2']
passages = ["样例文档-1", "样例文档-2"]
instruction = "为这个句子生成表示以用于检索相关文章:"

model = SentenceTransformer(embedding_models)
q_embeddings = model.encode([instruction+q for q in queries], normalize_embeddings=True)
p_embeddings = model.encode(passages, normalize_embeddings=True)
scores = q_embeddings @ p_embeddings.T
print(scores)
# [[0.3372506  0.20507795]
#  [0.22591084 0.38495794]]

LlamaIndex与Ollama

用LlamaIndex和Ollama可以构建模型的RAG的知识库并输出:

import logging
import sys
from llama_index.core import PromptTemplate, Settings, SimpleDirectoryReader, VectorStoreIndex
from llama_index.core.node_parser import SentenceSplitter
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
import ollama
from llama_index.core import Document

# Step 1️⃣ 设置日志
# 设置日志记录的最小级别为 WARNING,避免输出 DEBUG 和 INFO 信息
logging.basicConfig(stream=sys.stdout, level=logging.WARNING)  # 只输出 WARNING 及以上级别的日志

# 如果你只想屏蔽来自 llama_index 的日志,也可以使用下面的代码来禁用它
logging.getLogger("llama_index").setLevel(logging.WARNING)  # 设置 llama_index 的日志级别为 WARNING


# Step 2️⃣ 定义 system prompt
SYSTEM_PROMPT = """You are a helpful AI assistant."""
query_wrapper_prompt = PromptTemplate(
    "[INST]<<SYS>>\n" + SYSTEM_PROMPT + "<</SYS>>\n\n{query_str}[/INST] "
)

# Step 4️⃣ 配置 LlamaIndex 使用 BAAI/bge-base-zh-v1.5 作为嵌入模型
Settings.llm = None
Settings.embed_model = HuggingFaceEmbedding(
    model_name="/Users/avilazhang/PycharmProjects/models/BAAI/bge-large-zh-v1.5"  # 使用 BGE 中文嵌入模型
)

# Step 5️⃣ 定义 B公司人力资源部的组织架构及业务分工文档
docs = [
    "B公司人力资源部(HR)负责公司的招聘、培训、员工关系管理、绩效考核等职能。人力资源部的组织架构分为三个主要小组:招聘组、培训组和员工关系组。",
    "招聘组负责公司各类职位的招聘,筛选候选人,组织面试并安排入职培训。招聘组目前有5名成员,主要负责技术岗位和管理岗位的招聘。",
    "培训组负责公司内部员工的职业发展培训,组织新员工培训、领导力培训和技能提升课程。培训组目前有3名成员,分别负责技术培训、软技能培训和高管培训。",
    "员工关系组负责员工关系的维护,解决员工与公司之间的各类问题,组织公司文化活动,提升员工满意度。员工关系组目前有4名成员。",
    "人力资源部总监为李晓红,负责整体管理,向公司CEO汇报。每月与各小组负责人召开一次会议,评估部门目标和完成情况。",
    "招聘组负责所有岗位的招聘,包括技术岗位、市场岗位、财务岗位等。技术岗位的招聘由王刚负责,市场岗位招聘由张婷负责,财务岗位招聘由刘峰负责。",
    "培训组目前在进行年度员工培训计划,2025年的重点是提升员工的领导力和跨部门协作能力。",
    "员工关系组正在策划一项关于员工福利的提升项目,预计将在2025年初开始实施。"
]

# Step 6️⃣ 读取文档并构建索引
documents = [Document(text=doc) for doc in docs]  # 将文档转化为 LlamaIndex 的文档对象
index = VectorStoreIndex.from_documents(documents, transformations=[SentenceSplitter(chunk_size=256)])

# Step 7️⃣ 存储向量索引
index.storage_context.persist(persist_dir='doc_emb')  # 保存向量索引到本地目录

# Step 8️⃣ 构建查询引擎,搜索TopK。
query_engine = index.as_query_engine(similarity_top_k=5)

# Step 9️⃣ 模拟用户查询并执行检索
query = "B公司人力资源部的组织架构是怎样的?"
response = query_engine.query(query)

# Step 10️⃣ 打印检索结果
print("检索结果:", response)

# Step 11️⃣ 构造 Ollama 生成答案的 Prompt
prompt = f"""
请根据以下背景知识回答用户的问题:

【背景知识】
{response}

【问题】
{query}

【回答】
"""

# Step 12️⃣ 使用 Ollama DeepSeek-R1:32b 模型生成答案
print("🤖 正在生成回答...\n")

# 使用 Ollama 调用 DeepSeek-R1:32b 模型进行流式输出
stream = ollama.chat(
    model="deepseek-r1:32b",
    messages=[{"role": "user", "content": prompt}],
    stream=True
)

# Step 13️⃣ 流式输出结果
response_buffer = ""
for chunk in stream:
    delta = chunk.get("message", {}).get("content", "")
    print(delta, end="", flush=True)  # 实时输出
    response_buffer += delta

# Step 14️⃣ # 能流式输出最终生成的答案
print("\n\n生成的答案:", response_buffer)

用多条数据查询之后得到以下结论:

查询回答(来自 RAG + LLM)结论
B公司人力资源部的组织架构是怎样的?B公司的人力资源部负责公司的招聘、培训、员工关系管理以及绩效考核等职能。该部门的组织架构分为三个主要小组:招聘组、培训组和员工关系组。 1. 招聘组: 负责公司各类职位的招聘,包括技术岗位、市场岗位、财务岗位等。 招聘组目前有5名成员,分别由王刚负责技术岗位招聘,张婷负责市场岗位招聘,刘峰负责财务岗位招聘。 2. 培训组: 负责入职培训及其他类型的员工培训,提升员工的技能和工作表现。虽然背景信息中未详细说明该组的具体情况,但可以推断其在培养员工能力方面起着关键作用。 3. 员工关系组: 负责维护员工与公司之间的关系,解决各类问题,组织公司文化活动以提升员工满意度。 该组目前有4名成员,致力于促进积极的职场环境和增强团队凝聚力。 人力资源部的整体管理由总监李晓红负责,她定期召开会议评估部门目标的完成情况,并向公司CEO汇报。这种层级分明、分工明确的组织架构确保了人力资源各项职能的有效执行。 正确
B公司人力资源部2025年有哪些任务? B公司人力资源部在2025年的任务包括: 1. 年度员工培训计划:重点是提升员工的领导力和跨部门协作能力。这是由培训组负责的任务。 2. 员工福利提升项目:员工关系组正在策划并预计将在2025年初开始实施这一项目。 此外,虽然招聘组负责公司各类职位的招聘工作,但并未提到具体的2025年任务目标。人力资源部总监李晓红每月与各小组负责人召开会议,评估部门目标和完成情况,这也是其常规职责的一部分,但未特别指出为2025年的具体任务。 正确 
B公司人力资源部的招聘工作有哪些人在负责?我需要找到他们。 B公司人力资源部的招聘工作由以下人员负责: 1. 王刚 – 负责技术岗位招聘 2. 张婷 – 负责市场岗位招聘 3. 刘峰 – 负责财务岗位招聘  这三位人员分别负责各自领域的招聘工作,如果您需要联系他们,可以按照上述信息进行。正确
什么是生物学?根据提供的背景信息,未提及“生物学”的相关内容。如需了解生物学的定义,请参考可靠的科学资源或教科书。不太好,需要修改Prompt
网络监控是什么?网络监控是指通过各种技术和工具持续监测计算机网络的状态和活动,以便及时发现并解决潜在的安全威胁、性能问题或异常行为。其主要目的是确保网络安全、优化网络性能、预防未经授权的访问,并在出现问题时快速响应。 网络监控通常包括以下方面:1. 流量分析:监控数据流量以检测异常模式或潜在攻击。2. 入侵检测和防御:使用防火墙、入侵检测系统(IDS)等工具防止未经授权的访问。3. 性能管理:优化网络资源分配,确保服务质量和高可用性。4. 日志记录与分析:跟踪网络活动,便于审计和故障排查。 这些措施帮助企业保护敏感数据,维护业务连续性和客户信任。正确
请介绍下数学分析有哪些内容?根据提供的背景信息,数学分析的具体内容并未被提及。背景信息主要涉及公司人力资源部的组织结构和职责,包括招聘组、培训组和员工关系组的工作内容。如果您有关于数学分析的具体问题或需要其他帮助,请提供更多相关信息,我会尽力为您解答。不太好,需要修改Prompt

参考资料

  1. LlamaIndex:https://docs.llamaindex.ai/en/stable/
  2. GitHub链接:https://github.com/run-llama/llama_index
  3. 魔搭社区的嵌入模型:https://www.modelscope.cn/models/BAAI/bge-large-zh-v1.5/summary
  4. LlamaIndex中文文档:LlamaIndex 🦙 0.6.18
  5. Pinecore文档工具:Pinecone Database – Pinecone Docs

Milvus:高性能的向量数据库

Milvus简介

Milvus背景

在人工智能与大模型迅速发展的当下,向量数据库作为支撑语义搜索、图像识别、多模态理解等关键应用的底层基础设施,正扮演着越来越重要的角色。Milvus,作为当前最主流的开源向量数据库之一,专为处理大规模、高维向量的相似性检索而设计,具备高性能、高可扩展性和丰富的索引支持。无论是构建基于文本 embedding 的知识问答系统,还是处理亿级图像的相似性匹配任务,Milvus 都能以其强大的索引能力和灵活的接口,成为 AI 应用中的“记忆引擎”。它的出现,不仅填补了传统数据库在向量检索领域的空白,也为构建下一代智能应用提供了坚实的技术基石。

Milvus特点

Milvus支持的场景包括检索增强生成(RAG)、图像搜索、多模态搜索、混合搜索、GraphRAG等方向。非结构化数据(如文本、图像和音频)格式各异,蕴含丰富的潜在语义,因此分析起来极具挑战性。为了处理这种复杂性,Embeddings被用来将非结构化数据转换成能够捕捉其基本特征的数字向量。然后将这些向量存储在向量数据库中,从而实现快速、可扩展的搜索和分析。在这个背景下,Milvus提供强大的数据建模功能,使用户能够将非结构化或多模式数据组织成结构化的Collections。它支持多种数据类型,适用于不同的属性模型,包括常见的数字和字符类型、各种向量类型、数组、集合和 JSON,为您节省了维护多个数据库系统的精力。

Milvus 提供三种部署模式,涵盖各种数据规模–从 Jupyter Notebooks 中的本地原型到管理数百亿向量的大规模 Kubernetes 集群:

  1. Milvus Lite是一个 Python 库,可以轻松集成到您的应用程序中。作为 Milvus 的轻量级版本,它非常适合在 Jupyter Notebooks 中进行快速原型开发,或在资源有限的边缘设备上运行。对于新人学习而言,可以直接使用Milvus的Lite版本,轻松集成并使用。
  2. Milvus Standalone是单机服务器部署,所有组件都捆绑在一个 Docker 镜像中,方便部署。
  3. Milvus Distributed可部署在Kubernetes集群上,采用云原生架构,专为十亿规模甚至更大的场景而设计。该架构可确保关键组件的冗余。
Milvus的特点详细解释
向量搜索支持亿级向量的ANN(近似最近邻)TopK检索
混合搜索基于多个向量场进行 ANN 搜索。
范围搜索查找查询向量指定半径范围内的向量。
全文搜索基于 BM25 的全文搜索。
重排序(Rerankers)根据附加标准或辅助算法调整搜索结果顺序,完善初始 ANN 搜索结果。
获取根据主键检索数据。
查询使用特定的表达式检索数据。
多模型支持支持不同维度的向量(text/image embedding)
存储引擎支持多种存储后端(如本地磁盘、S3、MinIO)
横向扩展分布式架构,支持大规模扩容
高效搜索算法Milvus支持多种内存和磁盘索引/搜索算法,包括 IVF、HNSW、DiskANN 等
插件生态与Faiss、HNSW、ANN等索引算法对接
访问接口支持RESTful API、SDK(Python/Go/Java/Nodejs)/C#(微软提供)/gRPC API
向量管理支持批量导入、删除、版本管理等操作

Milvus的云原生和高度解耦的系统架构确保了系统可以随着数据的增长而不断扩展。可以借助 Kubernetes 或公共云轻松扩展。此外,Milvus 的各个组件都有很好的解耦,其中最关键的三项任务–搜索、数据插入和索引/压实–被设计为易于并行化的流程,复杂的逻辑被分离出来。这确保了相应的查询节点、数据节点和索引节点可以独立地向上和向下扩展,从而优化了性能和成本效率。

Milvus 高度解耦的系统架构

Milvus与AI的集成路径

Milvus与AI的结合方式主要集中在Embedding(嵌入)、Rerank(重排序)、RAG(检索增强生成)这三个方向上。

  1. Embeddings 模型集成:Embedding 模型将非结构化数据转换为其在高维数据空间中的数字表示,以便您能将其存储在 Milvus 中。目前,PyMilvus(Python SDK)集成了多个嵌入模型,以便您能快速将数据准备成向量嵌入。
  2. Reranker 模型集成:在信息检索和生成式人工智能领域,Reranker 是优化初始搜索结果顺序的重要工具。PyMilvus 也集成了几种 Rerankers 模型,以优化初始搜索返回结果的顺序。
  3. LangChain和其他人工智能工具集成:在 GenAI 时代,LangChain 等工具受到了应用程序开发人员的广泛关注。作为核心组件,Milvus 通常在此类工具中充当向量存储。

Milvus使用

Milvus的安装

开始之前,请确保本地环境中有Python 3.8+可用。安装pymilvus,其中包含 python 客户端库和 Milvus Lite。同时还可以把Milvus的model模型都安装上。

pip install -U pymilvus
pip install "pymilvus[model]"

安装好了之后可以通过pip list看到下面两个package安装成功。

如果有torch安装错误的提示,可以使用命令重新安装

conda install pytorch::pytorch torchvision torchaudio -c pytorch

并且可以使用代码来判断pytorch是否安装正常:

import torch
print(torch.__version__)
# 2.5.1

Milvus的数据库

在 Milvus 中,数据库是组织和管理数据的逻辑单元。为了提高数据安全性并实现多租户,你可以创建多个数据库,为不同的应用程序或租户从逻辑上隔离数据。例如,创建一个数据库用于存储用户 A 的数据,另一个数据库用于存储用户 B 的数据。它支持Python、Go、Java、NodeJS等语言去操作数据库。

可以使用 Milvus RESTful API 或 SDK 列出所有现有数据库并查看其详细信息。同时,还可以管理数据库的属性,包括更改、删除等操作。

Milvus 数据库中,collection 和 schema 是用于组织和管理数据的两个核心概念,主要用于处理和存储高维向量数据。

Collection

在 Milvus 中,collection 是一个数据的集合,可以理解为一个数据库表格的概念,用来存储和管理向量数据及相关的元数据。它的作用是:

  1. 一个 collection 由多个向量数据(如图像、文本等的向量表示)构成;
  2. 每个 collection 可以包含多个字段(例如,ID、向量、标签等)。
  3. 你可以创建、插入、查询、删除和更新集合中的数据。

Collection 是一个二维表,具有固定的列和变化的行。每列代表一个字段,每行代表一个实体。下图显示了一个有 8 列和 6 个实体的 Collection。

通常在创建集合时,需要定义向量的维度(比如 128 维、256 维等)以及其他属性(如数据类型)。例如:

from pymilvus import Collection

# 创建一个名为 "example_collection" 的集合
collection = Collection("example_collection")

Schema

schema 是定义一个 collection 中各个字段的结构和数据类型的描述。它类似于传统数据库中的表结构(如字段名和数据类型)。它的作用是:

  1. schema 确定了 collection 中各个字段的数据类型(例如整数、浮动小数、向量等),以及这些字段是否为可查询的或索引字段。
  2. 对于向量数据,schema 还定义了向量字段的维度和索引方式。向量字段(如 embedding 或 vector)是存储向量数据的核心字段。其他常规字段(如整型、浮动小数、字符串等),用于存储与向量相关的附加信息(例如文本、标签等)。

例子:

from pymilvus import MilvusClient, DataType, Collection

# Step 1️⃣ 创建 Milvus 客户端并初始化 Collection
# MilvusClient 是与 Milvus 服务进行交互的客户端,连接到指定的数据库。
client = MilvusClient("milvus_rag_zh_demo_2.db")  # 假设使用一个本地数据库文件作为存储

# COLLECTION_NAME 是我们想要操作的集合名
COLLECTION_NAME = "zh_rag_demo_2"

# Step 2️⃣ 删除已有的 Collection(如果存在)
# 如果该集合已经存在,我们删除旧的集合以重新创建
if client.has_collection(COLLECTION_NAME):
    print(f"Collection '{COLLECTION_NAME}' already exists. Dropping it.")
    client.drop_collection(COLLECTION_NAME)  # 删除集合

# Step 3️⃣ 定义 Collection 的 Schema
# Collection Schema 用于定义集合中的字段,包括数据类型、维度等。
schema = MilvusClient.create_schema(
    auto_id=False,  # 不自动生成 ID(我们手动指定 ID)
    enable_dynamic_field=True,  # 启用动态字段支持
)

# Step 4️⃣ 添加字段到 Schema
# 每个字段需要指定字段名称、数据类型,以及其他一些属性(如是否是主键)
schema.add_field(field_name="my_id", datatype=DataType.INT64, is_primary=True)  # 主键字段
schema.add_field(field_name="my_vector", datatype=DataType.FLOAT_VECTOR, dim=5)  # 向量字段,维度为5
schema.add_field(field_name="my_varchar", datatype=DataType.VARCHAR, max_length=512)  # 字符串字段,最大长度为512

Milvus Lite 目前仅支持 Ubuntu 和 MacOS 操作系统。如果在 Windows 系统上运行上述代码,将会遇到此错误。另外,使用Milvus的时候,要确保Milvus已经在本地或者远程服务器运行,否则会报错。Milvus的启动和运行建议使用Docker的方式执行。

一个 Collections Schema 有一个主键、最多四个向量字段和几个标量字段。下图说明了如何将文章映射到模式字段列表。

搜索系统的数据模型设计包括分析业务需求,并将信息抽象为模式表达的数据模型。例如,搜索一段文本必须 “索引”,通过 “嵌入 “将字面字符串转换为向量,并启用向量搜索。除了这一基本要求外,可能还需要存储出版时间戳和作者等其他属性。有了这些元数据,就可以通过过滤来完善语义搜索,只返回特定日期之后或特定作者发表的文本。您还可以检索这些标量与主文本,以便在应用程序中呈现搜索结果。每个标量都应分配一个唯一标识符,以整数或字符串的形式组织这些文本片段。这些元素对于实现复杂的搜索逻辑至关重要。

Milvus与Embedding

在当今的信息检索和智能问答系统中,Embedding(向量表示)技术成为了连接自然语言与高效计算的桥梁。通过将文本、图像等非结构化数据转化为高维向量,我们可以实现更精确的语义匹配和内容理解。而Milvus作为一款开源的向量数据库,专为此类场景而生。它支持大规模向量的高效存储与相似度检索,为构建智能搜索引擎、推荐系统及 AI 应用提供了强大的基础设施。下面将结合实际案例,介绍如何利用 Embedding 技术与 Milvus 搭建一套完整的语义检索流程。

于是,在pymilvus中可以引入embedding的模型工具,用于未来的向量输出和检索:

# 从 pymilvus 中引入用于 embedding 的模型工具
from pymilvus import model

# 如果访问 huggingface 官方地址失败(如网络受限),可以取消下面的注释
# 设置环境变量,切换为 huggingface 镜像地址(例如清华、阿里等镜像)
# import os
# os.environ['HF_ENDPOINT'] = 'https://hf-mirror.com'

# 初始化一个默认的 embedding 函数,会自动下载一个小型的句子向量模型:
# paraphrase-albert-small-v2(约 50MB),适合快速测试或演示用途。
embedding_fn = model.DefaultEmbeddingFunction()

# 定义待向量化的文本列表,每条文本都是一个独立的文档或知识片段。
docs = [
    "Artificial intelligence was founded as an academic discipline in 1956.",
    "Alan Turing was the first person to conduct substantial research in AI.",
    "Born in Maida Vale, London, Turing was raised in southern England.",
]

# 使用 embedding 函数将文本转化为向量(embedding)
# 得到的结果是一个 list,每条向量为一个 numpy 数组,维度为 768
vectors = embedding_fn.encode_documents(docs)

# 输出向量
print("vectors:", vectors)

# 输出向量维度信息(用于对齐 Milvus 中 Collection 的字段设计)
# embedding_fn.dim 表示当前模型生成的向量维度
# vectors[0].shape 表示第一条向量的维度
print("Dim:", embedding_fn.dim, vectors[0].shape)  # 预期输出 Dim: 768 (768,)

# 组织向量数据为结构化的格式,准备后续插入 Milvus:
# 每条记录包含:
# - id:唯一编号
# - vector:生成的 embedding 向量
# - text:原始文本内容(可用于展示/检索返回)
# - subject:人为指定的分类标签(这里用作 metadata 过滤的演示)
data = [
    {"id": i, "vector": vectors[i], "text": docs[i], "subject": "history"}
    for i in range(len(vectors))
]

# 打印生成数据的基本信息:
# - 实体数量
# - 每条记录包含哪些字段
# - 向量维度是多少
print("Data has", len(data), "entities, each with fields: ", data[0].keys())
print("Vector dim:", len(data[0]["vector"]))

除此之外,在模型选择方面,还可以选择 Sentence Transformers、BGE M3、SPLADE、instructor、nomic、mGTE、Model2Vec,另外OpenAI、gemini、Voyage、Jina AI、Cohere、Ministral AI的模型需要相应的API-KEY才能使用。

嵌入函数类型API 或开源
openai密集API
sentence transformer密集开源
SPLADE稀疏开源
bge-m3混合开源
远航密集型应用程序接口
jina密集API
cohere密集API
指导员密集开源
Mistral AI密集应用程序接口
Nomic密集API
mGTE混合型开源
Model2Vec混合型开源
双子座混合型私有

可以参考代码进行修改,在model这个部分进行修改即可:

# 从 pymilvus 中引入用于 embedding 的模型工具
from pymilvus import model

# 如果访问 huggingface 官方地址失败(如网络受限),可以取消下面的注释
# 设置环境变量,切换为 huggingface 镜像地址(例如清华、阿里等镜像)
# import os
# os.environ['HF_ENDPOINT'] = 'https://hf-mirror.com'

# 初始化一个默认的 embedding 函数,会自动下载一个小型的句子向量模型:
# paraphrase-albert-small-v2(约 50MB),适合快速测试或演示用途。
# embedding_fn = model.DefaultEmbeddingFunction()

# sentence transformers 模型
embedding_fn = model.dense.SentenceTransformerEmbeddingFunction(
    model_name='all-MiniLM-L6-v2',  # Specify the model name
    device='cpu'  # Specify the device to use, e.g., 'cpu' or 'cuda:0'
)

# # BGE M3 模型
# embedding_fn = model.hybrid.BGEM3EmbeddingFunction(
#     model_name='BAAI/bge-m3',  # Specify the model name
#     device='cpu',  # Specify the device to use, e.g., 'cpu' or 'cuda:0'
#     use_fp16=False  # Specify whether to use fp16. Set to `False` if `device` is `cpu`.
# )

# # splade 模型
# embedding_fn = model.sparse.SpladeEmbeddingFunction(
#     model_name="naver/splade-cocondenser-selfdistil",
#     device="cpu"
# )

# 定义待向量化的文本列表,每条文本都是一个独立的文档或知识片段。
docs = [
    "Artificial intelligence was founded as an academic discipline in 1956.",
    "Alan Turing was the first person to conduct substantial research in AI.",
    "Born in Maida Vale, London, Turing was raised in southern England.",
]

# 使用 embedding 函数将文本转化为向量(embedding)
# 得到的结果是一个 list,每条向量为一个 numpy 数组,维度为 768
vectors = embedding_fn.encode_documents(docs)

# 输出向量
print("vectors:", vectors)

# 输出向量维度信息(用于对齐 Milvus 中 Collection 的字段设计)
# embedding_fn.dim 表示当前模型生成的向量维度
# vectors[0].shape 表示第一条向量的维度
print("Dim:", embedding_fn.dim, vectors[0].shape)  # 预期输出 Dim: 768 (768,)

# 组织向量数据为结构化的格式,准备后续插入 Milvus:
# 每条记录包含:
# - id:唯一编号
# - vector:生成的 embedding 向量
# - text:原始文本内容(可用于展示/检索返回)
# - subject:人为指定的分类标签(这里用作 metadata 过滤的演示)
data = [
    {"id": i, "vector": vectors[i], "text": docs[i], "subject": "history"}
    for i in range(len(vectors))
]

# 打印生成数据的基本信息:
# - 实体数量
# - 每条记录包含哪些字段
# - 向量维度是多少
print("Data has", len(data), "entities, each with fields: ", data[0].keys())
print("Vector dim:", len(data[0]["vector"]))

下面代码的整体流程是:连接 Milvus 客户端并创建集合,初始化一个嵌入模型并将文本转化为向量,组织数据结构并插入到 Milvus,使用一个问题进行语义查询,获取最相似的文本内容。

# 引入必要的库:pymilvus 中的模型工具和客户端类
from pymilvus import model
from pymilvus import MilvusClient

# 初始化一个 Milvus 客户端,连接到本地或指定路径的数据库文件
client = MilvusClient("milvus_demo.db")

# 如果已存在名为 "demo_collection" 的集合,先删除(避免重复创建时报错)
if client.has_collection(collection_name="demo_collection"):
    client.drop_collection(collection_name="demo_collection")

# 创建一个新的集合(Collection),用于存储向量数据
# 参数说明:
# - collection_name:集合名称
# - dimension:向量的维度(本例使用的是 768 维)
client.create_collection(
    collection_name="demo_collection",
    dimension=768,
)

# ⚠️ 如果无法连接 huggingface 官方模型仓库(比如被墙),可以使用国内镜像站点:
# 设置 HF_ENDPOINT 环境变量来更改默认的 huggingface 地址,例如使用清华镜像:
# import os
# os.environ['HF_ENDPOINT'] = 'https://hf-mirror.com'

# 初始化一个默认的 embedding 函数,会自动下载 paraphrase-albert-small-v2 模型
# 模型体积小,加载快,适合用于快速测试/演示
embedding_fn = model.DefaultEmbeddingFunction()

# (可选)你也可以使用更强的模型,例如 SentenceTransformer、BGE M3、Splade 等
# 下面是一些替代方案(按需取消注释):

# 使用 sentence-transformers 模型
# embedding_fn = model.dense.SentenceTransformerEmbeddingFunction(
#     model_name='all-MiniLM-L6-v2',
#     device='cpu'  # 或使用 'cuda:0' 来使用 GPU
# )

# 使用 BGE M3 多任务嵌入模型
# embedding_fn = model.hybrid.BGEM3EmbeddingFunction(
#     model_name='BAAI/bge-m3',
#     device='cpu',
#     use_fp16=False
# )

# 使用稀疏向量模型 Splade(适用于稀疏向量检索场景)
# embedding_fn = model.sparse.SpladeEmbeddingFunction(
#     model_name="naver/splade-cocondenser-selfdistil",
#     device="cpu"
# )

# 准备文本数据:这些将作为示例文档被嵌入为向量
docs = [
    "Artificial intelligence was founded as an academic discipline in 1956.",
    "Alan Turing was the first person to conduct substantial research in AI.",
    "Born in Maida Vale, London, Turing was raised in southern England.",
]

# 使用嵌入函数将文本转换为向量
# 返回值为一个列表,每个元素是一个 numpy 数组(维度为 768)
vectors = embedding_fn.encode_documents(docs)

# 打印生成的向量(可以注释掉以避免打印过多内容)
print("vectors:", vectors)

# 打印嵌入函数维度和实际向量维度(用于确认维度一致性)
print("Dim:", embedding_fn.dim, vectors[0].shape)

# 将向量数据组织为结构化格式,便于后续插入到 Milvus 中
# 每个字典代表一条记录,包括:
# - id:唯一编号
# - vector:对应的嵌入向量
# - text:原始文本
# - subject:可选分类标签(可用于后续过滤查询)
data = [
    {"id": i, "vector": vectors[i], "text": docs[i], "subject": "history"}
    for i in range(len(vectors))
]

# 打印数据结构信息:
print("Data has", len(data), "entities, each with fields: ", data[0].keys())
print("Vector dim:", len(data[0]["vector"]))

# 将数据插入到 Milvus 中的 demo_collection 集合
res = client.insert(collection_name="demo_collection", data=data)

# 打印插入结果(通常包含成功插入的数量等信息)
print("res:", res)

# 接下来执行向量搜索(即:语义检索)
# 使用同样的嵌入函数对查询语句进行编码,得到向量
query_vectors = embedding_fn.encode_queries(["Who is Alan Turing?"])

# ⚠️ 如果没有 embedding 函数,也可以使用随机向量模拟查询(仅限演示用)
# import random
# query_vectors = [ [ random.uniform(-1, 1) for _ in range(768) ] ]

# 在 demo_collection 中执行向量检索
res_search = client.search(
    collection_name="demo_collection",  # 检索目标集合
    data=query_vectors,  # 查询向量
    limit=2,  # 返回最相似的 2 条记录
    output_fields=["text", "subject"],  # 指定返回的字段(原始文本和标签)
)

# 打印检索结果(包括匹配文本和相似度等信息)
print("res_search:", res_search)

# 提取并打印搜索结果中的具体条目
print(list(res_search[0])[0])  # 第一个查询返回的第一条结果
print(list(res_search)[0][1])  # 第一个查询返回的第二条结果

同时,文件夹下会出现一个milvus_demo.db,用于保存向量数据。

如果画一个流程图的话,是按下面的流程来运行的。

由于Milvus Lite的所有数据都存储在本地文件中,因此即使在程序终止后,你也可以通过创建一个带有现有文件的MilvusClient ,将所有数据加载到内存中。例如,这将恢复 “milvus_demo.db “文件中的 Collections,并继续向其中写入数据。

from pymilvus import MilvusClient
client = MilvusClient("milvus_demo.db")

如果想删除某个 Collections 中的所有数据,可以通过以下方法丢弃该Collections:

# Drop collection
client.drop_collection(collection_name="demo_collection")

Milvus与Rerankers

在现代语义检索系统中,检索流程通常被划分为两个阶段:初始召回(First-Stage Retrieval)与重排序(Re-ranking)。Milvus 作为一个开源、高性能的向量数据库,专为处理大规模高维向量检索任务而设计,广泛应用于初始召回阶段。其核心能力在于高效构建和查询向量索引(如 IVF、HNSW、DiskANN 等),支持近似最近邻(ANN)算法,以实现对查询向量在大规模语料中的快速相似度搜索。通过将文本、图像等非结构化数据嵌入为向量,Milvus 能够在亚秒级时间内返回与输入语义最接近的候选项,为后续精排阶段提供基础支撑。

而 Rerankers(重排序模型)主要作用于检索系统的第二阶段。它通常采用更精细的模型架构(如基于 Transformer 的 Cross-Encoder),以逐对方式对候选文本与查询进行交互式建模,从而输出更精准的相关性评分。尽管计算开销相较于向量检索更高,Rerankers 在精度上的提升对于提高系统整体性能具有关键意义。因此,将 Milvus 用于高效召回,再通过 Rerankers 对候选结果进行精细排序,已成为构建高质量语义检索系统的主流范式。

常见的Rerankers功能包括以下五种,有开源模型和应用程序接口。

Rerankers 功能应用程序接口或开源开源地址
BGE开源https://ollama.com/zyw0605688/bge-reranker-v2-m3
交叉编码器开源https://huggingface.co/cross-encoder/ms-marco-MiniLM-L6-v2
Voyage应用程序接口 
Cohere应用程序接口 
Jina AIAPI 

如果使用BGE的重排序模型来构建的话,可以使用以下代码的案例:

# 从 pymilvus.model.reranker 模块中引入 BGE 重排序模型函数
from pymilvus.model.reranker import BGERerankFunction

# ----------------------------------------------------------
# 初始化 Reranker(重排序器):
# 使用 BAAI(智源研究院)提供的 BGE-Reranker-v2-M3 模型。
# 该模型基于 Cross-Encoder 架构,通过对 query 和文档对进行语义交互建模,
# 输出相关性打分,用于对初始检索结果进行排序提升精度。
# ----------------------------------------------------------
bge_rf = BGERerankFunction(
    model_name="BAAI/bge-reranker-v2-m3",  # 模型名称,默认即为该模型
    device="cpu"  # 计算设备,可改为 'cuda:0' 使用 GPU 加速
)

# ----------------------------------------------------------
# 定义一个查询(query),用于检索历史相关信息。
# ----------------------------------------------------------
query = "What event in 1956 marked the official birth of artificial intelligence as a discipline?"

# ----------------------------------------------------------
# 定义候选文档列表(documents):
# 模拟从 Milvus 检索返回的初步候选文本片段(Top-K),
# 接下来将使用 Reranker 进一步对它们进行精排。
# 文档集合里面有四个元素,从0到3编号。
# ----------------------------------------------------------
documents = [
    "In 1950, Alan Turing published his seminal paper, 'Computing Machinery and Intelligence,' proposing the Turing Test as a criterion of intelligence, a foundational concept in the philosophy and development of artificial intelligence.",
    "The Dartmouth Conference in 1956 is considered the birthplace of artificial intelligence as a field; here, John McCarthy and others coined the term 'artificial intelligence' and laid out its basic goals.",
    "In 1951, British mathematician and computer scientist Alan Turing also developed the first program designed to play chess, demonstrating an early example of AI in game strategy.",
    "The invention of the Logic Theorist by Allen Newell, Herbert A. Simon, and Cliff Shaw in 1955 marked the creation of the first true AI program, which was capable of solving logic problems, akin to proving mathematical theorems."
]

# ----------------------------------------------------------
# 执行重排序操作:
# 将 query 与每个文档组合进行相关性评分,输出按分值降序排列的 Top-K 文档。
# top_k 参数指定只保留得分最高的前 K 条(这里设为 3)。
# 返回结果为一个包含 RerankResult 对象的列表,每个对象包含:
# - index:原文档在输入列表中的索引位置
# - score:query 与该文档的语义相关性打分(越高越相关)
# - text:文档原文内容
# ----------------------------------------------------------
results = bge_rf(
    query=query,
    documents=documents,
    top_k=3,  # 返回得分最高的前 3 条
)

# ----------------------------------------------------------
# 遍历输出精排结果:
# 展示每条候选文档的原始索引、得分(保留 6 位小数)、文本内容。
# 注意结果已按 score 排序,score 越高代表与 query 越匹配。
# ----------------------------------------------------------
for result in results:
    print(f"Index: {result.index}")  # 文本在原始 documents 中的位置
    print(f"Score: {result.score:.6f}")  # 重排序得分
    print(f"Text: {result.text}\n")  # 文本内容


如果将query和document修改成中文,同样可以找到结果。查询是:

query = "1956年标志着人工智能正式诞生的事件是什么?"

候选文档是:

documents = [
    "1950年,图灵发表了著名论文《计算机器与智能》,提出了图灵测试,这是人工智能哲学的重要基石。",
    "1956年达特茅斯会议被广泛认为是人工智能作为一个学科诞生的标志,在这次会议上,“人工智能”这一术语首次被提出,并确立了研究目标。",
    "1951年,英国数学家图灵开发了一个可以下棋的程序,展示了早期的人工智能应用。",
    "1955年,艾伦·纽厄尔与赫伯特·西蒙等人发明了“逻辑理论家”程序,这是第一个能够自动证明定理的人工智能系统。"
]

其搜索的结果是:

如果需要使用交叉编码器,那么可以参考HuggingFace上面的链接(https://huggingface.co/cross-encoder/ms-marco-MiniLM-L6-v2),输入以下代码即可计算两个文档之间的相似度。

from sentence_transformers import CrossEncoder

model = CrossEncoder('cross-encoder/ms-marco-MiniLM-L6-v2')
scores = model.predict([
    ("How many people live in Berlin?", "Berlin had a population of 3,520,031 registered inhabitants in an area of 891.82 square kilometers."),
    ("How many people live in Berlin?", "Berlin is well known for its museums."),
])
print(scores)

# [ 8.607141 -4.320079]

还可以用以下多种模型进行选择:

Model-NameNDCG@10 (TREC DL 19)MRR@10 (MS Marco Dev)Docs / Sec
Version 2 models   
cross-encoder/ms-marco-TinyBERT-L2-v269.8432.569000
cross-encoder/ms-marco-MiniLM-L2-v271.0134.854100
cross-encoder/ms-marco-MiniLM-L4-v273.0437.72500
cross-encoder/ms-marco-MiniLM-L6-v274.339.011800
cross-encoder/ms-marco-MiniLM-L12-v274.3139.02960
Version 1 models   
cross-encoder/ms-marco-TinyBERT-L267.4330.159000
cross-encoder/ms-marco-TinyBERT-L468.0934.52900
cross-encoder/ms-marco-TinyBERT-L669.5736.13680
cross-encoder/ms-marco-electra-base71.9936.41340
Other models   
nboost/pt-tinybert-msmarco63.6328.82900
nboost/pt-bert-base-uncased-msmarco70.9434.75340
nboost/pt-bert-large-msmarco73.3636.48100
Capreolus/electra-base-msmarco71.2336.89340
amberoad/bert-multilingual-passage-reranking-msmarco68.435.54330
sebastian-hofstaetter/distilbert-cat-margin_mse-T2-msmarco72.8237.88720

下面我们使用cross-encoder/ms-marco-MiniLM-L12-v2模型来进行相似度的计算:

from transformers import AutoTokenizer, AutoModelForSequenceClassification
import torch
from sentence_transformers import CrossEncoder

# 方法一:
model = CrossEncoder('cross-encoder/ms-marco-MiniLM-L12-v2')
scores = model.predict([
    ("How many people live in Berlin?", "Berlin had a population of 3,520,031 registered inhabitants in an area of 891.82 square kilometers."),
    ("How many people live in Berlin?", "Berlin is well known for its museums."),
])
print(scores)

# 方法二:
model = AutoModelForSequenceClassification.from_pretrained('cross-encoder/ms-marco-MiniLM-L12-v2')
tokenizer = AutoTokenizer.from_pretrained('cross-encoder/ms-marco-MiniLM-L12-v2')

features = tokenizer(['How many people live in Berlin?', 'How many people live in Berlin?'], ['Berlin had a population of 3,520,031 registered inhabitants in an area of 891.82 square kilometers.', 'Berlin is well known for its museums.'],  padding=True, truncation=True, return_tensors="pt")

model.eval()
with torch.no_grad():
    scores = model(**features).logits
    print(scores)

如果要进行重排序的话,可以参考下面的文档:

# 从 pymilvus.model.reranker 模块中导入交叉编码器重排序函数
from pymilvus.model.reranker import CrossEncoderRerankFunction

# ✅ 步骤 1:定义交叉编码器(Cross Encoder)重排序函数
# 该函数内部会自动下载 Hugging Face 上的模型并用于 rerank
ce_rf = CrossEncoderRerankFunction(
    model_name="cross-encoder/ms-marco-MiniLM-L12-v2",  # 使用指定的 cross-encoder 模型(支持语义匹配任务)
    device="cpu"  # 指定模型运行设备,如 'cpu' 或 'cuda:0'(GPU)
)

# ✅ 步骤 2:定义用户查询(Query)
query = "What event in 1956 marked the official birth of artificial intelligence as a discipline?"
# 中文翻译:1956年哪一事件标志着人工智能作为一门学科的正式诞生?

# ✅ 步骤 3:准备待重排序的候选文档(Documents)
# 每个字符串都是一个候选答案,Cross Encoder 会将它们与 Query 组合成一个个句对进行评分
documents = [
    "In 1950, Alan Turing published his seminal paper, 'Computing Machinery and Intelligence,' proposing the Turing Test as a criterion of intelligence, a foundational concept in the philosophy and development of artificial intelligence.",
    # 图灵1950年的论文,提出图灵测试,为AI发展奠定哲学基础

    "The Dartmouth Conference in 1956 is considered the birthplace of artificial intelligence as a field; here, John McCarthy and others coined the term 'artificial intelligence' and laid out its basic goals.",
    # 1956年达特茅斯会议,被广泛认为是AI的诞生标志

    "In 1951, British mathematician and computer scientist Alan Turing also developed the first program designed to play chess, demonstrating an early example of AI in game strategy.",
    # 图灵在1951年开发了下棋程序,展示早期AI在博弈中的应用

    "The invention of the Logic Theorist by Allen Newell, Herbert A. Simon, and Cliff Shaw in 1955 marked the creation of the first true AI program, which was capable of solving logic problems, akin to proving mathematical theorems."
    # 1955年“逻辑理论家”程序是首个能解逻辑问题的AI程序
]

# ✅ 步骤 4:调用重排序函数进行语义匹配排序(Reranking)
# Cross Encoder 会对 (query, document) 成对输入进行语义评分,返回得分最高的 top_k 条
results = ce_rf(
    query=query,
    documents=documents,
    top_k=3,  # 返回得分最高的前 3 个文档
)

# ✅ 步骤 5:遍历结果,输出每条结果的索引、分数、文本内容
# Cross Encoder 输出的是基于语义匹配的相关性打分,越高越相关
for result in results:
    print(f"Index: {result.index}")       # 文档在原始列表中的索引
    print(f"Score: {result.score:.6f}")   # Cross Encoder 计算出的相关性得分
    print(f"Text: {result.text}\n")       # 对应的文档内容

Milvus与RAG

RAG简介

Retrieval-Augmented Generation(RAG)是一种结合了生成模型与外部知识库的问答与文本生成框架,它通过引入检索机制增强了语言模型的上下文感知能力与事实一致性。传统的预训练语言模型(如 GPT、BERT 等)虽然在多种自然语言任务中表现优异,但其生成内容完全依赖于固定参数中的知识,难以动态更新、覆盖长尾信息或应对实时变化。RAG 模型通过“检索-生成”的两阶段流程克服了这一局限:首先基于输入查询从外部文档库中检索相关文本段落(通常以嵌入向量为索引),然后将检索结果与原始查询共同输入生成模型,从而生成更丰富、准确且可溯源的回答。

Milvus 作为一款专注于向量检索的高性能数据库,在 RAG 框架中扮演着关键的知识检索组件。它能够高效地存储和检索大规模嵌入文档,利用近似最近邻(ANN)算法快速定位与查询语义最接近的上下文。通过将文本数据嵌入为高维向量并存入 Milvus,RAG 系统可以在每次生成任务中实时访问结构化外部知识,从而动态增强语言模型的生成能力。

RAG 与 Milvus 的集成,使得模型生成不仅更具上下文相关性,同时具有良好的可扩展性与知识更新能力。该组合为构建高质量的问答系统、智能客服、科研助手等提供了坚实的技术基础,并代表了当前生成式 AI 系统从封闭式向开放式知识访问的演进方向。

一个简单的模式就是如下图所示的案例:

Retrieval-Augmented Generation(RAG)框架通过将外部知识检索与语言模型的生成能力结合,有效增强了模型的事实一致性与动态更新能力。本文所采用的 RAG 系统主要包括三个核心阶段:文档嵌入与索引构建、在线查询与检索生成、以及可选的重排序增强。

一、文档嵌入与索引构建

首先,系统从原始知识库中收集结构化或非结构化的文档内容。通过分段与预处理操作,每个文档被切分为若干语义清晰的片段。这些片段随后输入至预训练的文本嵌入模型(如 Sentence Transfomers、BGE M3、Instructor、Model2Vec等),将文本转化为固定维度的语义向量。所有向量及其对应的文本片段被统一存储于向量数据库 Milvus 中。Milvus 支持高效的向量索引构建(如 HNSW、ANN、DiskANN 等),为大规模语义检索提供底层支撑。

二、在线检索与生成

当用户提交自然语言查询后,系统首先将查询文本通过同样的嵌入模型转化为查询向量。随后,该向量被用于在 Milvus 中进行近似最近邻检索,系统返回与查询语义最接近的 Top-K 文本片段。此阶段主要实现高召回率的候选过滤,是整个生成流程的语义支撑部分。

三、重排序与上下文拼接(可选增强)

为进一步提升检索结果的相关性,系统可引入 Reranker 模块对 Milvus 返回的候选片段进行重排序。Reranker 通常采用基于 Transformer 的 Cross-Encoder 架构逐对计算候选段与查询之间的交互得分,以获得更高精度的排序结果。或者BGE的Reranker模型来获取排序结果。排序后的文本被选取若干条,并与原始用户查询共同拼接为生成模型的输入上下文。

四、语言模型生成回答

最终,上下文与用户查询被输入至大型语言模型(如GPT、LLaMA、ChatGLM、DeepSeek等),模型基于输入内容生成语言自然、语义准确、并融合外部知识的响应文本。该流程实现了生成式AI系统与结构化外部知识库之间的协同融合,兼具生成能力与知识可控性。

RAG与Milvus的示例

用Milvus以及相应的embedding和rerankers可以获得相应知识库的问答功能。现在给一个demo示例,假设我们有一个公司A的组织架构和部门内容介绍(纯属虚构,如有雷同,纯属巧合),我们将其放入知识库中,形成一个docs的文档数据,然后把这些数据放入Milvus的数据库中,再通过Client去检索和重排,得到数据context_text之后将其作为背景知识放入输入的数据prompt中,最后用Ollama的流式输出得到结果。

from pymilvus import MilvusClient
from pymilvus import model
from pymilvus.model.reranker import CrossEncoderRerankFunction
from sentence_transformers import SentenceTransformer
import ollama
import time

# Step 1️⃣ 创建 Milvus 客户端并初始化 Collection
client = MilvusClient("milvus_rag_zh.db")
COLLECTION_NAME = "zh_rag_demo"

# 若已存在,删除原 Collection
if client.has_collection(COLLECTION_NAME):
    client.drop_collection(COLLECTION_NAME)

# 创建新的向量集合,维度要和选用的 embedding 模型一致
client.create_collection(
    collection_name=COLLECTION_NAME,
    dimension=768,  # 使用默认模型生成的是 768 维向量
)

# Step 2️⃣ 中文句向量模型加载,用于对文档和查询编码
embedding_model = model.DefaultEmbeddingFunction()


# 准备中文知识库文档(可视为 RAG 的数据库),伪造的数据,如有雷同,纯属巧合。
docs = [
    "A公司由五个一级部门组成:战略规划部、产品研发部、市场销售部、人力资源部与财务管理部。",
    "战略规划部负责公司整体战略制定与年度业务目标设定,由高级副总裁王蕾领导。",
    "产品研发部下设三个小组:智能算法组、后端架构组、移动客户端组,分别由赵新宇、韩飞和李倩倩负责。",
    "人力资源部目前有6名成员,涵盖招聘、培训、绩效、薪酬等模块,负责人为HR总监陈蓉。",
    "市场销售部主要负责B端客户开拓与服务,目前设有北京、上海、深圳三个销售大区。",
    "财务管理部由CFO黄志明牵头,下设预算组、税务组与资金组,分别管理不同的财务职责。",
    "A公司CEO为沈立峰,CTO为冯启航,两人每季度召开一次高管战略会,协调部门合作。",
    "智能算法组正在负责天眼项目的模型迭代,预计Q3完成V2版本部署。",
    "后端架构组正在推动服务中台的容器化改造,目前已完成40%的微服务迁移。",
    "移动客户端组刚完成v6.2.0版本的迭代,新增了消息推送与报表订阅功能。"
]

# 将中文文档编码为向量(embedding)
vectors = embedding_model.encode_documents(docs)

# 组织结构化数据,插入到 Milvus 中
data_to_insert = [
    {"id": i, "vector": vectors[i], "text": docs[i], "tag": "公司组织架构"}
    for i in range(len(docs))
]

client.insert(collection_name=COLLECTION_NAME, data=data_to_insert)

# Step 3️⃣ 用户输入查询(中文)
query = "谁是A公司的CTO?"

# 查询向量化
query_vector = embedding_model.encode_documents([query])

# Step 4️⃣ 从 Milvus 中基于向量检索 Top-K 最相关文档
search_results = client.search(
    collection_name=COLLECTION_NAME,
    data=query_vector,
    limit=5,
    output_fields=["text"]
)

# print(search_results)
# print(list(search_results[0]))

# 提取原始文本内容
retrieved_texts = [doc["entity"]["text"] for doc in list(search_results[0])]

# Step 5️⃣ 使用 CrossEncoder 进行重排序,提升相关性排名
reranker = CrossEncoderRerankFunction(
    model_name="cross-encoder/ms-marco-MiniLM-L12-v2",
    device="cpu"
)

reranked = reranker(
    query=query,
    documents=retrieved_texts,
    top_k=3  # 可以根据需要调整返回数量
)

# 拼接重排序后的文档,作为 LLM 的上下文
context_text = "\n".join([r.text for r in reranked])

# Step 6️⃣ 构造 prompt,准备传入 LLM 生成回答
prompt = f"""
请根据以下背景知识回答用户提出的问题:

【背景知识】
{context_text}

【问题】
{query}

【回答】
"""

# Step 7️⃣ 使用 Ollama + DeepSeek 模型生成回答(流式输出)
print("🤖 正在生成回答...\n")

# 调用 Ollama SDK,使用 streaming=True 获取流式输出
stream = ollama.chat(
    model="deepseek-r1:32b",
    messages=[{"role": "user", "content": prompt}],
    stream=True
)

# Step 8️⃣ 打印流式输出结果
response_buffer = ""
for chunk in stream:
    delta = chunk.get("message", {}).get("content", "")
    print(delta, end="", flush=True)  # 实时输出
    response_buffer += delta

通过更换query的内容,可以获得以下结论:

  1. 向量嵌入和Rerank存在优化空间,包括模型的选型、参数配置等内容,否则知识库无法精确找出相关知识;
  2. 找出的个性化词条作为输入是不会影响外部公开问题的正常回答的。
查询回答(来自 RAG + LLM)结论
谁是A公司的CTO?冯启航是A公司的CTO。正确
A公司哪个小组负责天眼项目?A公司的天眼项目负责人尚未明确,但根据背景知识,该项目可能由产品研发部的其中一个小组负责。具体来说: 1. 智能算法组:负责AI和数据分析相关的工作。2. 后端架构组:负责应用程序的后台结构。3. 移动客户端组:负责移动端应用开发。 如需确定具体负责人,请提供更多项目细节。错误,原因是搜索的时候没有找到天眼项目这个信息。
A公司中产品研发部下有哪些组?A公司中产品研发部下有智能算法组、后端架构组和移动客户端组三个小组。正确
A公司的预算组是哪位负责?根据提供的背景知识,无法确定A公司预算组的具体负责人。虽然预算管理通常由财务管理部负责,但背景信息中并未提及该部门的负责人或相关细节。因此,基于现有信息,我们不能确定预算组的负责人是谁。 【答案】根据提供的背景知识,无法确定A公司的预算组是由谁负责,因为相关信息未提及。错误,原因是搜索的时候没有找到预算组这个信息。关键字的搜索不够好。 
王蕾负责什么?王蕾是公司的高级副总裁,负责领导战略规划部,主要职责包括制定公司整体战略和设定年度业务目标。正确
什么是数学分析?数学分析是研究函数的性质及其变化规律的一个重要学科,主要涵盖微积分、实变函数、复变函数等内容,广泛应用于物理学、工程学和经济学等领域。正确,没有受到知识库的影响
物理学有哪些研究方向?物理学是一门广泛而深入的科学,涵盖了许多不同的研究方向和分支领域。以下是一些主要的研究方向: 1. 经典力学:研究物体在宏观尺度下的运动和相互作用,包括牛顿力学、拉格朗日力学和哈密顿力学。正确,没有受到知识库的影响

同时,可以查看Collection的数据库信息。

from pymilvus import MilvusClient

# 创建 Milvus 客户端并连接数据库
client = MilvusClient("milvus_rag_zh.db")
COLLECTION_NAME = "zh_rag_demo"

# 获取集合的collection信息。要查看数据库中的所有集合,你可以使用 list_collections() 方法,它将返回当前数据库中的所有集合名称。
collection_list = client.list_collections()
print("List of Collections:", collection_list)

# 查看集合的统计信息,要查看集合中包含的实体数量,你可以使用 get_collection_stats() 方法。它将返回集合的统计信息,其中包括存储的向量数量(即实体数量)。
collection_stats = client.get_collection_stats(COLLECTION_NAME)
print("Collection Stats:", collection_stats)

# 还可以获取特定 Collection 的详细信息
desc_collection = client.describe_collection(collection_name=COLLECTION_NAME)
print("Describe Collection:", desc_collection)

Milvus总结

综上所述,Milvus 是一个开源的高性能向量数据库,专为处理大规模、高维度数据的存储与检索而设计。它支持多种数据类型的高效索引和快速检索,特别适用于机器学习、人工智能和数据分析领域中的相似性搜索任务。Milvus 能够处理从文本、图像到视频等多种格式的向量数据,并且具有出色的扩展性,能够应对大数据量的挑战。通过提供如 IVF、HNSW、Annoy 等多种索引方式,Milvus 能显著提升高维向量检索的速度和效率,是实现高效数据检索和实时分析的重要工具。

参考资料

  1. Milvus的官网:https://milvus.io/zh
  2. Milvus的GitHub:https://github.com/milvus-io/milvus
  3. 用Python操作Milvus向量数据库的简明教程:https://www.dboop.com/ops/用python操作milvus向量数据库的简明教程/#创建索引

RAG与大模型的结合:让LLM更智能的关键

1.  RAG的定义

大模型(Large Language Models,LLMs)的发展经历了从小规模模型到如今大规模、深度学习技术不断突破的过程。最早的语言模型主要依赖规则和手工特征,虽然能够进行一定的语言理解和生成,但缺乏足够的灵活性和准确性。随着深度学习的兴起,尤其是深度神经网络的应用,大规模语言模型开始崭露头角。

从最初的GPT(Generative Pre-trained Transformer)到BERT(Bidirectional Encoder Representations from Transformers)再到如今的GPT-4、DeepSeek-R1等,语言模型的规模和能力迅速提升。大模型通常包含数十亿到数百亿个参数,通过海量数据进行预训练,能够捕捉到语言中的复杂关系和语境信息。大模型的预训练使其具备了强大的迁移学习能力,能够在多个任务上取得优秀的性能,无论是文本生成、问答、翻译还是推理任务。大模型的发展不仅在技术层面突破了许多原有的限制,还在应用上带来了巨大的变革。比如,基于大模型的自然语言处理技术已经广泛应用于智能助手、自动翻译、内容生成等领域,极大地提高了人机交互的效率和质量。从自然语言处理的发展历程来看,LLM已经是近期最热门的研究方向之一。

同时,大模型的研究方向是非常宽泛的,包括但不限于LLM本身,还包括提示词工程,检索增强生成及其各种变形,Agent LLM,LLM 应用框架等方向。

检索增强生成(Retrieval-augmented generation,RAG)是指对大型语言模型输出进行优化,使其能够在生成响应之前引用训练数据来源之外的权威知识库。大型语言模型(LLM)用海量数据进行训练,使用数十亿个参数为回答问题、翻译语言和完成句子等任务生成原始输出。在 LLM 本就强大的功能基础上,RAG 将其扩展为能访问特定领域或组织的内部知识库,所有这些都无需重新训练模型。这是一种经济高效地改进 LLM 输出的方法,让它在各种情境下都能保持相关性、准确性和实用性。下图展示了有RAG和没有RAG的两种完全不同的答案。

2.  RAG的重要性

LLM 是一项关键的人工智能(AI)技术,为智能聊天机器人和其他自然语言处理(Natural Language Processing,NLP)应用程序提供支持。目标是通过交叉引用权威知识来源,创建能够在各种环境中回答用户问题的机器人。不幸的是,LLM 技术的本质在 LLM 响应中引入了不可预测性。此外,LLM 训练数据是静态的,并引入了其所掌握知识的截止日期。

LLM 面临的已知挑战包括

  • 在没有答案的情况下提供虚假信息。
  • 当用户需要特定的当前响应时,提供过时或通用的信息。
  • 从非权威来源创建响应。
  • 由于术语混淆,不同的培训来源使用相同的术语来谈论不同的事情,因此会产生不准确的响应。

可以将大语言模型看作是一个过于热情的新员工,他拒绝随时了解时事,但总是会绝对自信地回答每一个问题。不幸的是,这种态度会对用户的信任产生负面影响,这是您不希望聊天机器人效仿的!

RAG 是解决其中一些挑战的一种方法,它会重定向 LLM,从权威的、预先确定的知识来源中检索相关信息。组织可以更好地控制生成的文本输出,并且用户可以深入了解 LLM 如何生成响应。

上图呈现了一个简单的RA-LLMs框架。

3.  RAG的优势

3.1 经济高效

聊天机器人开发通常从基础的大模型开始。基础模型是在广泛的广义和未标记数据上训练的 API 可访问 LLM。针对组织或领域特定信息重新训练的计算和财务成本很高。RAG 是一种将新数据引入 LLM 的更加经济高效的方法。它使生成式人工智能技术更广泛地获得和使用。

3.2 信息的及时性

即使 LLM 的原始训练数据来源适合您的需求,但保持相关性也具有挑战性。RAG 允许开发人员为生成模型提供最新的研究、统计数据或新闻。他们可以使用 RAG 将 LLM 直接连接到实时社交媒体提要、新闻网站或其他经常更新的信息来源。然后,LLM 可以向用户提供最新信息。

3.3 增强信任度

RAG 允许 LLM 通过来源归属来呈现准确的信息。输出可以包括对来源的引文或引用。如果需要进一步说明或更详细的信息,用户也可以自己查找源文档。这可以增加对您的生成式人工智能解决方案的信任和信心。

3.4 增加控制权

借助 RAG,开发人员可以更高效地测试和改进他们的聊天应用程序。他们可以控制和更改 LLM 的信息来源,以适应不断变化的需求或跨职能使用。开发人员还可以将敏感信息的检索限制在不同的授权级别内,并确保 LLM 生成适当的响应。此外,如果 LLM 针对特定问题引用了错误的信息来源,他们还可以进行故障排除并进行修复。组织可以更自信地为更广泛的应用程序实施生成式人工智能技术。

4.  RAG的工作原理

如果没有 RAG,LLM 会接受用户输入,并根据它所接受训练的信息或它已经知道的信息创建响应。RAG 引入了一个信息检索组件,该组件利用用户输入首先从新数据源提取信息。用户查询和相关信息都提供给 LLM。LLM 使用新知识及其训练数据来创建更好的响应。下图显示了将 RAG 与 LLM 配合使用的概念流程。

4.1 创建外部数据

LLM 原始训练数据集之外的新数据称为外部数据。它可以来自多个数据来源,例如 API、数据库或文档存储库。数据可能以各种格式存在,例如文件、数据库记录或长篇文本。另一种称为嵌入语言模型的 AI 技术将数据转换为数字表示形式并将其存储在向量数据库中。这个过程会创建一个生成式人工智能模型可以理解的知识库。

4.2 检索相关信息

下一步是执行相关性搜索。用户查询将转换为向量表示形式,并与向量数据库匹配。例如,考虑一个可以回答组织的人力资源问题的智能聊天机器人。如果员工搜索:“我有多少年假?”,系统将检索年假政策文件以及员工个人过去的休假记录。这些特定文件将被退回,因为它们与员工输入的内容高度相关。相关性是使用数学向量计算和表示法计算和建立的。

4.3 增强LLM提示

接下来,RAG 模型通过在上下文中添加检索到的相关数据来增强用户输入(或提示)。此步骤使用提示工程技术与 LLM 进行有效沟通。增强提示允许大型语言模型为用户查询生成准确的答案。

4.4 更新外部数据

下一个问题可能是——如果外部数据过时了怎么办? 要维护当前信息以供检索,请异步更新文档并更新文档的嵌入表示形式。您可以通过自动化实时流程或定期批处理来执行此操作。这是数据分析中常见的挑战——可以使用不同的数据科学方法进行变更管理。

5.  检索增强生成和语义搜索

5.1 两者的定义

RAG(Retrieval-Augmented Generation):RAG的核心目标是通过检索外部知识(通常是文档、数据库、或其他文本资源)来增强生成式模型的回答能力。RAG结合了信息检索(retrieval)和生成模型(generation),它首先从大规模的文本库中检索相关内容,再利用生成模型(例如大型语言模型)结合这些内容生成最终的回答。这种方法特别适合用于生成需要依赖大量背景知识的文本,像是问答、文档摘要等任务。

语义搜索(Semantic Search):语义搜索的核心任务是通过理解查询的语义信息来找到与查询最相关的文档或片段。与传统的基于关键词的搜索方法不同,语义搜索基于向量表示和深度学习技术,能够理解查询和文档之间的深层语义关系,从而提供更相关的搜索结果。它通常用于搜索引擎中,目的是提高搜索结果的准确性和相关性。

5.2 两者的相关性

语义搜索可以提高 RAG 结果,适用于想要在其 LLM 应用程序中添加大量外部知识源的组织。现代企业在各种系统中存储大量信息,例如手册、常见问题、研究报告、客户服务指南和人力资源文档存储库等。上下文检索在规模上具有挑战性,因此会降低生成输出质量。

语义搜索技术可以扫描包含不同信息的大型数据库,并更准确地检索数据。例如,他们可以回答诸如 “去年在机械维修上花了多少钱?”之类的问题,方法是将问题映射到相关文档并返回特定文本而不是搜索结果。然后,开发人员可以使用该答案为 LLM 提供更多上下文。

RAG 中的传统或关键字搜索解决方案对知识密集型任务产生的结果有限。开发人员在手动准备数据时还必须处理单词嵌入、文档分块和其他复杂问题。相比之下,语义搜索技术可以完成知识库准备的所有工作,因此开发人员不必这样做。它们还生成语义相关的段落和按相关性排序的标记词,以最大限度地提高 RAG 有效载荷的质量。

6.  RAG的发展历程

6.1 RAG的成长树

大模型涉及的主要阶段包括预训练、微调和推理。随着大型语言模型(LLMs)的出现,RAG的研究最初集中于利用LLMs强大的上下文学习能力,主要集中在推理阶段。随后,研究逐渐深入,逐步与LLMs的微调过程结合。研究人员还在探索通过检索增强技术,在预训练阶段提升语言模型的能力。下图是RAG(检索增强生成)研究的技术发展路线图。

RAG过程在问答任务中的一个典型实例。它主要包括三个步骤:

  1. 索引:将文档拆分成若干块,编码成向量,并存储在向量数据库中。
  2. 检索:根据语义相似性,检索与问题最相关的前k个文档块。
  3. 生成:将原始问题和检索到的文档块一起输入到大型语言模型(LLM)中,生成最终答案。

6.2 RAG的三种形式

RAG可以分成三种形式,下图是RAG三种形式的比较:

(左)朴素RAG主要包括三个部分:索引、检索和生成。

(中)先进RAG提出了围绕预检索和后检索的多种优化策略,其过程类似于简单RAG,仍然遵循链式结构。

(右)模块化RAG继承并发展自前述范式,整体展示出更大的灵活性。其特点在于引入了多个具体的功能模块,并可以替换现有模块。整体过程不再局限于顺序的检索和生成,还包括迭代式和自适应检索等方法。

6.2.1 朴素的RAG

Naive RAG(朴素的检索增强生成模型)是最早的研究范式之一,它在 ChatGPT 被广泛采用后迅速获得了关注。Naive RAG 采用传统的 检索-生成(Retrieve-Generate)流程,主要包括三个步骤:索引、检索和生成。这一流程也被称为“检索-阅读”(Retrieve-Read)框架。

1. 索引(Indexing)

索引阶段首先是清洗和提取原始数据,这些数据通常来自不同的格式,如 PDF、HTML、Word 或 Markdown 文件,然后将其转换为统一的纯文本格式。为了适应语言模型的上下文限制,文本会被分割成较小的块(chunk)。这些文本块会使用嵌入模型(embedding model)转化为向量表示,并存储在向量数据库中。这一步对于后续检索阶段的高效相似度搜索至关重要。

2. 检索(Retrieval)

当用户提出查询时,RAG 系统使用在索引阶段相同的编码模型将查询转换为向量表示。然后,它计算查询向量与索引中每个文本块的向量之间的相似度分数。系统会优先检索与查询最相关的 Top K 个文本块,这些文本块会作为扩展上下文,供后续生成阶段使用。

3. 生成(Generation)

在生成阶段,用户提出的查询和检索到的相关文档会被组合成一个一致的提示(prompt),输入到一个大语言模型(LLM)中,任务是生成一个回应。模型生成回应的方式可以根据具体任务的要求而变化,模型可能会利用其内在的参数知识,也可以限制其回答只基于提供的文档内容。如果是多轮对话,现有的对话历史也可以被整合到提示中,以便模型能够进行多轮对话交互。

Naive RAG 的挑战和缺点

尽管 Naive RAG 有其优势,但它也存在一些显著的缺点和挑战:

1. 检索挑战

检索阶段通常面临精确度和召回率的挑战,可能会导致选择到与查询不相关或不对齐的文本块,或者无法检索到关键的有用信息。

2. 生成困难

在生成回答时,模型可能会面临 幻觉(Hallucination) 的问题,即生成的内容与检索到的上下文无关,甚至会出现生成的内容完全不准确的情况。生成的回答可能会出现无关、毒性或偏见的问题,影响回答的质量和可靠性。

3. 增强问题

将检索到的信息与不同任务进行整合时可能会遇到困难,有时会导致输出内容不连贯或不一致。检索到的信息可能存在冗余,例如从多个来源检索到类似的信息,从而导致重复的响应。此外,确定不同段落的意义和相关性,并确保输出的风格和语气一致,也是一个难点。

4. 复杂问题的处理

在面对复杂问题时,单次检索可能不足以获得足够的上下文信息。生成模型可能过于依赖检索到的增强信息,导致输出的内容仅仅是检索内容的重复,而缺乏深入的分析或综合信息。

6.2.2 增强的RAG

Advanced RAG(高级检索增强生成模型)通过引入特定的改进,旨在克服 Naive RAG 的局限性,重点提升检索质量。与朴素的 RAG 方法不同,Advanced RAG 采用了预检索(Pre-Retrieval)和后检索(Post-Retrieval)策略来优化检索过程,进一步改善了索引和检索的效率。

1. 预检索过程(Pre-Retrieval)

在预检索阶段,重点是优化索引结构和原始查询。通过提升索引的质量和优化查询,提升检索的精度和相关性。

优化索引

  • 增强数据粒度:提高数据分割的细致程度,使得每个数据块(Chuck)更具针对性,便于后续的精确检索。
  • 优化索引结构:调整数据存储和索引的方式,使其更加高效,支持快速检索。
  • 添加元数据:在索引中加入额外的信息(如时间戳、来源等元数据),提高检索时的上下文理解能力。
  • 对齐优化:确保数据之间的一致性和对齐,使得索引的构建更加精确。
  • 混合检索:结合不同的检索方法,进一步提高检索的多样性和精准性。

优化查询

  • 查询重写(Query Rewriting):通过重写用户的查询,使其更简洁、清晰,便于检索模型理解。
  • 查询转换(Query Routing):将用户的查询转换成更加结构化或易于理解的格式,以提高检索效果。
  • 查询扩展(Query Expansion):通过扩展查询的关键词,涵盖更多可能的相关信息,提高检索的全面性。

2. 后检索过程(Post-Retrieval)

在检索到相关内容后,后检索阶段的任务是将检索到的内容有效整合与用户的查询进行融合,从而生成准确的响应。

  • 重排(Re-ranking):对检索到的内容进行重排序,将最相关的文本块移至提示的边缘,以增强模型对关键内容的关注度。这个策略已经在一些框架中得到了应用,如 LlamaIndexLangChainHayStack
  • 摘要(Summary)与上下文压缩(Context Compression):提炼出关键的信息,直接将所有相关文档输入到大语言模型(LLM)中,可能会导致信息过载,使得模型难以集中注意力在关键信息上。因此,后检索阶段的重点是选择最重要的信息,强调关键部分,并压缩上下文,去除不必要的冗余内容。
  • 融合(Fusion):将各种信息融合到一起。

3. 优化策略

Advanced RAG 采用了多种优化方法,旨在提升整个检索过程的效果,特别是在检索的精确性和生成的相关性方面:

  • 增强检索质量:通过预检索和后检索策略,Advanced RAG 可以显著提高检索到的信息质量,使得生成的答案更加准确和相关。
  • 减少信息过载:后检索阶段通过重排和压缩上下文,减少了不相关信息的干扰,使得生成过程更加高效。

6.2.3 模块化的RAG

Modular RAG(模块化检索增强生成模型)在之前的 Naive RAGAdvanced RAG 基础上进一步发展,提供了更高的适应性和灵活性。它通过引入不同的模块来改进模型的各个部分,从而提高检索和处理能力。与传统的顺序处理方式不同,模块化 RAG 支持更加灵活的模块替换与配置,适应不同的任务需求。

1. 新模块(New Modules)

Modular RAG 框架引入了一些额外的专用组件,以增强其检索和处理能力。以下是一些关键的新模块:

  • Search 模块:适应特定场景,支持跨多个数据源(如搜索引擎、数据库和知识图谱)的直接检索。通过大语言模型(LLM)生成的代码和查询语言,实现对各种信息源的访问。
  • RAG Fusion 模块:解决传统检索的局限性,采用多查询策略,将用户的查询扩展为多种视角。通过并行的向量搜索和智能重排序,挖掘显式和转化性知识。
  • Memory 模块:利用 LLM 的记忆功能引导检索,创建一个无限制的记忆池。通过迭代自我增强,使文本与数据分布更加对齐,从而提高检索的准确性。
  • Routing 模块:在 RAG 系统中引导不同数据源的检索,选择最优的路径进行查询。无论是总结、特定数据库检索,还是合并多个信息流,Routing 模块都能进行灵活处理。
  • Predict 模块:通过生成上下文来减少冗余和噪音,直接通过 LLM 生成相关且准确的内容,从而提升信息的相关性和质量。
  • Task Adapter 模块:为不同的下游任务定制 RAG。通过少量示例生成任务特定的检索器,自动进行零-shot 输入的提示检索,支持更广泛的应用场景。

这些模块不仅使检索过程更加流畅,而且显著提升了检索信息的质量和相关性,适应了各种任务和查询,提供了更高的精度和灵活性。

2. 新模式(New Patterns)

Modular RAG 提供了极大的适应性,允许根据特定的挑战替换或重新配置模块。这使得 Modular RAG 超越了 Naive 和 Advanced RAG 固定结构的限制,能够根据任务需求灵活调整模块的交互流程。

  • Rewrite-Retrieve-Read 模型:利用 LLM 的能力通过重写模块和语言模型反馈机制优化查询,提升任务性能。
  • Generate-Read 模型:替代传统的检索过程,使用 LLM 生成的内容作为上下文,减少对传统检索的依赖。
  • Recite-Read 模型:强调从模型权重中检索知识,提升模型处理知识密集型任务的能力。
  • 混合检索策略(Hybrid Retrieval):综合关键字检索、语义检索和向量检索,适应多样化的查询需求。通过子查询和假设文档嵌入(HyDE),提高检索的相关性,专注于生成答案与实际文档之间的嵌入相似性。
  • 模块化模块流(Modular RAG Flow):通过 FLARE 和 Self-RAG 等技术,支持适应性检索,依据不同场景评估检索的必要性。这种灵活的架构不仅可以提高检索效率,还可以更容易地与其他技术(如微调或强化学习)进行集成。

3. 模块化 RAG 的优势

Modular RAG 提供了比 Naive 和 Advanced RAG 更加灵活的架构,能够动态调整模块交互和流向。其优点包括:

  • 灵活的模块替换:可以根据具体任务需求替换或重构模块,适应不同的应用场景。
  • 增强的信息检索能力:通过多种检索策略(如混合检索、并行检索等),提高了信息检索的精确性和全面性。
  • 自我增强和记忆功能:通过 Memory 模块,LLM 可以不断优化检索过程,提供更为精准的上下文信息。
  • 跨任务适应性:通过 Task Adapter 模块,RAG 可以根据不同的下游任务自动调整,以满足多种任务需求。

6.3 RAG与微调(Fine-Tuning)

RAG与其他模型优化方法在“是否需要外部知识”和“是否需要模型适应”方面的比较。提示工程(Prompt Engineering)对模型和外部知识的修改要求较低,主要侧重于利用大型语言模型(LLMs)本身的能力。而微调则涉及对模型的进一步训练。在RAG的早期阶段(简单RAG),对模型修改的需求较低。随着研究的进展,模块化RAG与微调技术的结合变得更加紧密。

6.4 检索(Retrieval)

RAG(检索增强生成模型)依赖外部知识来增强大语言模型(LLM)的能力,而检索源的类型和检索单元的粒度都会影响最终的生成结果。

1. 数据结构(Data Structure)

检索源的演变:最初,文本是主要的检索来源,随后扩展到半结构化数据(如PDF)和结构化数据(如知识图谱, KG)。除了从外部源进行检索外,近期的研究趋势还包括利用LLM自身生成的内容进行检索和增强。

检索单元的粒度:检索单元的粒度也会影响检索的效果。粗粒度的检索单元(如文档或句子)理论上可以提供更相关的信息,但也可能包含冗余内容,干扰下游任务。而细粒度的检索单元(如词语或短语)增加了检索的负担,且不能保证语义的完整性。选择合适的检索粒度是一种简单有效的策略,可以提升密集检索器的性能。

  • 文本中的粒度:从细粒度到粗粒度,粒度包括词语、短语、句子、命题、段落、文档等。DenseX 提出了使用命题作为检索单元的概念,命题被定义为文本中的原子表达,每个命题都封装了一个独特的事实信息,形式简洁、独立,旨在提高检索的精度和相关性。
  • 知识图谱中的粒度:在知识图谱中,检索粒度包括实体、三元组和子图等。粒度的选择也可以根据下游任务调整,如在推荐任务中检索物品ID,或者在问答任务中检索句子对等。

2. 索引优化(Indexing Optimization)

在索引阶段,文档会被处理、分段并转化为嵌入向量,存储在向量数据库中。索引的质量决定了检索阶段是否能获取到正确的上下文。

分段策略(Chunking Strategy):最常见的做法是将文档按照固定的令牌数进行分段(例如 100、256、512 等)。较大的分段能够捕捉更多上下文,但也会产生更多噪音,需要更长的处理时间和更高的成本。较小的分段可能无法完整传达必要的上下文,但噪音较少。为了解决这一问题,采用递归分割和滑动窗口的方法进行优化,使得不同的检索过程能够跨多个分段获取全局相关信息。

元数据附加(Metadata Attachments):分段可以通过附加元数据(如页码、文件名、作者、时间戳等)来丰富,从而在检索时基于元数据进行过滤,限制检索范围。元数据的不同权重可以在检索过程中实现时间感知 RAG,确保所用知识的时效性。

结构化索引(Structural Index):建立文档的层级结构可以有效提高检索效率。通过构建层级索引,RAG 系统可以快速检索和处理相关数据。知识图谱索引能够帮助保持一致性,并减少检索时的误差。此外,知识图谱还能将信息检索过程转化为 LLM 能够理解的指令,增强知识检索的精度和生成的上下文连贯性。

3. 查询优化(Query Optimization)

传统的 Naive RAG 依赖于用户原始查询进行检索,然而用户提问不够精确或清晰时,检索效果会受到影响。特别是,当查询本身很复杂,或者语言不够规范时,RAG 系统容易出现问题。

查询扩展(Query Expansion)

  • 多查询(Multi-Query):通过 LLM 进行查询扩展,将一个查询转化为多个并行查询,提供更丰富的上下文,确保生成答案的相关性。
  • 子查询(Sub-Query):将复杂的查询分解为一系列更简单的子问题,通过组合这些子查询来完整回答原始问题。这种方法类似于查询扩展,能提供更好的上下文。
  • 验证链(Chain-of-Verification,CoVe):扩展后的查询通过 LLM 进行验证,从而减少幻觉现象,提高检索结果的可靠性。

查询转化(Query Transformation)

  • 查询重写(Query Rewrite):LLM 可以重写查询,帮助生成更符合检索需求的问题。在实际应用中,像 BEQUE 就利用查询重写增强了对于长尾查询的召回效果。
  • 假设文档生成(HyDE):通过 LLM 生成假设性文档(即假设答案),在检索过程中计算查询和假设问题之间的相似度,从而缩小查询和答案之间的语义差距。
  • 退后提示(Step-back Prompting):将原始查询抽象成高层次概念问题,用于生成更有针对性的检索结果。

查询路由(Query Routing):基于查询的不同特点,路由到不同的 RAG 管道中,适应多样化的场景需求。

  • 元数据路由(Metadata Router):从查询中提取关键词(如实体),然后基于元数据进行过滤,缩小搜索范围。
  • 语义路由(Semantic Router):利用查询的语义信息进行路由,结合元数据和语义的混合路由方法,以提升查询路由效果。

4. 嵌入(Embedding)

在 RAG 系统中,通过计算查询和文档段落嵌入的相似度(例如余弦相似度)来实现检索。嵌入模型的语义表示能力在其中起着关键作用。

混合检索(Mix/Hybrid Retrieval):稀疏检索模型和密集检索模型可以互补,通过结合两者的优势,提升检索的多样性和准确性。例如,可以使用稀疏模型提供初步的搜索结果,再通过密集检索模型进行精细化检索。

微调嵌入模型(Fine-tuning Embedding Model):在某些领域,特别是在专业领域(如医疗、法律等)中,微调嵌入模型是必需的,以减少与预训练语料库的差异。通过使用 LLM 的结果作为监督信号进行微调,可以提高模型的性能。

5. 适配器(Adapter)

在微调模型时,可能会遇到一些问题,例如 API 集成或计算资源限制。因此,某些方法采用外部适配器来帮助对齐。

轻量级适配器(UPRISE):通过训练一个轻量级的提示检索器,自动从预构建的提示池中检索适合给定零-shot 任务输入的提示,从而优化 LLM 的多任务能力。

增强适配器(AAR):设计了一种通用适配器,能够适应多个下游任务,并提高在特定任务上的性能。

6.5 增强生成(Augmented Generation)

在RAG(检索增强生成)领域,标准的做法通常是先进行一次性检索,然后进行生成。这种方式可能导致效率低下,尤其对于需要多步推理的复杂问题,它提供的信息范围有限。为了解决这一问题,许多研究对检索过程进行了优化。除了最常见的单次检索,RAG还包括三种类型的检索增强过程。

(左) 迭代检索涉及在检索和生成之间交替进行,使每一步都能从知识库中获得更丰富、更有针对性的上下文。

(中)递归检索则通过逐步细化用户查询,将问题分解为子问题,然后通过检索和生成不断解决复杂问题。

(右)自适应检索侧重于使RAG系统能够自主判断是否需要外部知识检索,并决定何时停止检索和生成,通常使用LLM生成的特殊标记进行控制。

6.5.1 迭代检索(Iterative Retrieval)

迭代检索是一种基于初始查询和迄今为止生成的文本,反复检索知识库的方法,为LLM(大语言模型)提供更全面的知识基础。这种方法已被证明能够增强后续生成答案的鲁棒性,通过多次检索迭代,提供更多的上下文信息。然而,迭代检索可能会受到语义不连续性和冗余信息累积的影响。ITER-RETGEN提出了一种协同方法,将“检索增强生成”与“生成增强检索”结合起来,用于需要复现特定信息的任务。该模型利用生成的内容作为检索相关知识的上下文基础,从而在后续的迭代中生成更为精准的答案。

6.5.2 递归检索(Recursive Retrieval)

递归检索在信息检索和自然语言处理(NLP)中常用于提高搜索结果的深度和相关性。这个过程涉及基于先前搜索结果不断优化查询。递归检索旨在通过反馈循环逐渐接近最相关的信息,从而改善搜索体验。IRCoT使用了思维链(chain-of-thought)来指导检索过程,并基于获得的检索结果优化思维链。ToC则创建了一个澄清树,系统地优化查询中模糊的部分。递归检索尤其适用于复杂的搜索场景,其中用户需求从一开始就不完全明确,或者所需信息非常专业或细致。递归过程允许系统不断学习和适应用户需求,从而通常能提高搜索结果的满意度。

为了应对特定的数据场景,递归检索与多跳检索技术可以结合使用。递归检索涉及结构化索引,以分层方式处理和检索数据,这可能包括在执行检索之前对文档或长PDF进行总结。随后,基于这些摘要进行二次检索,体现了递归过程的特点。与此相对,多跳检索则旨在深入挖掘图结构数据源,提取相互关联的信息。

6.5.3 自适应检索(Adaptive Retrieval)

自适应检索方法通过允许LLM主动决定最佳的检索时机和内容,优化了RAG框架,从而提高了信息来源的效率和相关性。例如,Flare和Self-RAG就是通过这种方法来优化检索过程。随着这一趋势的发展,越来越多的LLM开始在其操作中主动做出判断,例如在模型代理(如AutoGPT、Toolformer和Graph-Toolformer)中也能看到这种趋势。Graph-Toolformer 就是将检索过程分为多个步骤,LLM主动使用检索器、应用Self-Ask技术,并采用少样本提示来发起搜索查询。这种主动的策略使得LLM能够决定何时需要检索信息,类似于代理在使用工具时的判断。

WebGPT引入了强化学习框架,训练GPT-3模型在文本生成过程中自主使用搜索引擎。它通过特殊的标记来导航这一过程,包括搜索引擎查询、浏览结果和引用参考文献,从而通过外部搜索引擎扩展GPT-3的能力。Flare则通过监控生成过程的置信度(如生成词汇的概率)来自动化检索时机,当概率低于某个阈值时,激活检索系统收集相关信息,从而优化检索周期。Self-RAG引入了“反思标记”,让模型能够自我反思其输出。这些标记有两种类型:“检索”和“批评”。模型可以自主决定何时启动检索,或者通过预设阈值触发检索过程。在检索过程中,生成器通过在多个段落中进行碎片级束搜索,得出最连贯的序列。批评分数用于更新细分分数,并且可以在推理过程中调整这些权重,从而量身定制模型的行为。Self-RAG的设计避免了额外分类器或依赖自然语言推理(NLI)模型,从而简化了何时启用检索机制的决策过程,提高了模型在生成准确回答时的自主判断能力。下图是Self-RAG的整体架构图。

6.6 RAG生态系统

综上所述,RAG生态系统如下图所示:

RAG的评价指标如下,其中包含了一些基准线(benchmark)和工具(tool)。

6.7 RAG的未来发展方向

RAG的未来发展方向包括:

  • RAG与长文本:长文本往往超出了传统模型能够处理的上下文长度。许多模型有输入长度的限制,当文本长度过长时,可能会出现截断现象。这会影响模型对全文的理解,尤其是当重要信息被截断时,系统可能无法提供完整的答案。长文本中的不同部分可能涉及不同的主题、背景或情节,如何确保检索到的信息与当前生成的内容保持一致性至关重要。
  • RAG的健壮性:RAG可能会面临检索过程中引入的噪声,例如与查询无关的文档或片段,或是检索到的文本含有误导性信息。噪声数据会影响生成结果的准确性和相关性。有时需要处理用户提出的模糊、含糊不清的查询,这些查询可能没有明确的意图或是包含多重意思。在这种情况下,RAG系统需要有效地推理和生成相关答案。
  • RAG的扩展规律(Scaling Law):随着数据集的增大,检索过程的复杂度会显著提升。需要优化检索算法和数据结构,以保持检索效率。通常,扩大检索规模可以提高生成结果的质量,但同时也可能增加不相关信息的干扰。
  • 生产级RAG:指已经优化并可以在实际环境中稳定运行的RAG系统。这类系统不仅要求具有高效的检索和生成能力,还需要具备可扩展性、低延迟和高可靠性等特点。
  • 混合方法:混合方法是指将多种不同的技术或模型结合起来,以优化RAG系统的性能。常见的混合方法包括将稀疏检索(例如BM25)与密集检索(例如BERT架构)结合,或者将规则驱动的系统与深度学习模型结合使用。
  • 多模态的RAG:图片、音频、视频、代码等作为知识库和信息输入也是存在着一定的挑战。

7.  参考资料

  1. Gao Y, Xiong Y, Gao X, et al. Retrieval-augmented generation for large language models: A survey[J]. arXiv preprint arXiv:2312.10997, 2023, 2.
  2. Gao Y, Xiong Y, Zhong Y, et al. Synergizing RAG and Reasoning: A Systematic Review[J]. arXiv preprint arXiv:2504.15909, 2025.
  3. Li X, Jia P, Xu D, et al. A Survey of Personalization: From RAG to Agent[J]. arXiv preprint arXiv:2504.10147, 2025.
  4. Arslan M, Ghanem H, Munawar S, et al. A Survey on RAG with LLMs[J]. Procedia Computer Science, 2024, 246: 3781-3790.
  5. Fan, Wenqi, et al. “A survey on rag meeting llms: Towards retrieval-augmented large language models.” Proceedings of the 30th ACM SIGKDD Conference on Knowledge Discovery and Data Mining. 2024.

GPT4All:本地部署的开源大语言模型

1.  GPT4All简介

1.1 开源项目

GPT4All 是由 Nomic AI 开发的一个开源项目,旨在让用户能够在个人设备上本地运行大型语言模型(LLM),无需依赖云服务。 这一项目自发布以来,已成为 GitHub 上增长最快的开源项目之一,拥有超过 7 万个 GitHub 星标。

1.2 适用场景

使用GPT4All的话有以下优势:

  • 隐私保护:处理敏感数据时,确保信息不外泄。
  • 离线使用:在没有网络连接的环境中使用 AI。
  • 教育与研究:用于教学、研究或学习目的。
  • 定制化需求:根据特定需求定制 AI 模型。

2.  核心特点

2.1. 完全本地运行,无需互联网连接

GPT4All 允许用户在 Windows、macOS 和 Linux 等操作系统上本地运行 LLM。 用户可以下载模型文件(通常为 1GB 至 8GB),并在没有网络连接的情况下使用 AI 聊天。

2.2 支持多种硬件平台

该项目支持多种硬件平台,包括支持 AVX 指令集的 CPU,以及 Apple M 系列芯片、AMD 和 NVIDIA GPU 等。 这使得用户能够在不同的设备上体验本地 LLM。

2.3 隐私优先

GPT4All 强调数据隐私,默认情况下,用户的对话数据不会离开本地设备。 如果用户选择使用远程模型或参与数据共享,系统会明确提示并征得同意。

2.4 丰富的模型支持

GPT4All 支持多种开源模型,包括 LLaMa、Mistral、DeepSeek R1、Nous-Hermes 等。 用户可以根据需求选择不同的模型进行本地部署。详情可以参考链接:https://github.com/nomic-ai/gpt4all/blob/main/gpt4all-chat/metadata/models3.json

2.5 集成本地文档支持

GPT4All 提供 LocalDocs 功能,允许用户将本地文档(如 PDF、TXT、Markdown 等)导入系统,与 AI 进行交互。 这对于处理敏感或私密信息非常有用。

3.  快速上手指南

3.1 下载并安装软件

访问下载适用于您操作系统(Windows、Mac、Linux)的安装包。

3.2 添加模型

启动应用程序后,点击“+ Add Model”按钮,选择并下载您需要的模型。

3.3 开始聊天

下载模型后,进入“Chats”界面,选择已加载的模型,开始与 AI 进行对话。并且还提供上传本地文件资料的功能,实现知识库的搜索。

3.4 使用Python的SDK

3.4.1 大语言模型

GPT4All 提供了 Python SDK,方便开发者将其集成到自己的项目中。 此外,项目采用 MIT 开源许可证,允许用户进行自定义和二次开发。

安装方法:

pip install gpt4all

使用方法:

可以按照官方提供的模板进行使用,如果模型没有提前下载的话,在第一次使用的时候,代码会自动下载模型。

from gpt4all import GPT4All
model = GPT4All("Meta-Llama-3-8B-Instruct.Q4_0.gguf") # downloads / loads a 4.66GB LLM
with model.chat_session():
    print(model.generate("How can I run LLMs efficiently on my laptop?", max_tokens=1024))

如果想要进行流式输出或者一次性输出,可以使用streaming这个参数进行控制,参考代码:

from gpt4all import GPT4All

def output_with_stream_control(prompt: str, model_name: str = "Meta-Llama-3-8B-Instruct.Q4_0.gguf", max_tokens: int = 1024, streaming: bool = False):
    model = GPT4All(model_name)  # 加载指定模型

    # 创建一个对话会话
    with model.chat_session() as session:
        response_buffer = ""

        if streaming:
            # 启用流式输出
            for chunk in model.generate(prompt, max_tokens=max_tokens, streaming=streaming):
                response_buffer += chunk
                print(chunk, end='', flush=True)  # 实时输出生成的文本
            print("\n\n生成的完整答案:", response_buffer)
        else:
            # 批量输出(等待完整生成后返回)
            response_buffer = model.generate(prompt, max_tokens=max_tokens, streaming=streaming)
            print("\n生成的完整答案:", response_buffer)

        return response_buffer

if __name__ == "__main__":
    prompt = "用中文回答,什么是化学?"
    result = output_with_stream_control(prompt, streaming=False)
    print('result:', result)

模型的选择范围很多,当前支持的部分模型可以参考表格:

GPT4All model nameFilesizeRAM RequiredParametersQuantizationDeveloperLicenseMD5 Sum (Unique Hash)
Meta-Llama-3-8B-Instruct.Q4_0.gguf4.66 GB8 GB8 Billionq4_0MetaLlama 3 Licensec87ad09e1e4c8f9c35a5fcef52b6f1c9
Nous-Hermes-2-Mistral-7B-DPO.Q4_0.gguf4.11 GB8 GB7 Billionq4_0Mistral & Nous ResearchApache 2.0Coa5f6b4eabd3992da4d7fb7f020f921eb
Phi-3-mini-4k-instruct.Q4_0.gguf2.18 GB4 GB3.8 billionq4_0MicrosoftMITf8347badde9bfc2efbe89124d78ddaf5
orca-mini-3b-gguf2-q4_0.gguf1.98 GB4 GB3 billionq4_0MicrosoftCC-BY-NC-SA-4.00e769317b90ac30d6e09486d61fefa26
gpt4all-13b-snoozy-q4_0.gguf7.37 GB16 GB13 billionq4_0Nomic AIGPL40388eb2f8d16bb5d08c96fdfaac6b2c

同时,SDK的所有参数可以参考链接:https://docs.gpt4all.io/gpt4all_python/ref.html#gpt4all.gpt4all.GPT4All.list_models

3.4.2 嵌入模型

除了大语言模型之外,它还提供三种嵌入模型,其本地调用的使用案例如下所示:

from nomic import embed
embeddings = embed.text(["String 1", "String 2"], inference_mode="local")['embeddings']
print("Number of embeddings created:", len(embeddings))
print("Number of dimensions per embedding:", len(embeddings[0]))

其嵌入模型有三个:

NameUsing with nomicEmbed4All model nameContext LengthEmbedding DimensionsFile Size
Nomic Embed v1embed.text(strings, model=”nomic-embed-text-v1″, inference_mode=”local”)Embed4All(“nomic-embed-text-v1.f16.gguf”)2048768262 MiB
Nomic Embed v1.5embed.text(strings, model=”nomic-embed-text-v1.5″, inference_mode=”local”)Embed4All(“nomic-embed-text-v1.5.f16.gguf”)204864-768262 MiB
SBertn/aEmbed4All(“all-MiniLM-L6-v2.gguf2.f16.gguf”)51238444 MiB

4.  参考资料:

  1. GPT4All的GitHub地址:https://github.com/nomic-ai/gpt4all
  2. GPT4All的文档:https://docs.gpt4all.io/
  3. nomic的官网:https://www.nomic.ai/
  4. 模型的选择范围:https://github.com/nomic-ai/gpt4all/blob/main/gpt4all-chat/metadata/models3.json

Python代码检测工具

代码规范

对于程序员而言,代码规范不仅仅是为了让代码看起来更整洁,它直接影响着代码的可读性、可维护性和团队的协作效率。统一的代码风格使得团队成员能够快速理解彼此的代码,无论是在日常的开发、代码审查还是修复bug时,都能有效避免因风格差异带来的误解或错误。遵循代码规范还能帮助提高代码质量,降低潜在的bug风险,并且对后期的扩展与重构更加友好。尤其是在大型项目或多团队协作的情况下,良好的代码规范更是保证项目可持续发展的基石。因此,始终坚持良好的代码规范是每个开发者应尽的责任,它不仅仅是为了提升个人编程习惯,更是为了整个团队的协同作战与代码的长期健康。

Python代码规范

Python 提倡简洁、清晰、易读的代码风格,PEP 8 是 Python 社区推荐的官方代码风格指南,它帮助开发者统一代码风格,提高代码的可读性和可维护性。遵循 Python 代码规范不仅有助于开发者之间的协作,还能让代码更加规范化,减少潜在的错误。以下是一些常见的 Python 代码规范。

1. 命名规范

  • 变量、函数和方法的命名:使用小写字母,并通过下划线 _ 分隔单词(即蛇形命名法)。例如:user_age,calculate_total()
  • 类名的命名:使用首字母大写的驼峰命名法。例如:UserProfile,OrderProcessor
  • 常量命名:所有字母大写,单词间使用下划线分隔。例如:MAX_RETRIES,PI
  • 私有变量和方法:以单下划线 _ 开头,表示该变量或方法是内部使用,不应直接访问。例如:_internal_data
  • 避免使用Python保留字(如 class、if、try 等)作为变量名。

2. 缩进与空格

  • 缩进:使用 4 个空格进行缩进,不要使用制表符(Tab)。这是 Python 语法要求的,错误的缩进会导致语法错误。
  • 行内空格:在运算符两边加空格,增强可读性。
    例如:对于赋值:x = 10
    对于运算符:y = x + 5
  • 函数参数的空格:函数定义和调用时,参数列表的两边不要加空格。例如:
def add_numbers(a, b):    
    return a + b
  • 括号内的空格:不要在括号内多余的地方加空格。例如:
my_list = [1, 2, 3]  # 正确
my_list = [ 1, 2, 3 ]  # 错误

3. 行长限制

单行长度:每行代码的长度建议不超过 79 个字符。对于文档字符串(docstring)和长注释,推荐不超过 72 个字符。这有助于提高代码的可读性,尤其是在显示设备宽度有限时。如果行长超过限制,可以使用反斜杠 \ 进行换行,或者在括号、列表、字典等容器中自动换行。

4. 文档字符串(Docstring)

模块和类:在模块和类定义后,添加文档字符串说明其功能。文档字符串应该简洁明了,并且应说明类和模块的主要功能和用途。

class Calculator:    
    """This class performs basic arithmetic operations."""    
    pass
  • 函数和方法:为每个函数和方法提供文档字符串,描述其作用、参数和返回值。
def add(a, b):
    """
    Add two numbers and return the result.
    
    Parameters:
    a (int or float): The first number.
    b (int or float): The second number.
    
    Returns:
    int or float: The sum of a and b.
    """
    return a + b

5. 异常处理

异常捕获:应该尽量避免使用过于宽泛的 except 块,避免捕获不必要的异常。应当明确捕获特定异常。

try:
    x = 1 / 0
except ZeroDivisionError as e:
    print(f"Error: {e}")

多个异常捕获:如果需要捕获多种异常,可以使用元组来列出这些异常类型。

try:
    some_code()
except (TypeError, ValueError) as e:
    print(f"Error: {e}")

6. 导入顺序

标准库导入:首先导入 Python 标准库模块,如 os、sys 等。

第三方库导入:其次导入外部安装的第三方库,例如 numpy、pandas、requests 等。

本地应用库导入:最后导入你自己编写的模块或应用库。

按照以上顺序,导入部分每一类模块之间应该留一行空行。例如:

import os
import sys

import numpy as np
import pandas as pd

from mymodule import my_function

7. 避免重复代码

Python 提供了许多库和工具,可以避免代码重复。如果发现自己写了类似的代码片段多次,应考虑将其提取成函数或类,提升代码的复用性。适当使用 Python 的标准库,如 itertools、functools 等,避免自己手动实现复杂的功能。

遵循 Python 代码规范能够帮助我们编写更简洁、更易于理解和维护的代码。最重要的规范包括命名规则、缩进与空格、行长限制、文档字符串、异常处理等。在大型项目中,团队成员遵循统一的规范可以提高协作效率,减少因代码风格不一致带来的混乱和错误。因此,开发者应该积极遵循 PEP 8 等官方规范,并利用代码规范检查工具(如 flake8、pylint 等)来保持代码质量。

圈复杂度

圈复杂度(Cyclomatic Complexity)是衡量一个程序的控制流复杂度的一个指标,它由 Thomas McCabe 于 1976 年提出。圈复杂度的核心思想是衡量程序中独立路径的数量,反映了程序中控制流的复杂程度。简单来说,圈复杂度可以帮助你了解一个程序有多少条不同的执行路径。

为什么圈复杂度重要?

  • 高圈复杂度:意味着代码中有很多的判断、循环和分支,程序的执行路径复杂。高复杂度的代码难以理解、测试和维护。
  • 低圈复杂度:意味着代码结构简单,控制流清晰,容易理解和维护。

计算圈复杂度

圈复杂度的计算公式为:

V(G)=E−N+2P,其中:

  • V(G) 是圈复杂度(Cyclomatic Complexity)。
  • E 是程序图中的边的数量(边代表程序控制流的转移,比如跳转、条件等)。
  • N 是程序图中的节点的数量(节点代表基本块,即一组顺序执行的语句)。
  • P 是程序图中的连通组件的数量(一般情况下 P = 1,即程序是一个连通的整体)。

具体解释:

E:程序的控制流转移数量。例如,if、while、for、case 语句的数量都会增加边的数量。

N:控制流图中节点的数量,代表代码的块,例如顺序执行的语句组。

P:通常程序只有一个连通组件,即 P = 1,代表程序是一个整体。

直观解释

可以通过 控制流图 来理解圈复杂度。控制流图是一个图论的概念,它将程序的每个基本块(例如条件判断、循环等)表示为图中的节点,程序的控制流(跳转)表示为边。圈复杂度就是计算该图中所有独立路径的数量。

例如,下面是一个简单的代码示例:

def example(a):
    if a > 10:
        return "greater"
    else:
        return "lesser"

这段代码的控制流图非常简单,只有两个分支。它的圈复杂度为 2,因为有两个独立的路径(a > 10 和 a <= 10)。

计算圈复杂度的示例:

  1. 简单顺序执行
def simple_function():
    a = 5
    b = 10
    c = a + b
    return c
  • 控制流图:只有一个顺序的执行,没有条件和分支。
  • 圈复杂度:1(只有一个路径,程序从头到尾顺序执行)
  • 条件判断
def function_with_if(a):
    if a > 10:
        return "greater"
    else:
        return "lesser"

控制流图:有一个 if 语句,形成两个分支路径。圈复杂度:2(一个条件判断,两个路径)

  • 循环语句
def function_with_while(a):
    while a > 0:
        a -= 1
    return a

控制流图:有一个 while 循环,形成一个循环路径。

圈复杂度:2(一个循环结构,两个路径:一个是 while 循环路径,另一个是跳出循环后的路径)

如何使用圈复杂度?

  1. 代码可维护性:高圈复杂度意味着代码结构复杂,容易引入 bug,不利于维护。因此,圈复杂度高的代码通常需要重构。
  2. 测试覆盖率:圈复杂度的一个重要应用是 测试路径覆盖,它提供了最小路径集 的数量,这些路径集需要被单元测试覆盖。如果圈复杂度是 10,那么最少需要设计 10 个不同的测试用例来保证所有路径都被测试。
  3. 代码审查和重构:高圈复杂度通常提示代码不易理解或过于复杂,可能需要重构,降低复杂度,提高可读性。

小结:

  • 低圈复杂度:代码清晰,易于理解和维护,测试更容易覆盖。
  • 高圈复杂度:代码难以理解和测试,容易出错,可能需要重构。

圈复杂度是衡量代码复杂度的重要指标,它能帮助开发者评估代码的质量和可维护性。

Python代码检测工具使用指南

本文介绍多种常用的Python代码检测工具(pylint、flake8、ruff),涵盖安装方法基本使用以及项目级检查的实践指导,帮助开发者快速实现代码质量分析与规范检查。

1. Pylint

1.1 安装

使用pip就可以轻松地把pylint这个工具安装好。

pip install pylint

1.2 使用场景

检查单个文件

pylint my_script.py # 检查单个文件

检查文件夹

pylint src/  # 递归检查目录下所有.py文件

检查项目

pylint project/ --recursive=y # 检查项目

1.3 配置与过滤

生成配置文件:

pylint --generate-rcfile > .pylintrc

如果不想看某类错误的时候,我们可以选择忽略特定错误:

pylint my_script.py --disable=E1101,C0114  # 关闭未解析的属性和缺失docstring警告

2. Flake8

2.1 安装

使用pip就可以轻松地把flake8这个工具安装好。

pip install flake8

2.2 使用场景

检查单个文件

flake8 my_script.py  # 检查单个文件

检查文件夹

flake8 src/  # 检查所有.py文件

检查项目

可以通过下述命令来检查当前的目录和所有子目录

flake8 .  # 递归检查当前目录及子目录

同时,flake8默认会使用pep8第三方包检查代码(经常会安装mccabe和pyflakes,安装之后,flake8就会提供个性的功能)。 pep8第三方包只能检查代码是否符合 pep8 代码规范(所以 flake8默认是使用pep8代码规范做检查)。

相对于Pylint ,flake8提供了些特有的功能。

  • 检查代码的圈复杂度(flake8会调用mccabe计算圈复杂度)。
  • 圈复杂度和if语句有关,选择分支越多,圈复杂度越高。
  • 圈复杂度越低越好。圈复杂度高影响代码可读性,代码容易出错。
  • flake8官网建议圈复杂不要超过 12 。

2.3 配置与扩展

配置文件支持:在 setup.cfg 或 .flake8 中配置规则:

pip install flake8-mutable  # 安装可变默认参数检测插件flake8 --enable-extensions MutableDefaultArg

3. Ruff

3.1 安装

使用pip就可以轻松地把ruff这个工具安装好。

pip install ruff
# 或使用独立二进制(无Python环境依赖):
curl -Ls https://github.com/astral-sh/ruff/releases/latest/download/ruff-linux-amd64 | sudo tee /usr/local/bin/ruff >/dev/null && sudo chmod +x /usr/local/bin/ruff

3.2 使用场景

检查单个文件

ruff check my_script.py

检查文件夹/项目

ruff check src/  # 检查目录ruff check .     # 检查整个项目

自动修复问题

ruff check --fix my_script.py

3.3 配置

兼容flake8配置:直接复用 .flake8 或 pyproject.toml,或在 pyproject.toml 中指定规则:[tool.ruff] line-length = 100 ignore = [“E501”, “F401”]

4.  Mccabe

这是用来检查圈复杂度的工具

4.1 安装

pip install mccabe
pip install --upgrade mccabe
pip uninstall mccabe

4.2 使用场景

python -m mccabe --min 5 mccabe.py
("185:1: 'PathGraphingAstVisitor.visitIf'", 5)
("71:1: 'PathGraph.to_dot'", 5)
("245:1: 'McCabeChecker.run'", 5)
("283:1: 'main'", 7)
("203:1: 'PathGraphingAstVisitor.visitTryExcept'", 5)
("257:1: 'get_code_complexity'", 5)

5.  Prospector

5.1 Prospector项目介绍

Prospector 是一款专为 Python 代码设计的强大分析工具,它旨在提供关于错误、潜在问题、规范违规以及复杂性方面的详尽信息。这款工具集成了诸如 Pylint、pycodestyle 和 McCabe 等众多Python代码分析工具的功能于一身。通过自定义配置文件(即“profile”),Prospector 提供了适用于大多数情况的默认配置,旨在帮助开发者在无需大量前期设置的情况下即可开始提升代码质量。它还能够适应项目所依赖的特定库和框架,比如自动调整对 Django 或 Celery 的支持,以减少误报。

5.2 项目快速启动

要迅速开始使用 Prospector,首先确保你的环境中安装了 Python 和 pip。然后,执行以下命令来安装 Prospector:

pip install prospector

安装完毕后,在你的Python项目根目录下运行 Prospector,即可获取到代码审查报告:

cd /path/to/your/python/projectprospector

这将输出可能存在的问题列表,帮助你识别和修正代码中的隐患。对于更定制化的控制,可以添加额外参数,例如使用 –strictness medium 来设定中等严格的检查级别。

prospector --strictness high

5.3 应用案例和最佳实践

在使用 Prospector 时,一个典型的最佳实践是将其集成到持续集成(CI)流程中。比如,通过 .pre-commit-config.yaml 文件配置预提交钩子,确保每次提交前都经过代码质量检查:

repos:
  - repo: https://github.com/PyCQA/prospector
    rev: 1.10.0  # 使用具体版本或'master'以获取最新版本
    hooks:
      - id: prospector
        args: ["--summary-only"]  # 只显示总结,简化输出

对于团队协作项目,通过创建适合自己团队编码风格的配置文件(prospector.yml),可以进一步优化Prospector的行为,确保所有开发者遵循一致的标准。

5.4 典型生态项目

Prospector 在 Python 生态中扮演着重要角色,尤其是在那些重视代码质量和一致性维护的项目中。结合其他生态项目,如 mypy 进行静态类型检查,或 bandit 进行安全审计,可以构建出更全面的质量保障体系。Prospector的设计使其能与这些工具良好协同工作,通过在Prospector中启用相应插件,可以实现多维度的代码检查。

通过简单的配置和灵活的插件机制,Prospector不仅提升了单个项目的开发效率,也促进了整个Python社区代码标准的一致性和代码质量的普遍提升,成为了现代软件开发生命周期中不可或缺的一部分。

参考资料

  1. 代码检查工具文档介绍:https://wangmeng-python.readthedocs.io/en/latest/readability/code-analysis-tools.html
  2. Mccabe的GitHub链接:https://github.com/pycqa/mccabe
  3. Prospector的GitHub链接:https://github.com/prospector-dev/prospector
  4. ruff:https://myapollo.com.tw/blog/python-linter-ruff/

Ollama简介:让大模型走进每个开发者的工具箱

Ollama的介绍

Ollama 是一款强大的人工智能语言大模型(LLM)平台,专注于为开发者和企业提供高效、可定制的文本生成和自然语言处理能力。通过集成先进的深度学习技术,Ollama 能够在本地帮助用户生成高质量的文章、解答复杂问题、提供自动化客服支持等。无论是内容创作、数据分析,还是智能客服系统,Ollama 都能提供灵活的解决方案,并支持跨平台应用。凭借其易用的接口、快速的响应速度和强大的定制化功能,Ollama 已成为越来越多开发者和企业的首选工具,为他们在复杂任务中提供智能化的辅助和支持。


不仅如此,Ollama还提供了一些非常简单的方式来下载、运行、加载和使用各种预训练的开源大语言模型,支持文本生成、知识问答等常见的自然语言处理功能。在Ollama的加持下,NLP不再是只有深度学习背景的开发者才能够接触的领域。

Ollama的入门

在GitHub的官网上,可以找到Ollama的链接是:https://github.com/ollama/ollama。同时,它可以支持MAC、Windows、Linux的使用,并且Linux的下载和安装命令如下:

curl -fsSL https://ollama.com/install.sh | sh

除此之外,Ollama还支持通过Docker的方式进行部署。在使用Ollama的之前,需要将其安装在电脑上,根据不同的操作系统,可以选择不同的安装方式。

下载与安装

Windows系统

打开浏览器,访问 Ollama 官方网站:https://ollama.com/download,下载适用于 Windows 的安装程序。下载地址为:https://ollama.com/download/OllamaSetup.exe。下载完成后,双击安装程序并按照提示完成安装。打开命令提示符或 PowerShell,输入以下命令验证安装是否成功:

ollama --version

如果上述命令显示版本号,则表示安装成功。

Mac系统

打开浏览器,访问 Ollama 官方网站:https://ollama.com/download,下载适用于 macOS 的安装程序。下载地址为:https://ollama.com/download/Ollama-darwin.zip。下载完成后,双击安装包并按照提示完成安装。安装完成后,通过以下命令验证:

ollama --version

如果上述命令显示版本号,例如ollama version is 0.6.5,则表示安装成功。如果显示zsh: command not found: ollama,则表示没有安装成功。

Linux系统

在Linux系统上,可以一键安装ollama,输入以下命令即可:

curl -fsSL https://ollama.com/install.sh | bash

安装完成后,通过以下命令验证:

ollama --version

如果上述命令显示版本号,则表示安装成功。

部分模型

在GitHub的官网上,我们可以看到Ollama可以支持和下载的模型种类是非常多的,包括Gemma、DeepSeek、Llama、LLaVA等,并且不同的大小也可以通过参数来进行选择。通常来说,模型的参数越多,模型的大小也就越大。更全的模型库可以参考链接:https://ollama.com/library

模型参数大小下载并运行
Gemma 31B815MBollama run gemma3:1b
Gemma 34B3.3GBollama run gemma3
Gemma 312B8.1GBollama run gemma3:12b
Gemma 327B17GBollama run gemma3:27b
QwQ32B20GBollama run qwq
DeepSeek-R17B4.7GBollama run deepseek-r1
DeepSeek-R1671B404GBollama run deepseek-r1:671b
Llama 3.370B43GBollama run llama3.3
Llama 3.23B2.0GBollama run llama3.2
Llama 3.21B1.3GBollama run llama3.2:1b
Llama 3.2 Vision11B7.9GBollama run llama3.2-vision
Llama 3.2 Vision90B55GBollama run llama3.2-vision:90b
Llama 3.18B4.7GBollama run llama3.1
Llama 3.1405B231GBollama run llama3.1:405b
Phi 414B9.1GBollama run phi4
Phi 4 Mini3.8B2.5GBollama run phi4-mini
Mistral7B4.1GBollama run mistral
Moondream 21.4B829MBollama run moondream
Neural Chat7B4.1GBollama run neural-chat
Starling7B4.1GBollama run starling-lm
Code Llama7B3.8GBollama run codellama
Llama 2 Uncensored7B3.8GBollama run llama2-uncensored
LLaVA7B4.5GBollama run llava
Granite-3.28B4.9GBollama run granite3.2

DeepSeek-r1会有不同的模型参数和大小,最少的模型参数是1.5b,最大的模型参数是671b。这些可以在Ollama的官网上找到,并且可以基于本地电脑的配置下载到本地电脑进行运行。在运行模型的时候,请注意mac的内存情况,以及参考Ollama官方提供的建议:You should have at least 8 GB of RAM available to run the 7B models, 16 GB to run the 13B models, and 32 GB to run the 33B models.

Ollama的使用

模型下载

使用帮助命令可以查到ollama的常见命令如下:

ollama -h

目前以操作deepseek-r1:7b模型为例,当你只需要下载模型的时候,需要使用命令:

ollama pull deepseek-r1:7b

当你需要下载模型并且运行的时候,需要使用命令,同时就会进入对话功能,正常的使用即可。退出的时候可以使用ctrl+d或者/bye即可。

ollama run deepseek-r1:7b

如果想查看该模型的细节,可以用show命令进行展示。

ollama show deepseek-r1:7b

当你想查看Ollama安装了多少大模型的时候,可以使用命令:

ollama list

在mac上执行ollama serve,会出现Error: listen tcp 127.0.0.1:11434: bind: address already in use的错误。原因是:Mac安装Ollama后,启动Ollama后会本地监听本地TCP的11434端口,但这个监听仅仅是本地层面的监听,无法被本地以外的主机访问,也就是无法被同网段的主机访问。如果其他主机需要访问的话,需要采用docker部署的方式,重新修改一个新的端口即可,同时对外开放相应的端口。

模型交互

命令行交互

在mac上启动命令行,可以将模型直接启动起来,进入对话模式。

ollama run deepseek-r1:7b

在交互模式下,输入/bye或按下Ctrl+d退出即可。

单次命令交互

通过管道将输入传递给相应的模型,模型进行输出,例如输入“什么是数学?”就可以用以下命令:

echo "什么是数学?" | ollama run deepseek-r1:7b

使用命令行参数

甚至还可以直接在命令行中传递输入以下内容,直接获得结果。

ollama run deepseek-r1:7b "撰写一份周报的模板"

使用文件交互,例如有一个文件是input_text_1.txt,内容是“什么是化学?”,那么通过这个符号<以及路径和文件就可以输入给模型,并且得到输出的结果。

ollama run deepseek-r1:7b </Users/zr9558/Documents/Datasets/text/input_text_1.txt 

自定义提示词

通过 Modelfile 定义自定义提示词或系统指令,使模型在交互中遵循特定规则。创建自定义模型,编写一个 Modelfile:

FROM deepseek-r1:7b SYSTEM "你是一个编程助手,专门帮助用户编写代码。"

创建自定义模型:

ollama create runoob-model -f ./Modelfile

运行自定义模型:

ollama run runoob-model

发送请求交互

通过curl命令可以看到当前端口启动的模型:

curl http://localhost:11434/api/tags

通过curl命令和相应的参数配置,可以实现发送请求给本地mac启动的模型。

curl http://localhost:11434/api/generate -d '{
  "model": "deepseek-r1:7b",
  "prompt": "什么是生物学?主要研究哪些方向?",
  "stream": false
}'

还可以增加更为复杂的参数进行curl请求,其中options里面就是模型的参数选择。

curl http://localhost:11434/api/generate -d '{
  "model": "deepseek-r1:7b",
  "prompt": "什么是生物学?主要研究哪些方向?",
  "stream": false,
  "options": {
    "temperature": 0.7,
    "max_tokens": 100
  }
}'

如果选择stream是true,则用流式进行输出,那么则是逐行输出,每一行的输出是就是词语或者汉字字符,把每一行的response汇总到一起就是最终的输出。

curl http://localhost:11434/api/generate -d '{
  "model": "gemma3:27b",
  "prompt": "用一句话介绍数学是什么?",
  "stream": true
}'

Python 交互

ollama提供了多种方式与Python代码进行交互,包括request,ollama SDK等。

requests 交互

可以直接使用Python的requests模块发送请求,并获得相应的结果。

import requests

# 生成文本
response = requests.post(
    "http://localhost:11434/api/generate",
    json={
        "model": "gemma3:27b",
        "prompt": "用一句话介绍什么是线性代数",
        "stream": False
    }
)
print(response.json())

另外,还可以这样去写代码:

import requests
response = requests.post(
    "http://localhost:11434/api/chat",
    json={
        "model": "gemma3:27b",
        "messages": [
            {
                "role": "user",
                "content": "用一句话描述什么是实变函数"
            }
        ],
        "stream": False
    }
)
print(response.json())

Ollama 交互

Ollama有python的SDK,可以使用python的版本,其GitHub源码链接是https://github.com/ollama/ollama-python。使用pip就可以完成安装:

pip install ollama

然后在Mac的PyCharm中使用以下代码,就可以发送请求给模型,进行结果的一次性返回:

from ollama import chat
from ollama import ChatResponse

response: ChatResponse = chat(model='gemma3:27b', messages=[
  {
    'role': 'user',
    'content': '用一句话介绍什么是泛函分析',
  },
])
# 打印响应内容
print(response['message']['content'])

print('-'*40)

# 或者直接访问响应对象的字段
print(response.message.content)

如果要做流式输出,则可以采用以下方法:

from ollama import chat

stream = chat(
    model='deepseek-r1:32b',
    messages=[{'role': 'user', 'content': '什么是数学分析?'}],
    stream=True,
)

# 逐块打印响应内容
for chunk in stream:
    print(chunk['message']['content'], end='', flush=True)


ollama的chat 方法可以与模型进行对话生成,发送用户消息并获取模型响应:

import ollama

print(ollama.chat(model='gemma3:27b', messages=[{'role': 'user', 'content': '用一句话介绍:数学中的动力系统是什么?'}]))

输出以下内容:

model=’gemma3:27b’ created_at=’2025-04-15T02:56:36.041842Z’ done=True done_reason=’stop’ total_duration=3464291750 load_duration=48093500 prompt_eval_count=20 prompt_eval_duration=433924792 eval_count=22 eval_duration=2981754125 message=Message(role=’assistant’, content=’数学中的动力系统研究的是随时间变化的系统,尤其是系统状态如何随时间演变。\n’, images=None, tool_calls=None)

如果只需要输出message中content 的部分,则可以这样修改代码:

import ollama

print(ollama.chat(model='gemma3:27b', messages=[{'role': 'user', 'content': '用一句话介绍:数学中的动力系统是什么?'}]).message.content)

ollama的generate方法用于文本生成任务。与chat方法类似,但是它只需要一个prompt参数。同时,如果只需要查看response的时候,就可以参考以下代码:

import ollama

print(ollama.generate(model='gemma3:27b', prompt='用一句话介绍:数学中的常微分方程是什么?'))

print(ollama.generate(model='gemma3:27b', prompt='用一句话介绍:数学中的常微分方程是什么?').response)

ollama的list方法可以列出所有可用的模型:

import ollama print(ollama.list())

ollama的show方法可以显示指定模型的详细信息:

import ollama print(ollama.show('deepseek-r1:32b'))

ollama的embed方法可以输出文本嵌入:

import ollama

print(ollama.embed(model='deepseek-r1:32b', input='The sky is blue because of rayleigh scattering'))

print(ollama.embed(model='deepseek-r1:32b', input='The sky is blue because of rayleigh scattering').embeddings)

另外,ollama还有create(创建新模型)、copy(复制)、delete(删除)、pull(拉取)、push(推送到远端)等常用的方法。另外,还可以使用ps命令查看运行的模型:

import ollama
print(ollama.ps())

客户端

还可以创建自定义客户端,来进一步控制请求配置,比如设置自定义的 headers 或指定本地服务的 URL。通过 Client,用户可以自定义请求的设置(如请求头、URL 等),并发送请求。

from ollama import Client

client = Client(
    host='http://localhost:11434',
    headers={'x-some-header': 'some-value'}
)

response = client.chat(model='gemma3:27b', messages=[
    {
        'role': 'user',
        'content': '什么是生物学',
    },
])
print(response['message']['content'])

如果用户希望异步执行请求,可以使用AsyncClient类,适用于需要并发的场景。异步客户端支持与传统的同步请求一样的功能,唯一的区别是请求是异步执行的,可以提高性能,尤其是在高并发场景下。

import asyncio
from ollama import AsyncClient

async def chat():
    message = {'role': 'user', 'content': '用简单的语句描述工作中的日报有哪些内容?'}
    response = await AsyncClient().chat(model='gemma3:27b', messages=[message])
    print(response['message']['content'])

asyncio.run(chat())

如果用户需要异步地处理流式响应,可以通过将stream=True设置为异步生成器来实现。

import asyncio
from ollama import AsyncClient

async def chat():
    message = {'role': 'user', 'content': '用简单的语句描述工作中的日报有哪些内容?'}
    async for part in await AsyncClient().chat(model='gemma3:27b', messages=[message], stream=True):
        print(part['message']['content'], end='', flush=True)

asyncio.run(chat())

文章总结

Ollama 是一个本地大模型运行框架,致力于让开发者在个人设备上快速部署和使用各类开源大语言模型(如 LLaMA、Mistral、Gemma、DeepSeek等)。它通过极简的 CLI 命令(如 ollama run llama3),帮助用户在无需复杂环境配置的情况下,一键拉起本地模型。Ollama 提供了统一的模型管理、会话API和内存管理机制,是开发者测试、原型开发、本地私有化部署的理想工具,也适合作为RAG、Agent框架中的模型后端接入点。

参考资料

  1. 官网链接:https://ollama.comhttps://ollama.org.cn
  2. GitHub地址:https://github.com/ollama/ollama
  3. Ollama中文文档:https://ollama.readthedocs.io/quickstart/
  4. Ollama教程:https://www.runoob.com/ollama/ollama-tutorial.html
  5. Ollama中文文档:https://ollama.readthedocs.io
  6. LlamaFactory:https://www.llamafactory.cn

Python的包管理工具

在程序员日常的工作中,在研究某些源码的时候,会进行Python版本或者某个package版本的限制。此时,如果频繁地修改自己的环境将会极大地降低开发和调试的效率。在这种背景下,各种包管理工具就显得尤为重要。

Anaconda、Miniconda 和 Miniforge

在 Python 开发过程中,包管理是一个至关重要的环节。无论是处理多个项目的依赖关系,还是为数据科学、机器学习等领域构建环境,使用合适的包管理工具能够大大提升开发效率。常见的工具包括 AnacondaMinicondaMiniforge。虽然它们都可以用于包管理和虚拟环境的创建,但它们在安装方式、功能以及适用场景上有所不同。

Anaconda:全功能的解决方案

Anaconda 是一个集成开发环境,专为数据科学、机器学习和科学计算设计,其官网是https://www.anaconda.com。它不仅提供了一个易于使用的包管理器(`conda`),还包含了大量常用的第三方库,如 NumPy、Pandas、Matplotlib、Scikit-learn、Tensorflow等。用户安装 Anaconda 后,几乎可以立即开始各种开发任务,而不需要额外安装其他依赖包。对于初学者或需要快速配置工作环境的开发者来说,Anaconda 是一个非常方便的选择。

然而,Anaconda 的一个缺点是它的安装包较大,安装过程中会下载和安装大量的库,这意味着它可能会占用较多的磁盘空间。如果你只是需要某些特定的库而不需要整个 Anaconda 套件,那么安装过程可能会显得不那么高效。同时,在商业版本中,Anaconda是需要付费的,每个月50美金的开销。如果是学术圈的账号,则需要每个月花费15美金。当然,如果是个人电脑的话,是完全免费的。

Miniconda:轻量级的替代品

如果你觉得 Anaconda 包含了太多不必要的库,可以考虑使用 Miniconda,其下载渠道是https://www.anaconda.com/download/success。Miniconda是Anaconda的一个轻量级版本,它仅包含conda包管理器和Python。相比于Anaconda,Miniconda提供了更小的安装包和更灵活的定制选项。安装Miniconda后,你可以根据项目的需要单独安装所需的包,而不会被一些默认的库所困扰。

Miniconda 特别适合那些想要掌控每个依赖的开发者,尤其是对于对系统资源要求较高的环境或者空间受限的用户来说,Miniconda 是一个理想的选择。通过 Miniconda,用户可以更精细地管理虚拟环境,避免不必要的包冲突和冗余安装。但是请注意,如果应用到商业领域,一旦贵公司的员工数超过200人,那同样也是需要收费的。

Miniforge:社区驱动的开源选择

Miniforge 是一个社区驱动的开源项目,其官网链接是:https://conda-forge.org/miniforge/。它提供了一个更加轻量级且完全开源的 Conda 发行版。它基于 Miniconda,但与 Anaconda 官方发行版不同,Miniforge 默认使用由 Conda Forge 社区维护的包源。Conda Forge 是一个由开发者和数据科学家共同维护的开源软件包仓库,其包的更新和维护通常较为频繁且具有较好的兼容性。同样的,Miniforge 支持windows、linux、mac三个常见的操作系统,且开源使用

Miniforge 的优势在于它的完全开源性和灵活性。与官方的 Anaconda 发行版相比,Miniforge 更加贴近社区的需求。因此,适合那些有开源需求或倾向于使用 Conda Forge 的开发者。通过 Miniforge,用户可以轻松接入 Conda Forge 仓库,享受社区贡献的丰富资源。

在不同的场景下需要选择合适的工具

选择Anaconda、Miniconda还是Miniforge,取决于你的具体需求。对于刚入门的Python开发者或者需要快速搭建环境的用户,Anaconda是一个非常好的选择,它提供了全套的功能和库支持。对于更有经验的开发者或需要精细控制环境和依赖的用户,Miniconda提供了更为轻量和灵活的解决方案。而如果你倾向于使用开源社区维护的包源,并且希望避开官方发行版的一些限制,Miniforge无疑是一个值得考虑的选择。

conda 常见命令

接下来我将介绍一些 conda 常用命令,这些命令对于管理环境和包非常重要,能够帮助你高效地进行 Python 开发。无论你使用的是 AnacondaMiniconda 还是 Miniforge,`conda` 都是这些工具的核心命令行工具。

1. 创建新环境

要创建一个新的虚拟环境,可以使用 `conda create` 命令。你可以指定 Python 版本,甚至指定要安装的包:

conda create --name myenv python=3.9

这条命令会创建一个名为 `myenv` 的新环境,并安装 Python 3.9 版本。你也可以在创建环境时同时安装其他包:

conda create --name myenv python=3.9 numpy pandas

此命令将在环境中同时安装 numpypandas 库。

2. 激活环境

创建好环境后,需要激活它以便在该环境中工作。使用 `conda activate` 命令:

conda activate myenv

一旦激活环境,命令行提示符会改变,显示当前活跃的环境名称。比如,`(myenv)` 会出现在命令行前缀。

3. 停用环境

当你完成工作后,可以使用 `conda deactivate` 命令退出当前环境,返回到基环境(base environment):

conda deactivate

这将让你回到 `base` 环境,或者如果你已经处于 base 环境,则返回到系统默认的 Python 环境。

4. 列出所有环境

要查看当前所有的 `conda` 环境,可以使用 `conda env list` 或 `conda info –envs` 命令:

conda env list

这个命令会列出所有的环境,以及当前激活的环境。

5. 删除环境

如果你不再需要某个环境,可以使用 `conda remove` 命令删除它:

conda remove --name myenv --all

这将删除名为 `myenv` 的环境及其所有内容。

6. 安装包

要在当前环境中安装新的 Python 包,使用 `conda install` 命令:

conda install numpy

这会安装 numpy 包到当前激活的环境中。你还可以一次性安装多个包:

conda install numpy pandas matplotlib

如果你需要安装某个特定版本的包,可以在包名后加上版本号:

conda install numpy=1.21

7. 更新包

要更新某个已安装包到最新版本,使用 `conda update` 命令:

conda update numpy

如果你想更新所有已经安装的包,可以使用:

conda update --all

8. 卸载包

如果你不再需要某个包,可以使用 `conda remove` 命令将其卸载:

conda remove numpy

这会将 numpy 从当前环境中删除。

9. 查看已安装的包

要查看当前环境中已安装的所有包,可以使用 `conda list` 命令:

conda list

这将列出所有已安装的包及其版本号。

10. 查找包

如果你想查找某个包的信息,可以使用 `conda search` 命令:

conda search numpy

这会返回 numpy 包的所有可用版本和其他相关信息。

11. 导出环境

如果你想分享或备份某个环境的所有包和版本,可以使用 `conda list –export` 导出环境配置:

conda list --export > environment.txt

这会将环境中所有安装的包及其版本信息写入一个文本文件 `environment.txt`。

12. 从文件创建环境

如果你有一个由 `conda list –export` 或 `conda env export` 创建的环境文件,可以通过以下命令来重新创建相同的环境:

conda create --name myenv --file environment.txt

如果是通过 `conda env export` 导出的 YAML 文件,可以使用:

conda env create -f environment.yml

13. 导入环境

如果你从其他开发者那里获取了环境文件(通常是 `.yml` 文件),你可以通过 `conda env create` 命令来创建该环境:

conda env create -f environment.yml

14. 更新 Conda

保持 Conda 本身的最新版本非常重要。可以通过以下命令来更新 Conda:

conda update conda

15. 清理缓存

随着时间的推移,`conda` 会在本地存储一些缓存文件,可以使用以下命令来清理这些缓存并释放磁盘空间:

conda clean --all

这个命令会删除未使用的包、缓存和旧的安装包,帮助节省存储空间。

这些是 `conda` 命令中最常用的一些基本命令。掌握它们可以帮助你高效地创建和管理虚拟环境,安装、更新和删除 Python 包,从而为 Python 开发提供更加灵活和高效的工作流。根据你的需求,可以灵活地使用这些命令来管理不同项目的环境和依赖,确保项目的稳定性和可重现性。

PyCharm:专为 Python 打造的 IDE

PyCharm 介绍

PyCharm 是JetBrains出品的一款功能强大的 Python 集成开发环境(IDE),被广泛应用于 Python 开发、Web 开发、数据科学与自动化脚本等领域。它不仅拥有智能代码补全、调试器、单元测试、版本控制等一体化开发功能,还原生支持 Jupyter Notebook、Django、Flask 等主流框架。在与Conda结合使用时,PyCharm 表现尤为出色。你可以在 PyCharm 中轻松指定Conda创建的虚拟环境作为项目的 Python 解释器。通过图形化界面安装包、管理环境、配置依赖变得直观易懂,大大降低了 Python 初学者和数据科学开发者的上手门槛。

Conda 与 PyCharm 的无缝集成

将 Conda 与 PyCharm 搭配使用,是当前主流的 Python 开发组合之一。你可以先通过 Conda 创建项目所需的虚拟环境,然后在 PyCharm 中将其作为解释器加载使用。无论是 Web 应用开发还是数据分析建模,这种搭配不仅提高了开发效率,也确保了项目环境的清晰可控。具体的配置方法可以参考链接:https://www.jetbrains.com/help/pycharm/conda-support-creating-conda-virtual-environment.html

总结

AnacondaMinicondaMiniforge 都是强大的工具,可以帮助 Python 开发者高效地管理环境和包。它们各有优势,Anaconda 提供了一个全面的解决方案,Miniconda 更加轻量,而 Miniforge 则更加注重开源生态。程序员可以将conda配合 PyCharm 使用,开发者可以在强大的 IDE 中享受无缝的 Conda 环境集成和包管理。通过熟练掌握常见的 conda 命令,开发者可以高效地创建、更新、管理虚拟环境和包,确保开发过程的流畅性和项目的可重现性。这些工具和命令结合使用,将大大提高 Python 开发的效率和可维护性。

用 pyecharts 让数据可视化更生动

Pyecharts 背景介绍

在当今大数据时代,数据可视化已经成为信息表达的重要方式。无论是商业分析、科研探索,还是 Web 应用展示,直观的图表总能让数据讲述更生动的故事。而在 Python 生态中,Pyecharts 是一个强大且易用的数据可视化库,它基于 ECharts,提供了丰富的可视化组件,支持折线图、柱状图、饼图、地图等多种图表类型,且能够方便地集成到 Web 端和 Jupyter Notebook 中。

对于想要用 Python 实现高质量可视化的开发者来说,Pyecharts 是一个不错的选择。它不仅封装了强大的 ECharts 功能,还让复杂的交互图表变得更加简单。本文将介绍 Pyecharts 的核心功能,并通过示例展示如何使用它进行数据可视化,让你的数据更具表现力!

从官网的介绍来看,pyecharts 有以下诸多特性:

  1. 简洁的 API 设计,使用如丝滑般流畅,支持链式调用
  2. 囊括了 30+ 种常见图表,应有尽有
  3. 支持主流 Notebook 环境,Jupyter Notebook 和 JupyterLab
  4. 可轻松集成至 Flask,Django 等主流 Web 框架
  5. 高度灵活的配置项,可轻松搭配出精美的图表
  6. 详细的文档和示例,帮助开发者更快的上手项目
  7. 多达 400+ 地图文件以及原生的百度地图,为地理数据可视化提供强有力的支持

并且可以通过 pip 安装源码安装两种方式来安装 pyecharts:

# 安装 v2 以上版本
$ pip install pyecharts -U

# 安装 v2 以上版本
$ git clone https://github.com/pyecharts/pyecharts.git

从 GitHub 的 pyecharts 官网来看,安装好 pyecharts 之后,就可以进行代码的运行,并可以在浏览器中看到数据可视化的效果。

from pyecharts.charts import Bar
from pyecharts import options as opts

# V1 版本开始支持链式调用
bar = (
    Bar()
    .add_xaxis(["衬衫", "毛衣", "领带", "裤子", "风衣", "高跟鞋", "袜子"])
    .add_yaxis("商家A", [114, 55, 27, 101, 125, 27, 105])
    .add_yaxis("商家B", [57, 134, 137, 129, 145, 60, 49])
    .set_global_opts(title_opts=opts.TitleOpts(title="某商场销售情况"))
)
bar.render()

通过生成的 render.html 文件,点开之后就可以看到柱状图的可视化效果。

同样的,在 Jupyter Notes 中也可以直接呈现出这些效果。另外,在 pyecharts 的图表类型里面,绝对不仅仅局限于柱状图,折线图、饼图、散点图都可以做出来。详情可以参见表格:

图表类型适用场景
柱状图(Bar)适用于分类数据的对比,如销售数据、人口分布
折线图(Line)适用于趋势分析,如股票价格、温度变化
饼图(Pie)适用于数据占比展示,如市场份额、人口构成
散点图(Scatter)适用于数据分布分析,如身高体重关系、房价分布
地图(Map)适用于地理数据可视化,如人口分布、疫情数据
热力图(Heatmap)适用于二维数据分析,如温度分布、访问热度
词云(WordCloud)适用于文本数据分析,如关键词分析
箱线图(Box Plot)数据分布分析、离群值检测、统计描述。展示数据的最大值、最小值、中位数、四分位数及异常值,帮助识别数据的离散性和分布情况。
仪表盘(Gauge)实时监控、KPI展示、进度追踪。适用于实时数据展示,显示目标进度或某项指标的当前状态。
漏斗图(Funnel)销售漏斗、转化率分析、用户行为分析。用于展示数据流的逐步转化过程,适合分析各阶段转化情况。
树图(Tree)组织结构、层级关系、分类展示。适用于展示层级结构,如公司组织架构、文件目录等。
平行坐标系图(Parallel Coordinates)多维数据分析、机器学习特征分析。用于展示多维数据的关系,适合高维数据的可视化,如特征对比分析。
桑基图(Sankey Diagram)数据流、能源流、资金流、转化流。展示不同阶段之间的数据流动和流量,适合展示数据的流向。
地理坐标系图(Geo)地理数据展示、区域分布、人口分布。适合展示地理位置相关的数据,如城市人口、区域销售数据等。
时间线图(Timeline)动态数据展示、时间序列分析、趋势展示。适用于随着时间变化的数据可视化,展示历史数据的变化趋势。
3D 散点图(3D Scatter)三维数据展示、空间数据分析。用于展示三维空间中的数据点,适合显示三维数据分布。
3D 柱状图(3D Bar)三维数据展示、空间分析。通过三维柱状图展示多维数据的对比,适合空间或高维数据展示。
3D 曲面图(3D Surface)三维曲面展示、空间数据分析。适用于展示三维空间中的连续数据关系,如科学计算中的曲面拟合。

基础图表介绍

柱状图(Bar Chart)使用介绍

柱状图(Bar Chart)是最常见的图表类型之一,适用于展示不同类别之间的数量对比。它通过竖直或水平的条形来表示每个类别的数值大小,帮助我们快速识别出数据中的差异和趋势。

代码示例

from pyecharts.charts import Bar
from pyecharts import options as opts

# 创建柱状图对象
bar = Bar()

# 链式调用进行配置
bar.add_xaxis(["A", "B", "C", "D", "E"])  # 设置x轴类别
bar.add_yaxis("销量", [120, 200, 150, 80, 70])  # 设置y轴数据

# 设置全局配置
bar.set_global_opts(
    title_opts=opts.TitleOpts(title="销售数据", subtitle="2023年上半年"),
    xaxis_opts=opts.AxisOpts(name="商品"),
    yaxis_opts=opts.AxisOpts(name="销量")
)

# 渲染生成图表
bar.render()

代码解析

  • Bar():创建一个柱状图对象。
  • add_xaxis(["A", "B", "C", "D", "E"]):设置 x 轴的类别,通常是你想要展示的各个分类(如商品、地区等)。
  • add_yaxis("销量", [120, 200, 150, 80, 70]):设置 y 轴的数据,即每个分类的数值。
  • set_global_opts():用来设置图表的全局配置项,包括标题、x 轴和 y 轴的名称等。这里使用了链式调用来逐一设置标题、x 轴和 y 轴的配置。
  • render():将图表渲染成 HTML 文件,方便在浏览器中查看。

运行上述代码后,会在当前目录下生成一个 render.html 文件,打开该文件可以看到柱状图的展示效果。该柱状图展示了商品 A、B、C、D、E 的销量数据,且带有标题和坐标轴名称。

除了基础配置,Pyecharts 还支持进一步定制柱状图的外观,例如设置柱子的颜色、添加图例、调整样式等。下面是一个进阶的示例,展示了如何进行更多的自定义。

from pyecharts.charts import Bar
from pyecharts import options as opts

# 创建柱状图对象
bar = Bar()

# 链式调用进行配置
bar.add_xaxis(["A", "B", "C", "D", "E"])  # 设置x轴类别
bar.add_yaxis("销量", [120, 200, 150, 80, 70], color="skyblue")  # 设置y轴数据并调整颜色
bar.add_yaxis("利润", [50, 100, 70, 60, 90], color="orange")  # 添加另一组y轴数据

# 设置全局配置
bar.set_global_opts(
    title_opts=opts.TitleOpts(title="销售数据", subtitle="2023年"),
    xaxis_opts=opts.AxisOpts(name="商品"),
    yaxis_opts=opts.AxisOpts(name="销量/利润"),
    legend_opts=opts.LegendOpts(pos_top="10%")  # 图例位置
)

# 渲染生成图表
bar.render("render_advanced.html")

代码解析

  • add_yaxis("销量", [120, 200, 150, 80, 70], color="skyblue"):为柱状图添加另一组数据,并设置柱子的颜色为“skyblue”。
  • add_yaxis("利润", [50, 100, 70, 60, 90], color="orange"):再次为柱状图添加一组数据,用于展示利润,颜色设置为“orange”。
  • legend_opts=opts.LegendOpts(pos_top="10%"):设置图例的位置,使其出现在图表的顶部。

用上述代码生成的图表如下所示:

折线图(Line Chart)使用介绍

折线图(Line Chart)是用于展示数据随时间变化趋势的常见图表类型。它通过将数据点连接成线段的方式,帮助用户识别数据变化的规律和趋势。折线图适用于时间序列数据、趋势分析、对比分析等场景。

在 Pyecharts 中,可以使用链式调用方式来非常方便地生成折线图,并进行多种定制化配置。

代码示例

from pyecharts.charts import Line
from pyecharts import options as opts

# 创建折线图对象
line = Line()

# 链式调用进行配置
line.add_xaxis(["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul"])  # 设置x轴标签(月份)
line.add_yaxis("销量", [150, 200, 180, 220, 240, 280, 300])  # 设置y轴数据(销量)

# 设置全局配置
line.set_global_opts(
    title_opts=opts.TitleOpts(title="2023年上半年销量趋势"),
    xaxis_opts=opts.AxisOpts(name="月份"),
    yaxis_opts=opts.AxisOpts(name="销量"),
    tooltip_opts=opts.TooltipOpts(trigger="axis", axis_pointer_type="line")  # 设置悬浮提示框
)

# 渲染生成图表
line.render()

代码解析

  • Line():创建一个折线图对象。
  • add_xaxis(["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul"]):设置 x 轴标签,这里是月份。
  • add_yaxis("销量", [150, 200, 180, 220, 240, 280, 300]):设置 y 轴数据,这里是每个月的销量数据。
  • set_global_opts():设置全局配置,包括图表的标题、坐标轴名称等。
    • title_opts=opts.TitleOpts(title="2023年上半年销量趋势"):设置图表的标题。
    • xaxis_opts=opts.AxisOpts(name="月份")yaxis_opts=opts.AxisOpts(name="销量"):设置 x 轴和 y 轴的名称。
    • tooltip_opts=opts.TooltipOpts(trigger="axis", axis_pointer_type="line"):设置提示框,鼠标悬浮时会显示相应的数据。
  • render():生成 HTML 文件并渲染折线图,可以通过浏览器打开查看。

Pyecharts 还支持在同一个折线图中展示多条折线,适用于对比多个系列的数据。此外,还可以定制折线的颜色、线条样式、图例等。下面是一个进阶示例,展示了如何在折线图中绘制多条折线,并进行更多样式的自定义。

from pyecharts.charts import Line
from pyecharts import options as opts

# 创建折线图对象
line = Line()

# 添加x轴
line.add_xaxis(["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul"])

# 添加销量数据线
line.add_yaxis("销量", [150, 200, 180, 220, 240, 280, 300], color="skyblue", is_smooth=True, linestyle_opts=opts.LineStyleOpts(width=2))

# 添加利润数据线
line.add_yaxis("利润", [50, 100, 70, 60, 90, 150, 200], color="orange", is_smooth=True, linestyle_opts=opts.LineStyleOpts(width=2, type_="dashed"))

# 设置全局配置
line.set_global_opts(
    title_opts=opts.TitleOpts(title="2023年上半年销售与利润趋势"),
    xaxis_opts=opts.AxisOpts(name="月份"),
    yaxis_opts=opts.AxisOpts(name="金额"),
    legend_opts=opts.LegendOpts(pos_top="5%"),  # 设置图例位置
    tooltip_opts=opts.TooltipOpts(trigger="axis", axis_pointer_type="line")  # 提示框
)

# 渲染生成图表
line.render("render_advanced.html")

代码解析

  • is_smooth=True:使折线图的线条变得平滑,避免折线过于尖锐。
  • linestyle_opts=opts.LineStyleOpts(width=2):设置折线的宽度为 2。
  • color="skyblue"color="orange":分别为销量线和利润线设置不同的颜色。
  • type_="dashed":设置利润线为虚线样式。
  • legend_opts=opts.LegendOpts(pos_top="5%"):设置图例的位置为顶部。

使用上述配置,将得到一个包含两条折线的图表,分别表示“销量”和“利润”,并且每条折线有不同的颜色、样式和图例。生成的图表将帮助你更加清晰地对比不同指标之间的关系。

饼图(Pie Chart)使用介绍

饼图(Pie Chart)是一种常见的统计图表,用于展示数据各部分占总量的比例。它通过一个圆形图形,将整体数据分成若干扇形区域,每个区域的角度代表该部分占总体的比例。饼图通常用于展示各个部分对总量的贡献,特别适用于数据分布较为离散或比例关系显著的场景。饼图具有直观、简洁的特点,非常适合用来展示市场份额、销售比例、人口分布等场景。

饼图的适用场景

  1. 市场份额分析:展示各个品牌或公司在市场中的份额。
  2. 财务数据展示:比如收入、支出的分布情况。
  3. 人口或地区分布:例如某个地区不同年龄段的比例。
  4. 产品分类统计:展示不同产品销售比例。

代码示例

from pyecharts.charts import Pie
from pyecharts import options as opts

# 创建饼图对象
pie = Pie()

# 链式调用进行配置
pie.add(
    "销售额",  # 数据系列名称
    [("苹果", 30), ("香蕉", 20), ("橙子", 50)],  # 数据内容:水果及其对应的销售额
    radius=["30%", "75%"],  # 饼图的半径范围
)

# 设置全局配置
pie.set_global_opts(
    title_opts=opts.TitleOpts(title="2023年水果销售占比"),
    legend_opts=opts.LegendOpts(orient="vertical", pos_top="15%", pos_left="2%"),  # 设置图例位置
)

# 渲染生成图表
pie.render()

代码解析

  • Pie():创建一个饼图对象。
  • add():用于添加数据。第一个参数是系列名称,这里是“销售额”。第二个参数是数据,包含了水果名称和对应的销售额。radius 用于设置饼图的半径,["30%", "75%"] 表示饼图的内半径和外半径,控制图形的大小和内外环之间的空隙。
  • set_global_opts():设置全局配置项,包括图表的标题、图例的位置等。
    • title_opts=opts.TitleOpts(title="2023年水果销售占比"):设置饼图的标题。
    • legend_opts=opts.LegendOpts(orient="vertical", pos_top="15%", pos_left="2%"):设置图例的位置,图例采用垂直排列,位置靠左并放置在图表的顶部。
  • render():生成 render.html 文件,使用浏览器打开即可查看图表效果。

Pyecharts 还支持更多的自定义选项,比如突出显示某个扇区、设置标签显示、调整动画效果等。以下是一个进阶的示例,展示了如何突出显示某个数据点,并显示详细标签。

代码示例

from pyecharts.charts import Pie
from pyecharts import options as opts

# 创建饼图对象
pie = Pie()

# 链式调用进行配置
pie.add(
    "销售额",  # 数据系列名称
    [("苹果", 30), ("香蕉", 20), ("橙子", 50)],
    radius=["30%", "75%"],  # 饼图的半径范围
    label_opts=opts.LabelOpts(
        is_show=True,  # 显示标签
        position="outside",  # 标签位置在扇形外部
        formatter="{b}: {c} ({d}%)",  # 标签内容,显示类别、数值和百分比
    ),
)

# 设置全局配置
pie.set_global_opts(
    title_opts=opts.TitleOpts(title="2023年水果销售占比"),
    legend_opts=opts.LegendOpts(orient="vertical", pos_top="15%", pos_left="2%"),
)

# 渲染生成图表
pie.render("render_advanced.html")

代码解析

  • label_opts=opts.LabelOpts(is_show=True, position="outside", formatter="{b}: {c} ({d}%)"):控制标签的显示和格式,position="outside" 将标签放置在扇形的外侧,formatter="{b}: {c} ({d}%)" 设置标签内容显示为“类别: 数值(百分比)”。

饼图的每个扇区都标有相应的标签,显示该类别的数值和占总量的百分比,同时标签线也经过了样式调整。生成的图表将更加清晰,用户能够轻松识别每个部分的具体信息。

散点图(Scatter Plot)使用介绍

散点图(Scatter Plot)通常用于展示两个变量之间的关系,比如在医学研究中,身高和体重之间的关系就是一个经典的分析场景。我们将用一个简单的例子来展示如何使用 Pyecharts 绘制散点图,并分析数据点之间的趋势。

在这个示例中,我们将生成一组虚拟的身高和体重数据,并通过散点图展示身高与体重之间的关系。假设身高和体重之间有某种程度的线性相关性,散点图将帮助我们直观地观察这一点。

数据示例

假设我们有以下数据:

  • 身高(cm):一个人的身高一般在 150cm 到 200cm 之间。
  • 体重(kg):根据身高,体重会有所不同,一般来说,身高越高,体重大致也会越大。

我们将生成一些模拟数据,展示身高与体重之间的关系。

代码示例

from pyecharts.charts import Scatter
from pyecharts import options as opts
import random

# 创建散点图对象
scatter = Scatter()

# 生成身高(cm)和体重(kg)数据
height = [random.randint(150, 200) for _ in range(50)]  # 随机生成50个身高数据
weight = [round(h * 0.5 + random.randint(10, 20), 1) for h in height]  # 假设体重与身高成正比,并添加随机偏差

# 将身高和体重数据配对
data = list(zip(height, weight))

# 添加身高和体重数据
scatter.add_xaxis([d[0] for d in data])  # 将身高数据作为 X 轴
scatter.add_yaxis("体重", [d[1] for d in data], symbol_size=8, color="#ff7f50")  # 将体重数据作为 Y 轴,并设置颜色

# 设置全局配置
scatter.set_global_opts(
    title_opts=opts.TitleOpts(title="身高与体重的关系", subtitle="散点图展示身高与体重之间的相关性"),
    xaxis_opts=opts.AxisOpts(
        name="身高 (cm)", type_="value", name_location="middle", name_gap=30
    ),
    yaxis_opts=opts.AxisOpts(
        name="体重 (kg)", type_="value", name_location="middle", name_gap=30
    ),
    tooltip_opts=opts.TooltipOpts(
        trigger="item",  # 触发方式为“item”
        formatter="身高: {b} cm<br/>体重: {c} kg",  # 格式化提示框内容,显示身高和体重
    ),
    visualmap_opts=opts.VisualMapOpts(
        min_=50,
        max_=150,
        dimension=1,  # 按体重的值进行颜色映射
        range_color=["#d94e5d", "#eac736", "#50a3ba"],  # 配置颜色范围
    ),
)

# 渲染生成图表
scatter.render()

代码解析

  • 使用 Scatter() 创建一个散点图对象,后续的配置和数据添加都将在此对象上进行。
  • height:我们用 random.randint(150, 200) 随机生成 50 个介于 150cm 到 200cm 之间的身高数据。
  • weight:体重是根据身高生成的。假设体重大致与身高成正比,h * 0.5 是体重与身高的比例,随机加上一个范围在 10 到 20 之间的偏差,使得数据看起来更自然。
  • add_xaxis():将 height 数据作为 X 轴的值传入。
  • add_yaxis():将 weight 数据作为 Y 轴的值传入,并设置点的大小为 8,颜色为 #ff7f50(一种橙色)。
  • title_opts:设置图表的标题为“身高与体重的关系”。
  • xaxis_optsyaxis_opts:分别设置 X 轴和 Y 轴的名称,并调整名称的位置。
  • tooltip_opts:配置鼠标悬浮时的提示框,显示身高和体重的具体数值。
  • visualmap_opts:根据体重值设置颜色映射,从红色到蓝色,体重越大,颜色越接近蓝色。
  • 使用 render() 方法将图表渲染到一个 HTML 文件中,这样我们可以在浏览器中查看该图表。

展示效果

生成的散点图会展示 50 个身高与体重数据点,其中:

  • X 轴表示身高(单位:cm)。
  • Y 轴表示体重(单位:kg)。
  • 数据点的颜色从红色到蓝色,代表不同的体重值,颜色越蓝表示体重大,颜色越红表示体重较小。
  • 鼠标悬停在某个数据点时,提示框会显示该点的身高和体重。

通过 Pyecharts,我们可以快速绘制出身高与体重之间的关系散点图。该图表不仅直观地展示了数据点之间的相关性,还通过颜色映射、交互提示等增强了可读性和易用性。使用 Pyecharts 的散点图,不仅可以用于类似的线性数据分析,还可以扩展到多维度数据的可视化分析中。

图表排版

多个图表竖排

当我们掌握了各种图表的基本使用方法后,接下来一个非常重要的任务就是将这些图表有效地集成到网页中,展示数据的可视化效果。Pyecharts 提供了非常方便的功能,让我们能够将图表生成 HTML 文件,并嵌入到网页中进行展示。通过将图表集成到网页,用户不仅能够与数据进行互动,还能够获得更加直观、动态的展示效果。

在接下来的内容中,我们将详细介绍如何将多个图表(如柱状图、折线图、散点图等)融合到一个网页中,并通过 HTML 和 JavaScript 来增强页面的交互性和用户体验。通过这种方式,你可以将不同类型的图表展示在同一页面上,利用 Pyecharts 提供的丰富配置选项,轻松实现数据可视化的多样性和灵活性。

from pyecharts.charts import Bar, Line, Pie, Scatter, Page
from pyecharts import options as opts
import random

# 创建柱状图
bar = Bar()
bar.add_xaxis(["A", "B", "C", "D", "E"])
bar.add_yaxis("类别1", [random.randint(10, 100) for _ in range(5)], color="#d94e5d")
bar.add_yaxis("类别2", [random.randint(10, 100) for _ in range(5)], color="#50a3ba")
bar.set_global_opts(
    title_opts=opts.TitleOpts(title="柱状图示例"),
    xaxis_opts=opts.AxisOpts(name="类别"),
    yaxis_opts=opts.AxisOpts(name="值"),
)

# 创建折线图
line = Line()
line.add_xaxis(["Jan", "Feb", "Mar", "Apr", "May"])
line.add_yaxis("销售额", [random.randint(100, 500) for _ in range(5)], color="#ff7f50")
line.set_global_opts(
    title_opts=opts.TitleOpts(title="折线图示例"),
    xaxis_opts=opts.AxisOpts(name="月份"),
    yaxis_opts=opts.AxisOpts(name="销售额"),
)

# 创建饼图
pie = Pie()
pie.add("产品占比", [("产品A", 40), ("产品B", 30), ("产品C", 20), ("产品D", 10)])
pie.set_global_opts(title_opts=opts.TitleOpts(title="饼图示例"))

# 创建散点图
scatter = Scatter()
x_data = [random.randint(1, 100) for _ in range(30)]
y_data = [random.randint(1, 100) for _ in range(30)]
scatter.add_xaxis(x_data)
scatter.add_yaxis("散点数据", y_data, symbol_size=8, color="#ff7f50")
scatter.set_global_opts(
    title_opts=opts.TitleOpts(title="散点图示例"),
    xaxis_opts=opts.AxisOpts(name="X轴"),
    yaxis_opts=opts.AxisOpts(name="Y轴"),
)

# 使用 Page 将多个图表放在一个页面中
page = Page()
page.add(bar, line, pie, scatter)

# 渲染页面到 HTML 文件
page.render("combined_chart.html")

print("所有图表已合并到 combined_chart.html 文件中。")

通过执行这段代码,最终会生成一个名为 combined_chart.html 的文件。打开该文件后,你将看到一个网页,包含四个图表(柱状图、折线图、饼图、散点图),它们将呈现在同一个页面中,用户可以浏览并查看不同图表的数据。通过 Pyecharts 提供的 Page 类,我们可以方便地将多个图表集成到一个 HTML 页面中进行展示,提升数据展示的效果和用户体验。

拖拽图表

在很多场景下,我们需要根据各个图表的具体情况来进行拖拽式的展示,在这里,pyecharts 同样提供了一个拖拽式的功能。Save Config 按钮就是用来保存拖拽后的样式的。

from pyecharts.charts import Bar, Line, Pie, Scatter, Page
from pyecharts import options as opts
import random

# 创建柱状图
bar = Bar(init_opts=opts.InitOpts(width="50%", height="400px"))
bar.add_xaxis(["A", "B", "C", "D", "E"])
bar.add_yaxis("类别1", [random.randint(10, 100) for _ in range(5)], color="#d94e5d")
bar.add_yaxis("类别2", [random.randint(10, 100) for _ in range(5)], color="#50a3ba")
bar.set_global_opts(
    title_opts=opts.TitleOpts(title="柱状图示例"),
    xaxis_opts=opts.AxisOpts(name="类别"),
    yaxis_opts=opts.AxisOpts(name="值"),
)

# 创建折线图
line = Line(init_opts=opts.InitOpts(width="50%", height="400px"))
line.add_xaxis(["Jan", "Feb", "Mar", "Apr", "May"])
line.add_yaxis("销售额", [random.randint(100, 500) for _ in range(5)], color="#ff7f50")
line.set_global_opts(
    title_opts=opts.TitleOpts(title="折线图示例"),
    xaxis_opts=opts.AxisOpts(name="月份"),
    yaxis_opts=opts.AxisOpts(name="销售额"),
)

# 创建饼图
pie = Pie(init_opts=opts.InitOpts(width="50%", height="400px"))
pie.add("产品占比", [("产品A", 40), ("产品B", 30), ("产品C", 20), ("产品D", 10)])
pie.set_global_opts(title_opts=opts.TitleOpts(title="饼图示例"))

# 创建散点图
scatter = Scatter(init_opts=opts.InitOpts(width="50%", height="400px"))
x_data = [random.randint(1, 100) for _ in range(30)]
y_data = [random.randint(1, 100) for _ in range(30)]
scatter.add_xaxis(x_data)
scatter.add_yaxis("散点数据", y_data, symbol_size=8, color="#ff7f50")
scatter.set_global_opts(
    title_opts=opts.TitleOpts(title="散点图示例"),
    xaxis_opts=opts.AxisOpts(name="X轴"),
    yaxis_opts=opts.AxisOpts(name="Y轴"),
)

# 使用 Page 将多个图表放在一个页面中,调整为左右布局
page = Page(layout=Page.DraggablePageLayout, page_title="综合数据展示")
page.add(bar, line, pie, scatter)

# 渲染页面到 HTML 文件
page.render("combined_chart.html")

print("所有图表已合并到 combined_chart.html 文件中。")

这样会形成一个可以拖拽式的网页,拖拽完成之后点击左上角的 Save Config 按钮,可以得到一个 chart_config.json 文件。然后写一个新的脚本,运行下面的代码,即可将原有的 html 文件(’combined_chart.html’)和 chart_config.json 文件一起生成新的 html 文件(’combined_chart_resize.html’)并且符合拖拽后的样式。

from pyecharts.charts import Page
# 在生成的config上,重新生成chart
page = Page()
page.save_resize_html('combined_chart.html', cfg_file='chart_config.json', dest='combined_chart_resize.html')

通过 PageDraggablePageLayout 布局,图表会以拖拽的方式自动排列。你可以通过手动调整页面上的每个图表位置。width="50%" 表示每个图表将占据页面宽度的一半,因此两个图表将并排显示。height="400px" 设置每个图表的高度为 400px,可以根据需要调整这个值。

增加标题

在数据可视化的场景中,需要给这个页面增加一个标题,在这里,可以使用一个空的饼图来实现,也就是只需要展示标题而不需要展示饼图的数据。

from pyecharts.charts import Bar, Line, Pie, Scatter, Page
from pyecharts import options as opts
import random

# 创建饼图,只显示标题
big_title = (
    Pie(init_opts=opts.InitOpts(width="50%", height="50px"))
    .set_global_opts(
        title_opts=opts.TitleOpts(
            title="数据可视化大屏",
            title_textstyle_opts=opts.TextStyleOpts(
                font_size=40,  # 调整字体大小
                font_weight="bold",  # 可选:字体加粗
                color="#000000"  # 可选:字体颜色
            ),
        )
    )
)

# 创建柱状图
bar = Bar(init_opts=opts.InitOpts(width="50%", height="300px"))
bar.add_xaxis(["A", "B", "C", "D", "E"])
bar.add_yaxis("类别1", [random.randint(10, 100) for _ in range(5)], color="#d94e5d")
bar.add_yaxis("类别2", [random.randint(10, 100) for _ in range(5)], color="#50a3ba")
bar.set_global_opts(
    title_opts=opts.TitleOpts(title="柱状图示例"),
    xaxis_opts=opts.AxisOpts(name="类别"),
    yaxis_opts=opts.AxisOpts(name="值"),
)

# 创建折线图
line = Line(init_opts=opts.InitOpts(width="50%", height="300px"))
line.add_xaxis(["Jan", "Feb", "Mar", "Apr", "May"])
line.add_yaxis("销售额", [random.randint(100, 500) for _ in range(5)], color="#ff7f50")
line.set_global_opts(
    title_opts=opts.TitleOpts(title="折线图示例"),
    xaxis_opts=opts.AxisOpts(name="月份"),
    yaxis_opts=opts.AxisOpts(name="销售额"),
)

# 创建饼图
pie = Pie(init_opts=opts.InitOpts(width="50%", height="300px"))
pie.add("产品占比", [("产品A", 40), ("产品B", 30), ("产品C", 20), ("产品D", 10)])
pie.set_global_opts(title_opts=opts.TitleOpts(title="饼图示例"))

# 创建散点图
scatter = Scatter(init_opts=opts.InitOpts(width="50%", height="300px"))
x_data = [random.randint(1, 100) for _ in range(30)]
y_data = [random.randint(1, 100) for _ in range(30)]
scatter.add_xaxis(x_data)
scatter.add_yaxis("散点数据", y_data, symbol_size=8, color="#ff7f50")
scatter.set_global_opts(
    title_opts=opts.TitleOpts(title="散点图示例"),
    xaxis_opts=opts.AxisOpts(name="X轴"),
    yaxis_opts=opts.AxisOpts(name="Y轴"),
)

# 使用 Page 将多个图表放在一个页面中,调整为左右布局
page = Page(layout=Page.DraggablePageLayout, page_title="综合数据展示")
page.add(big_title, bar, line, pie, scatter)

# 渲染页面到 HTML 文件
page.render("combined_chart.html")

print("所有图表已合并到 combined_chart.html 文件中。")

通过这样的方式,可以呈现出标题的样式,然后再使用拖拽式的方法,来实现最终的数据可视化看板呈现。下图就是一个完成的数据可视化看板样式。

结束语

在这篇文章中,我们深入探讨了 Pyecharts —— 一款简单易用、功能强大的 Python 数据可视化库。通过直观的图表和丰富的自定义选项,Pyecharts 不仅能够帮助我们快速生成各类图表,还能够通过精细的配置满足不同场景的需求。从基础的柱状图、折线图到复杂的地理坐标系图、3D 曲面图,Pyecharts 都能轻松驾驭,展示数据的独特魅力。作为 Python 生态中的重要可视化工具,Pyecharts 的灵活性与易用性使得它在数据分析、报表生成、科研展示等领域得到了广泛的应用。而通过与前端技术结合,它还可以将图表嵌入到网页中,让数据的可视化更具交互性和视觉冲击力。

无论是数据分析师、科学家,还是开发者、产品经理,掌握 Pyecharts 都能让你在数据可视化的道路上走得更远。随着数据量的不断增长,如何用图表讲述一个清晰、有说服力的故事已经成为我们不断追求的目标。而 Pyecharts,正是一个帮助我们实现这一目标的得力助手。希望望这篇文章能够为你打开数据可视化的新世界。如果你还没有开始使用 Pyecharts,今天就可以动手试试。通过不断尝试和探索,你会发现更多有趣的图表效果,进而提升你对数据的理解和呈现能力。

数据可视化不仅仅是让数字“好看”,更是让数据“讲故事”。在这个信息爆炸的时代,掌握数据的可视化语言,正是与世界对话的钥匙。感谢阅读,也希望你在 Pyecharts 的世界里,能够享受创作的乐趣,发现更多无限的可能性。

从开发到部署:使用 Python 构建和发布完整服务的全流程

背景概述

在互联网公司的开发流程中,通常会涉及到以下方面的开发内容:客户端开发、后端开发、人工智能算法开发、前端开发、数据库开发等方向。而不同的员工往往只会负责其中的某一个部分,例如做前端开发的同事往往不会去深入了解人工智能算法开发的部分,做数据库优化的同事也不会去深入分析客户端开发的模块。但是在某些特殊的场景下,可能会需要一两位工程师去快速验证某项功能,实现从客户端到云服务,从云服务到数据库存储,再从数据库存储到前端网页展示的全流程开发过程。在这种情况下,就需要这一两位工程师掌握全栈的开发流程经验,以实现简单而又高效地开发过程,以应对具体的业务诉求。

画出整体的流程架构图通常则是以下简单的形式:

客户端 -> 后端服务(算法、数据库等)-> 前端 web 服务

从各个模块的开发内容来看,常见的开发工具包括但绝不仅仅限于以下表格:

开发模块工具库
客户端开发PyInstaller, Tkinter
后端开发Flask, Gunicorn
人工智能算法开发Torch, TensorFlow,ScikitLearn
前端 web 开发Vue, HTML, CSS, JavaScript,EChart
数据库开发Numpy,Scipy,Pandas, PyMySQL

Python 是一门非常强大的编程语言,可以实现的功能绝不仅仅是人工智能的算法开发,还包括生成 exe 可执行文件、GUI 图形界面开发、算法的后端服务部署,表格与数据库的数据分析、甚至与前端的服务对接等诸多功能。另外,在国内的前端开发环境中,HTML、CSS、JavaScript 和 VUE 框架使用得非常多,并且其参考文档和资料也非常丰富。因此,在熟练掌握 Python 的前提下,可以使用 Python 的各种 Package,结合前端框架 VUE 来实现一套全流程的开发和部署工作。

客户端开发

在客户端开发中,Python 以其简单易用的语法和丰富的第三方库,成为了许多开发者的首选语言。对于需要构建桌面应用程序的场景,Tkinterhttps://docs.python.org/3/library/tkinter.html)是一个非常流行的选择,而 PyInstallerhttps://pyinstaller.org/)则能够帮助开发者将 Python 程序打包成独立的可执行文件(例如 .exe),便于分发和部署在各个电脑上。

接下来,我们将深入介绍这两种工具的使用和应用场景,以及如何使用它们实现一个完整的客户端开发流程。

Tkinter:构建图形化用户界面 (GUI)

Tkinter 是 Python 的标准 GUI 库,适用于快速开发简单的桌面应用。Tkinter 提供了一个轻量级的图形界面工具集,支持基本的窗口、按钮、标签、文本框等控件,能够帮助开发者快速构建应用程序的界面。

Tkinter 的核心特点

Tkinter 具有如下的核心特点,让其在图形化用户界面开发的时候有独特的优势。

  1. 易于使用:Tkinter 是 Python 的标准库之一,内置在 Python 安装包中,无需额外安装。
  2. 跨平台:支持在 Windows、macOS 和 Linux 上运行,能够开发跨平台的应用。在某台 Windows 电脑上实现了 exe,即可移植到其他 Windows 电脑上,无需重新安装环境,方便其他所有者使用。
  3. 轻量级:适合用来构建功能较简单的桌面应用,尤其是工具类和小型应用。例如考勤的统计工具,简单的数据分析工具等。

示例:简单的 Tkinter 应用

以下是一个使用 Tkinter 构建简单窗口的代码示例:

import tkinter as tk

def on_click():
    label.config(text="按钮被点击!")

# 创建主窗口
root = tk.Tk()
root.title("简单的 Tkinter 应用")

# 设置窗口的尺寸为 600x600
root.geometry("600x600")

# 创建标签
label = tk.Label(root, text="Hello, Tkinter!")
label.pack(pady=20)

# 创建按钮
button = tk.Button(root, text="点击我", command=on_click)
button.pack(pady=10)

# 启动事件循环
root.mainloop()

在这个示例中,我们创建了一个简单的窗口,包含一个标签和一个按钮。点击按钮时,标签的文字会改变,呈现出“按钮被点击!”的字样。

Tkinter 控件介绍

Tkinter 中常用的控件,通过合理组合与布局,可以构建出丰富的图形用户界面(GUI)应用程序。在开发过程中,选择合适的控件和布局方式是实现良好用户体验的关键。通过灵活运用这些控件,开发者可以快速创建交互式、功能强大的桌面应用。

控件名称说明常用方法
Label用于显示文本或图像。config() 设置文本内容或图像,pack()、grid()、place() 放置控件。
Button创建按钮,用于执行某些操作。config() 设置按钮文本、样式,bind() 绑定事件,command 绑定函数。
Entry单行文本框,允许用户输入文本。get() 获取文本,insert() 插入文本,delete() 删除文本,focus() 设置焦点。
Text多行文本框,适用于较长文本输入和显示。insert() 插入文本,get() 获取文本,delete() 删除文本。
Checkbutton复选框,用于表示选中或未选中的状态。config() 设置选中或未选中,select()、deselect()、toggle() 改变状态,var.get() 获取状态。
Radiobutton单选按钮,允许用户从一组选项中选择一个。config() 设置标签和选中的值,select()、deselect() 改变状态,var.get() 获取选择值。
Listbox列表框,用于显示多个项,支持多选或单选。insert() 插入项,get() 获取选中项,delete() 删除项,curselection() 获取选中的项。
Scrollbar滚动条,通常与其他控件结合使用,用于在控件内显示大量内容。set() 设置滚动条位置,get() 获取滚动条位置,pack(side=”right”) 放置滚动条。
Frame帧容器,用于组织和管理其他控件。pack()、grid()、place() 布局,config() 设置背景颜色、边框等属性。
Canvas画布,用于绘制图形、文本或图片。create_line()、create_rectangle()、create_text() 绘制图形或文本,bind() 绑定事件。
Menu菜单,用于创建顶部菜单栏或上下文菜单。add_command() 添加菜单项,add_separator() 添加分隔符,post() 显示菜单。
Toplevel顶层窗口,用于创建新窗口。geometry() 设置窗口大小,withdraw() 隐藏窗口,deiconify() 显示窗口。
PanedWindow面板窗口,用于在同一窗口内分割多个区域。add() 添加控件,paneconfigure() 设置每个区域的配置。
Spinbox数值框或文本框,允许用户选择一个值(可以通过上下箭头或输入)。get() 获取值,set() 设置值,insert() 插入文本,delete() 删除文本。
Scale滑块,用于在一定范围内选择一个数值。get() 获取数值,set() 设置数值,bind() 绑定事件,tickinterval 设置刻度间隔。
Combobox下拉框,允许用户从多个选项中选择。get() 获取选择的项,set() 设置默认项,current() 设置当前选中的索引。
Message多行文本控件,类似于 Label,但支持多行显示和自动换行。config() 设置文本内容,pack()、grid() 布局。
LabelFrame标签框,一个包含标签的容器,常用于组织相关控件。pack()、grid()、place() 布局,config() 设置标签文本。
OptionMenu下拉菜单,用于从多个选项中选择一个。set() 设置选中的值,get() 获取选中的值,menu 设置菜单项。

PyInstaller:将 Python 程序打包成可执行文件

在开发桌面应用时,一个常见的需求是将 Python 脚本打包成独立的可执行文件,这样用户就不需要安装 Python 环境即可在同一个系统上的不同电脑上运行应用。PyInstaller 是实现这一目标的最佳工具之一。

PyInstaller 的优势

  1. 跨平台支持:PyInstaller 支持将 Python 程序打包为 Windows (.exe)、macOS (.app) 和 Linux 平台的可执行文件。
  2. 无需依赖 Python 环境:通过打包后,程序将所有的依赖都嵌入到可执行文件中,用户无需安装 Python 或其他库。
  3. 自动处理依赖:PyInstaller 会自动检测程序的依赖库并将其打包到可执行文件中。但是 Python 会有很多依赖包,所以在安装的时候,生成的文件大小通常会比用 C++/C# 的大一些,一般情况下会有 20 MB 甚至 100 MB 大小的可执行文件。

PyInstaller 使用步骤

  1. 安装 PyInstaller
    (1)使用 pip 安装 PyInstaller: pip install pyinstaller
    (2)使用 pip 升级 PyInstaller:pip install –upgrade pyinstaller
    (3)从官网上直接安装:git clone https://github.com/pyinstaller/pyinstaller,然后进入文件夹 cd pyinstaller,使用 pip 命令安装 pip install .。
  2. 打包应用
    在你的 Python 项目根目录下运行以下命令,PyInstaller 会自动分析你的 Python 文件及其依赖,并生成一个可执行文件: pyinstaller --onefile your_script.py --onefile 参数表示将所有文件打包成一个单独的 .exe 文件。
    (1)在 Windows 下执行的时候,如果打包成一个单独的 .exe 文件,则每次使用得时候都会在 C 盘生成一个文件,每调用一次生成一次。因此,在这里推荐使用文件夹的形式,而不是打包成一个 exe 文件。
    (2)涉及到 Tensorflow、Torch、ScikitLearn 等机器学习工具包的时候,不建议将其打包在 exe 文件里面,这样会导致文件过大,最终无法使用。
    (3)在打包的时候,python 脚本中最好只包含依赖简单的 package 或者 python 原生的 package,例如 numpy、requests、tkinter、opencv、PIL 等,复杂避免 PyInstaller 打包的时候由于依赖性等问题导致生成 exe 失败或者文件过大。过于复杂的计算可以放在云服务进行。
  3. 查看生成的文件
    打包成功后,会在 dist 目录下生成 .exe 文件,用户可以直接运行该文件。

PyInstaller 常见部分参数

  1. --onefile:将所有文件打包成一个单独的可执行文件。
  2. --noconsole:如果不需要显示控制台窗口(如 GUI 应用),可以加上此选项。
  3. --add-data:将额外的数据文件(如图片、配置文件等)一起打包。

示例: 如果你的程序还需要包含一些数据文件(比如图标),可以通过 --add-data 参数来指定:

pyinstaller --onefile --add-data="icon.ico;." your_script.py

在这个命令中,icon.ico 会被打包到可执行文件中,并可以在应用程序中使用。

Tkinter + PyInstaller:完整流程

让我们结合 Tkinter 和 PyInstaller,展示一个实际的开发流程。假设你开发了一个简单的 Tkinter 应用,并希望将其打包成独立的可执行文件,以下是完整的步骤:

步骤 1:创建 Tkinter 应用

我们使用之前的代码创建一个带按钮和标签的 Tkinter 应用。

import tkinter as tk

def on_click():
    label.config(text="按钮被点击!")

# 创建主窗口
root = tk.Tk()
root.title("Tkinter 应用")

# 创建标签
label = tk.Label(root, text="Hello, Tkinter!")
label.pack(pady=20)

# 创建按钮
button = tk.Button(root, text="点击我", command=on_click)
button.pack(pady=10)

# 启动事件循环
root.mainloop()

步骤 2:使用 PyInstaller 打包

在命令行中运行以下命令来打包程序:

pyinstaller your_script.py 

就可以直接将 your_script.py 里面的程序进行打包,在 Windows 中会形成一个 exe 的文件或者文件夹,在 Mac 中会形成一个 Unix 可执行文件。如下图所示:

当然,每个用户也可以根据实际情况来进行 PyInstaller 的参数配置,参数的详情和配置方法可以参考官方文档(https://pyinstaller.org/en/stable/usage.html),其通用的方法是
pyinstaller [options] script [script …] | specfile

常见的命令参数有以下内容:

参数描述示例
-F,–onefile将所有文件打包成一个单独的可执行文件。pyinstaller –onefile your_script.py
–noconsole / –windowed禁止显示命令行窗口,适用于 GUI 应用。pyinstaller –windowed your_script.py
–add-data添加额外的数据文件到打包的可执行文件中,格式:源路径;目标路径。pyinstaller –add-data=”icon.ico;.” your_script.py
–add-binary将二进制文件(如 DLL、SO 文件)添加到可执行文件中,格式:源路径;目标路径。pyinstaller –add-binary=”path_to_lib.dll;lib” your_script.py
–clean在构建之前清理临时文件。pyinstaller –clean your_script.py
–log-level设置 PyInstaller 的日志级别,常见值有 TRACE、DEBUG、INFO、WARN、ERROR 和 CRITICAL。pyinstaller –log-level=DEBUG your_script.py
–distpath,DIR指定生成的可执行文件的输出路径。pyinstaller –distpath=./output_folder your_script.py
–workpath指定构建过程中的工作目录路径(用于存放临时文件)。pyinstaller –workpath=./build_folder your_script.py
–specpath指定 .spec 文件存放的目录,在打包的时候可以用 .spec 文件的配置避免安装当前 python 环境中的一些 packagepyinstaller –specpath=./spec_folder your_script.py
–hidden-import手动指定 PyInstaller 没有自动检测到的模块或包。pyinstaller –hidden-import=module_name your_script.py
–runtime-hook指定在程序运行时加载的 Python 脚本。pyinstaller –runtime-hook=my_hook.py your_script.py
–debug在打包的可执行文件中启用调试模式,输出调试信息。pyinstaller –debug your_script.py
–platform指定打包目标平台,适用于跨平台打包。pyinstaller –platform=win32 your_script.py
–version-file增加版本信息,指定包含版本信息的文件(如 .rc 文件),以便嵌入版本信息。pyinstaller –version-file=version.txt your_script.py
–icon,-i为生成的可执行文件指定图标文件,使用的时候也要在同一个文件中,路径需要保持可移植。pyinstaller –icon=app_icon.ico your_script.py

例如:icon.ico 是应用的图标文件,--noconsole 选项确保程序启动时不会弹出命令行窗口,–onefile 表示打包成一个 exe 文件。

pyinstaller --onefile --noconsole --add-data="icon.ico;." your_script.py

步骤 3:运行打包后的程序

打包成功之后,PyInstaller 会生成一个 dist 文件夹,里面包含了打包后的 .exe 文件或者 Unix 可执行程序 exec。你可以直接将这个 .exe 文件或者 Unix 可执行程序发送给其他人,他们无需安装 Python 环境就可以运行你的应用。

通过结合 TkinterPyInstaller,我们能够快速开发并打包桌面应用。Tkinter 提供了简单易用的 GUI 组件,而 PyInstaller 让 Python 程序能够无缝地转化为可执行文件,解决了用户安装环境的烦恼。这种组合适用于开发功能较为简单的小型工具和应用,特别适合需要快速交付和部署的场景。

如果你需要更复杂的图形界面或更高性能的桌面应用,可能需要考虑使用其他 GUI 库如 PyQT,但 Tkinter 和 PyInstaller 依然是快速开发和打包桌面应用的强大工具。

后端开发

后端开发是构建 Web 应用程序中的核心部分,主要负责处理客户端请求、数据存储、业务逻辑和与前端的交互等关键部分。Python 提供了多种框架来构建高效的后端服务,其中 FlaskGunicorn 是非常流行且强大的工具。

Flask:轻量级 Web 框架

Flask 是一个 Python 编写的轻量级 Web 框架(https://flask.palletsprojects.com/en/stable/),它遵循了 WSGI(Web Server Gateway Interface)标准,非常适合快速构建 Web 应用。Flask 的设计理念是简单、灵活且扩展性强,它不强制开发者遵循特定的开发方式,因此可以轻松地用于小型应用或更大规模的项目。对于请求量不大的 Python 开发服务,完全可以使用 Flask 来进行应对。

Flask 的核心特点

  1. 轻便易用:Flask 本身提供的功能比较简洁,不会过多限制开发者的选择。
  2. 灵活性高:开发者可以根据需求自由地选择是否使用数据库、认证机制等功能。
  3. 扩展丰富:虽然 Flask 本身比较简单,但有很多第三方扩展库可以集成到项目中,例如数据库 ORM(SQLAlchemy)、认证、表单处理等。
  4. 易于上手:Flask 的文档十分详细,学习曲线较为平缓,适合开发快速原型和中小型应用。

Flask 构建基本 Web 应用

从 Flask 的官网上,我们可以找到一个最简单的 Flask 应用如下所示:

from flask import Flask

# 创建一个 Flask 应用
app = Flask(__name__)

# 定义一个简单的路由
@app.route('/')
def hello_world():
    return "Hello, World!"

# 运行 Flask 开发服务器
if __name__ == "__main__":
    app.run(debug=True)

其中,Flask(__name__) 用于创建一个 Flask 应用实例。@app.route('/') 用来定义 URL 路由和对应的视图函数。app.run(debug=True) 用于运行 Flask 开发服务器,debug=True 表示启用调试模式,帮助开发过程中发现问题。

同时,在 PyCharm 中启动上述脚本之后,一般会出现这样的 Warning 信息提示,这表示直接启动最好只用于开发环境,不要直接用于生产环境:

WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. Running on http://127.0.0.1:5000

点击 http://127.0.0.1:5000 链接之后,可以在 web 页面看到服务如下所示:

Flask 常见功能

Flask 在使用的时候,包括以下常见的功能:

  1. 路由(Routing):定义 URL 与视图函数之间的映射。
  2. 模板渲染(Template Rendering):Flask 集成了 Jinja2 模板引擎,用于动态生成 HTML 页面。
  3. 请求与响应处理:Flask 提供了请求对象 (request) 和响应对象 (response) 来处理 HTTP 请求和响应。
  4. 数据库支持:通过扩展如 SQLAlchemy、Flask-SQLAlchemy 等,Flask 可以支持多种数据库。
  5. 会话与认证:可以使用 Flask-Login、Flask-Security 等库来处理用户会话和认证。

Gunicorn:高效的 WSGI HTTP 服务器

Gunicorn 是一个 Python 的 WSGI HTTP 服务器,专门用于部署 Flask 和其他 Python Web 框架应用。WSGI(Web Server Gateway Interface)是 Python Web 应用与 Web 服务器之间的标准协议。Flask 等框架是基于 WSGI 的,但它们自带的开发服务器不适合在生产环境中使用,因为它不够稳定和高效。

Gunicorn 的核心特点

Gunicorn 的核心特点包括以下内容:

  1. 高效:Gunicorn 使用多个工作进程(workers)来处理并发请求,能够大幅提高性能。
  2. 易于集成:支持 Flask、Django、FastAPI 等多种 Python Web 框架,只需要通过 WSGI 规范进行集成。
  3. 兼容性好:Gunicorn 支持 UNIX、Linux 和 Windows 操作系统,能够在多个平台上运行。
  4. 多进程支持:Gunicorn 支持工作进程和线程池,可以通过配置多核 CPU 充分发挥机器性能。

如何用 Gunicorn 部署 Flask 应用

步骤 1:安装 Gunicorn
在你的虚拟环境中,使用 pip 安装 Gunicorn:

pip install gunicorn

步骤 2:启动 Gunicorn
假设你的 Flask 应用文件名为 app.py,并且应用实例是 app,可以通过以下命令启动 Gunicorn:

gunicorn -w 4 flask_backend:app

其中,-w 4 表示使用 4 个工作进程来处理请求(这个数值可以根据服务器的 CPU 核数进行调整)。flask_backend:app 指定 Flask 应用所在的文件和实例(flask_backend.py 文件中的 app)。

步骤 3:配置 Gunicorn
Gunicorn 提供了许多配置项,以下是一些常见的参数:

参数解释
--workers设置工作进程的数量。
--binds指定绑定的 IP 地址和端口,例如 0.0.0.0:8000
--timeout设置工作进程的超时时间(默认是 30 秒)
--log-level设置日志级别,常用的有 infodebugwarning

例如,使用以下命令运行 Gunicorn,并设置监听所有 IP 地址并监听 8000 端口:

gunicorn -workers 4 --bind 0.0.0.0:8000 flask_backend:app

Gunicorn 工作原理

Gunicorn 启动后,会启动多个工作进程来处理 HTTP 请求,每个进程会并行处理客户端的请求。请求到达 Gunicorn 后,Gunicorn 会将请求传递给 WSGI 应用(如 Flask),然后将响应返回给客户端。Gunicorn 使用的是多进程模型,能够充分利用多核 CPU 来提高应用的吞吐量。通过 Gunicorn 启动 Flask 应用后,你的应用就能够处理更高并发请求并为生产环境做好准备。如果需要更多的配置选项,可以参考 Gunicorn 官方文档 进行调整。

人工智能算法开发

在现代 Web 应用中,人工智能(AI)和机器学习(ML)算法的应用越来越广泛。将 AI 模型部署到 Web 服务中,可以让其他应用或用户通过 API 调用模型进行预测、分类、回归等任务。Flask 是一个轻量级的 Web 框架,非常适合将机器学习模型和 AI 算法封装成 API 服务。PyTorch 是一个流行的深度学习框架,广泛用于开发和训练神经网络。Flask 与 PyTorch 结合 可以实现将训练好的深度学习模型部署成 Web API,供外部应用调用。

当 AI 模型训练完成后,可以通过 Flask 构建 REST API,使得其他应用或前端可以轻松调用模型进行推理。Flask 作为一个轻量级的框架,能够快速构建 API 并且支持与 PyTorch 深度学习框架无缝对接。使用 Flask 和 Gunicorn 部署的 AI 模型,可以通过不同的方式进行扩展,如增加多台服务器、与其他微服务结合等。

构建 Flask API 服务与 PyTorch 模型结合

假设我们已经有了一个训练好的 PyTorch 模型,接下来将其部署为一个 Web 服务。以下是详细步骤:

步骤 1:准备 PyTorch 模型

首先,确保你已经有了训练好的 PyTorch 模型,并将其保存为 .pth 格式。例如这个脚本可以命名为 torch_model.py,内容是:

import torch
import torch.nn as nn

# 假设这是一个简单的神经网络
class SimpleModel(nn.Module):
    def __init__(self):
        super(SimpleModel, self).__init__()
        self.fc = nn.Linear(2, 1)

    def forward(self, x):
        return self.fc(x)

# 创建模型实例并保存
model = SimpleModel()
torch.save(model.state_dict(), 'simple_model.pth')

在这里,我们定义了一个简单的神经网络模型,并将其保存为 simple_model.pth

步骤 2:创建 Flask 应用

安装 Flask:

pip install flask

然后,创建一个 flask_backend.py 文件,来实现 Flask API:

from flask import Flask, request, jsonify
import torch
import torch.nn as nn

# 假设我们使用的是简单的线性模型
class SimpleModel(nn.Module):
    def __init__(self):
        super(SimpleModel, self).__init__()
        self.fc = nn.Linear(2, 1)

    def forward(self, x):
        return self.fc(x)

# 加载模型
model = SimpleModel()
model.load_state_dict(torch.load('simple_model.pth'))
model.eval()  # 切换到评估模式

# 创建 Flask 应用
app = Flask(__name__)

# 定义 API 路由
@app.route('/predict', methods=['POST'])
def predict():
    try:
        # 获取 JSON 数据
        data = request.get_json()

        # 获取输入特征
        features = data['features']
        
        # 将输入转换为 Tensor
        inputs = torch.tensor(features, dtype=torch.float32)
        
        # 获取预测结果
        with torch.no_grad():  # 关闭梯度计算
            prediction = model(inputs)

        # 返回预测结果
        return jsonify({'prediction': prediction.item()})
    
    except Exception as e:
        return jsonify({'error': str(e)}), 400

if __name__ == "__main__":
    app.run(debug=True)

代码解释

  1. Flask 创建应用实例:使用 Flask(__name__) 创建一个 Flask 应用实例。
  2. 加载模型:通过 torch.load('simple_model.pth') 加载预训练的模型权重,并通过 model.eval() 切换到评估模式。
  3. POST 请求路由/predict 路由使用 POST 方法接收数据,并进行模型预测。
  4. 数据处理:从请求中获取 JSON 数据,提取输入特征,并转换为 PyTorch Tensor 格式。
  5. 返回结果:预测结果通过 jsonify() 返回给客户端。

步骤 3:启动 Flask 服务

运行 Flask 服务:

python app.py

Flask 服务默认会在 http://127.0.0.1:5000/ 启动。

步骤 4:测试 API

你可以使用 Postman 或 CURL 工具来测试 API:

示例:发送CURL 请求

curl -X POST http://127.0.0.1:5000/predict -H "Content-Type: application/json" -d '{"features": [1.5, 2.0]}'

响应:得到 json 格式的数据如下:

{
"prediction":
0.3281208276748657
}

步骤 5:部署与优化

将模型与 Flask 服务结合后,你可以将应用部署到生产环境中。为了提高 Flask 应用的性能和稳定性,可以结合使用 GunicornuWSGI 作为 WSGI 服务器进行部署,具体步骤如下:

部署 Flask + Gunicorn

通过下面的步骤,我们可以安装并且启动 Gunicorn。

  1. 安装 Gunicorn:bash复制代码
    pip install gunicorn
  2. 启动应用:bash复制代码
    gunicorn -w 4 flask_backend:app
    这里 -w 4 表示启动 4 个工作进程,根据服务器的 CPU 核数来调整工作进程数。

批量预测:如果模型需要处理大量的请求,可以考虑一次性处理多个样本,而不是每个请求都单独处理。异步处理:可以使用 Celery 等异步任务队列来处理耗时的预测任务,提高系统的响应速度。GPU 支持:如果使用深度学习模型且需要高性能预测,可以在 Flask 服务中配置使用 GPU 进行推理,确保模型推理的速度。

Flask 使得将机器学习模型部署为 API 变得非常简单,适合快速开发和部署 AI 应用。PyTorch 是一个强大的深度学习框架,可以方便地加载训练好的模型进行推理,并与 Flask 紧密集成,提供 REST API 接口供其他系统或前端调用。通过结合使用 FlaskGunicorn,可以让 AI 模型在生产环境中高效稳定地运行,满足高并发请求的需求。这种 Flask 与 PyTorch 的结合应用非常适合用于构建机器学习服务、推荐系统、图像处理、自然语言处理等领域的 Web 应用。

前端开发

前端开发是构建用户界面的核心部分,尤其是在数据可视化应用中,前端开发的作用至关重要。通过 VUEHTMLCSSJavaScriptECharts,可以构建一个动态且互动性强的数据可视化应用,帮助用户更好地理解和分析数据。

HTML:结构化文档

HTML(超文本标记语言)是网页内容的基础,它定义了网页的结构,包括文本、图像、表格、表单等元素。在数据可视化应用中,HTML 主要用来构建网页的结构,如图表容器、按钮、文本标签等。

HTML 在数据可视化中的作用

  1. 容器:使用 <div><canvas><svg> 等标签作为图表容器,将图表嵌入到网页中。
  2. 布局:使用 HTML 元素来组织页面结构,布局不同的可视化图表、数据表格、筛选器等组件。

HTML 示例:图表容器

<template>
  <div>
    <h1>销售数据可视化</h1>
    <div id="chart-container"></div> <!-- 图表容器 -->
  </div>
</template>

CSS:样式和布局

CSS(层叠样式表)负责定义网页的外观和布局,包括颜色、字体、间距、布局等。在数据可视化应用中,CSS 被用来美化图表和布局,使得图表具有良好的可视性和交互性。

CSS 在数据可视化中的作用

  1. 布局:使用 Flexbox、Grid 等布局技术来排列多个图表和控件。
  2. 样式:通过 CSS 自定义图表的外观,例如设置图表的边框、背景、字体等。
  3. 动画:使用 CSS 动画或过渡效果来增强用户体验,比如在数据加载或交互时加入动画效果。

CSS 示例:图表容器样式

#chart-container {
  width: 100%;
  height: 400px;  /* 设置图表容器的大小 */
  margin-top: 20px;
  border: 1px solid #ddd;
  background-color: #f9f9f9;
}

JavaScript:数据处理与交互

JavaScript 是前端开发的核心语言,主要负责网页的行为和交互。在数据可视化中,JavaScript 主要用于处理数据、动态更新图表以及与后端进行交互。

JavaScript 在数据可视化中的作用

  1. 数据处理:使用 JavaScript 来处理和格式化数据,使其符合图表库的要求。
  2. 与 API 交互:通过 Ajax 或 Fetch API 与后端服务器通信,获取实时数据并更新图表。
  3. 事件处理:为用户交互(如点击、拖动、缩放)添加事件处理器,动态更新图表。

JavaScript 示例:使用 Fetch 获取数据

fetch('https://api.example.com/data')
  .then(response => response.json())
  .then(data => {
    this.chartData = data;
  })
  .catch(error => console.error('Error fetching data:', error));

Vue.js:现代化前端框架

Vue.js 是一个渐进式的 JavaScript 框架,专注于构建用户界面,特别是单页应用(SPA)。它的设计理念是简单、灵活且易于集成,适合构建动态且交互性强的 Web 应用。

Vue.js 在数据可视化中的应用

  1. 响应式数据绑定:Vue 的响应式数据系统能够让你轻松地将动态数据与视图绑定。当数据变化时,视图会自动更新,确保界面始终显示最新的数据。
  2. 组件化开发:Vue 鼓励将复杂的应用分解为小的组件,每个组件负责特定的功能,这使得开发和维护变得更加容易。
  3. 生态系统丰富:Vue 的生态系统中有很多优秀的插件,可以快速集成图表、地图、日期选择器等功能,特别适合做数据可视化。

简单示例:Vue 组件结构

<template>
  <div>
    <h1>数据可视化</h1>
    <my-chart :data="chartData"></my-chart>
  </div>
</template>

<script>
import MyChart from './components/MyChart.vue';

export default {
  components: {
    MyChart
  },
  data() {
    return {
      chartData: [10, 20, 30, 40, 50]  // 示例数据
    };
  }
};
</script>

<style scoped>
h1 {
  text-align: center;
  margin-top: 20px;
}
</style>

Vue.js 优势

  1. 易于集成:可以与现有的项目(如传统的 jQuery 应用)进行集成。
  2. 快速开发:通过双向绑定和组件化设计,能够加速开发过程,特别适用于数据驱动的交互式应用。
  3. 数据驱动:Vue 的响应式系统让你可以轻松地实现数据的动态更新。

Echarts 数据可视化

Echarts 的官方页面是:https://echarts.apache.org/zh/index.html

ECharts 是一个基于 JavaScript 的开源图表库,它能够帮助开发者快速创建各种类型的图表,如折线图、柱状图、饼图、雷达图等。ECharts 提供了丰富的功能,如动画效果、交互式操作、响应式布局等,非常适合用于构建动态的数据可视化页面。

ECharts 在数据可视化中的作用

ECharts 在实战中有着非常多的应用,包括:

  1. 丰富的图表类型:提供了包括折线图、柱状图、散点图、饼图、地图、热力图等多种图表类型,满足各种数据可视化需求。
  2. 灵活的配置:通过简单的配置,开发者可以自定义图表的样式、交互和动画效果。
  3. 高性能:ECharts 支持大量数据的渲染,适合处理复杂和海量的数据。
  4. 仪表盘:展示各种业务指标,如销售、流量、库存等数据的动态变化。
  5. 趋势分析:使用折线图或柱状图显示时间序列数据的变化趋势。
  6. 分布分析:通过热力图或散点图展示数据的地理分布或其他维度的分布。

ECharts 配置要点

同时,ECharts 的配置和使用要点包括:

  1. xAxisyAxis:设置图表的坐标轴。
  2. series:定义图表数据,可以选择图表类型(如折线图、柱状图等)和数据。
  3. tooltip:配置提示框,用于显示数据详情。

ECharts 示例:使用 Vue 集成 ECharts

首先,安装 echarts

npm install echarts --save

然后,在 Vue 组件中使用 ECharts:

<template>
  <div>
    <div ref="chart" style="width: 100%; height: 400px;"></div>
  </div>
</template>

<script>
import * as echarts from 'echarts';

export default {
  mounted() {
    const chart = echarts.init(this.$refs.chart);
    const option = {
      title: {
        text: '销售数据'
      },
      tooltip: {},
      xAxis: {
        data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
      },
      yAxis: {},
      series: [{
        name: '销售额',
        type: 'bar',
        data: [50, 60, 70, 80, 90, 100, 110]
      }]
    };
    chart.setOption(option);
  }
};
</script>

在 Echarts 的官方网站(https://echarts.apache.org/examples/zh/index.html)上,用户可以自行根据自己的需求来测试代码并进行可视化,而且可以选择的图表类型非常多,涵盖几乎所有的常见图形。这些图表类型都可以通过简单的配置来定制样式、颜色、动画等,帮助开发者轻松实现丰富的交互式可视化效果。

图表类型说明
折线图 (Line Chart)显示数据随时间变化的趋势,适用于展示时间序列数据。
柱状图 (Bar Chart)用于展示数据的分布,可以是水平或垂直的条形图。适用于比较不同类别的数据。
饼图 (Pie Chart)用于显示各部分在整体中的占比,适合展示比例数据。
散点图 (Scatter Chart)用于展示数据点的分布情况,通常用于两维数据的分布展示,适合查找相关性。
面积图 (Area Chart)是折线图的变体,填充了曲线下方的区域,用于显示多个系列之间的量化差异。
雷达图 (Radar Chart)用于展示多个维度的相对值,适合展示多维度的比较和趋势。
K线图 (Candlestick Chart)用于展示金融数据(如股票、外汇等),显示开盘、收盘、最高、最低价格等信息。
热力图 (Heatmap)用颜色深浅来表示数值大小,适用于密集数据的可视化,常用于地理数据或矩阵数据的展示。
漏斗图 (Funnel Chart)用于展示某一过程中的逐步转化,适合展示销售漏斗等数据流程。
仪表盘 (Gauge Chart)用于展示单一指标在某个范围内的进度或百分比,类似于仪表的表盘。
地图 (Map)用于展示地理信息数据,可以自定义地区、显示热力图等。
树图 (Tree Chart)展示树状层级数据,适合表示分类关系的数据结构。
日历图 (Calendar Chart)用于展示按日期的时间序列数据,常用于展示某个事件的发生情况,按月份、星期等展示数据。
桑基图 (Sankey Chart)用于展示流量的可视化,适合展示数据之间的流动和传递,常用于能源流、资金流等。
旭日图 (Sunburst Chart)是一种层级图,展示数据之间的父子关系,通常用于组织结构图、目录树等。
漏斗图 (Funnel Chart)用于展示某一流程中不同阶段的数据,适用于表示例如销售流程中的转化率。
仪表盘图 (Radar Chart)用于显示各个方向的多维数据,呈现多个维度的比较和分析。
条形图 (Horizontal Bar Chart)类似于柱状图,但数据是水平排列,适用于展示数据的大小或对比。
堆叠柱状图 (Stacked Bar Chart)将柱状图中的数据进行堆叠展示,适合查看各个部分相对于总量的贡献。
堆叠面积图 (Stacked Area Chart)类似堆叠柱状图,但以面积的方式呈现,适合展示时间序列数据的多项叠加变化。

通过的数据的直观可视化,有助于数据分析人员和业务人员更好地发现变化趋势,可以进行下一步业务决策。

如果你对 Python 比较熟悉,也可以直接使用 PyEcharts(https://pyecharts.org/#/)来进行数据分析和数据可视化,它具有以下特点:

  • 简洁的 API 设计,使用如丝滑般流畅,支持链式调用;
  • 囊括了 30+ 种常见图表,应有尽有;
  • 支持主流 Notebook 环境,Jupyter Notebook 和 JupyterLab;
  • 可轻松集成至 Flask,Django 等主流 Web 框架;
  • 高度灵活的配置项,可轻松搭配出精美的图表;
  • 详细的文档和示例,帮助开发者更快的上手项目;
  • 多达 400+ 地图文件以及原生的百度地图,为地理数据可视化提供强有力的支持。

同时,PyEcharts 可以与 web 框架 Flask 进行整合,实现网页端的数据可视化。还可以与 PyInstaller 结合,实现 exe 的开发功能。

数据库开发

在实际开发中,Python 常作为后端开发语言,通过与 MySQL 数据库结合,可以处理数据存储、查询及处理等任务。前端部分,Vue.js 是一个流行的前端框架,用于构建单页面应用,ECharts 是一个基于 JavaScript 的数据可视化库,可以帮助我们以图表的形式展示数据。

在此案例中,我们将通过 Python + MySQL 构建后端,Vue + ECharts 构建前端,展示一个前后端分离的应用,数据从 MySQL 获取并通过 API 提供给前端,前端使用 ECharts 显示数据可视化图表。

后端开发:Python 与 MySQL

步骤 1:安装依赖

首先,需要安装 Python 中用于操作 MySQL 的库。推荐使用 PyMySQLmysql-connector-python

pip install pymysql flask flask-cors

其中,pymysql 用来与 MySQL 数据库进行交互;flask 是后端 Web 框架,用于构建 API;flask-cors:解决跨域问题,使得前端(Vue)能够访问后端(Flask)接口。

步骤 2:配置 MySQL 数据库

假设我们有一个名为 sales_db 的 MySQL 数据库,其中有一个 sales_data 表,存储了每周的销售数据。

CREATE DATABASE sales_db;

USE sales_db;

CREATE TABLE sales_data (
    id INT AUTO_INCREMENT PRIMARY KEY,
    week VARCHAR(20),
    sales INT
);

INSERT INTO sales_data (week, sales) VALUES
('Week 1', 200),
('Week 2', 300),
('Week 3', 250),
('Week 4', 350);

步骤 3:创建 Flask 后端 API

创建一个简单的 Flask 应用,提供数据查询接口。API 从 MySQL 中查询销售数据,并返回给前端。

from flask import Flask, jsonify
from flask_cors import CORS
import pymysql

app = Flask(__name__)
CORS(app)  # 解决跨域问题

# MySQL 配置
db_config = {
    'host': 'localhost',
    'user': 'root',
    'password': 'password',
    'database': 'sales_db'
}

def get_sales_data():
    # 连接数据库
    connection = pymysql.connect(**db_config)
    cursor = connection.cursor()

    # 查询数据
    cursor.execute("SELECT week, sales FROM sales_data")
    result = cursor.fetchall()

    # 关闭连接
    cursor.close()
    connection.close()

    # 转换为字典格式
    data = [{"week": row[0], "sales": row[1]} for row in result]
    return data

@app.route('/api/sales', methods=['GET'])
def sales():
    data = get_sales_data()
    return jsonify(data)

if __name__ == '__main__':
    app.run(debug=True)

其中 /api/sales:这是我们创建的一个 API 路由,用于返回所有销售数据。后端将 MySQL 中的数据查询出来,格式化为 JSON 格式返回给前端。

前端开发:Vue + ECharts

步骤 1:安装依赖

首先,确保 Vue 和 ECharts 已经安装。你可以在 Vue 项目中使用以下命令安装 ECharts。

npm install echarts axios --save

其中,echarts 用于图表绘制;axios 用于发送 HTTP 请求,获取后端数据。

步骤 2:创建 Vue 项目

假设你已经有一个 Vue 项目结构,创建一个名为 SalesChart.vue 的组件来显示销售数据图表。

<template>
  <div>
    <h1>每周销售数据</h1>
    <div ref="chart" style="width: 100%; height: 400px;"></div>
  </div>
</template>

<script>
import axios from 'axios';
import * as echarts from 'echarts';

export default {
  data() {
    return {
      chartData: [],  // 存储从后端获取的数据
    };
  },
  mounted() {
    // 请求数据
    axios.get('http://localhost:5000/api/sales')
      .then(response => {
        this.chartData = response.data;
        this.drawChart();
      })
      .catch(error => {
        console.error('Error fetching sales data:', error);
      });
  },
  methods: {
    drawChart() {
      const chart = echarts.init(this.$refs.chart);

      const option = {
        title: {
          text: '每周销售数据',
        },
        tooltip: {},
        xAxis: {
          data: this.chartData.map(item => item.week),  // 获取周数据
        },
        yAxis: {},
        series: [
          {
            name: '销售额',
            type: 'bar',
            data: this.chartData.map(item => item.sales),  // 获取销售数据
          },
        ],
      };

      chart.setOption(option);
    },
  },
};
</script>

<style scoped>
h1 {
  text-align: center;
  margin-top: 20px;
}
</style>

代码说明:

  1. axios 请求数据:在 mounted 钩子中,使用 axios.get 向 Flask 后端的 /api/sales API 发送 GET 请求,获取销售数据。
  2. 绘制图表:在数据返回后,调用 drawChart 方法,使用 ECharts 在 ref="chart" 的容器中绘制柱状图。xAxis.data 映射每周的数据,series.data 映射每周的销售数据。
  3. ECharts 配置:设置图表的标题、提示框、X 轴、Y 轴、图表类型(柱状图)。

步骤 3:启动前端项目

使用 Vue CLI 启动前端应用:

npm run serve

这将启动一个开发服务器,默认地址是 http://localhost:8080/

前后端对接流程

  1. 后端(Flask):创建一个简单的 API 接口 /api/sales,从 MySQL 数据库中查询销售数据。
  2. 前端(Vue + ECharts):前端通过 axios 向 Flask 后端发送请求,获取销售数据并使用 ECharts 渲染为图表。

前后端的部署

步骤 1:后端部署

使用 Gunicorn 启动 Flask 应用:

gunicorn -w 4 flask_backend:app

Flask 后端部署到服务器:可以使用 Docker 等进行后端服务的部署。

步骤 2:前端部署

使用 Vue CLI 构建前端应用:

npm run build

部署到静态文件服务器:可以将构建后的前端文件部署到服务器(如 Nginx、Apache)或使用云服务(如 Netlify、Vercel)。

使用 Python 和 MySQL,后端通过 Flask 提供 API 来查询销售数据,并返回给前端。前端开发使用 Vue.js 作为前端框架,ECharts 用于数据可视化展示。前端通过 axios 向后端 API 发送请求,获取数据并用 ECharts 绘制图表。

结束语

在互联网公司的开发流程中,各个环节的职责通常是分工明确的,客户端开发、后端开发、人工智能算法开发、前端开发以及数据库优化等各自独立且专业化。然而,随着业务的多元化和复杂化,某些特殊的项目需要一两位工程师能够实现从客户端到云服务,从云服务到数据库,再到前端展示的全流程开发。这种跨领域的开发不仅要求工程师具备较为全面的技术栈掌握,还需要在实践中培养解决问题的综合能力。

全栈开发并不是仅仅涉及前后端的开发,更是从整体架构、数据流转到用户界面的完整理解和掌控。工程师需要具备对各个模块的深刻认识,能够灵活地协调不同开发环节之间的需求和要求,以达到高效、简洁、易维护的开发目的。在这个过程中,工程师不仅要熟悉每个开发模块的核心工具与技术,还要具备整合各个模块的能力,确保系统的流畅性与稳定性。

对于公司来说,拥有具备全栈开发能力的工程师,在效果验证的初期,不仅能有效地提升开发效率,减少团队沟通成本,还能加速项目交付和优化迭代。但也需要注意,全栈开发的实践更适用于一些复杂度较低、需求较为明确的项目。在更大规模、更加复杂的应用系统中,专注于某一领域的专家仍然具有不可替代的重要性,而且程序员也应该朝着技术深度与技术广度都发展的方向进行持续的努力。

强化学习的入门方法

强化学习是人工智能领域一个非常重要的分支,在游戏 AI 领域的应用是无处不在的,包括大家耳熟能详的 AlphaGo 和王者荣耀,其背后都使用了大量的强化学习方法。随着人工智能技术在互联网公司的日渐普及,人们对人工智能的期待也越来越高,也期待着人工智能未来能够做更多的事情。除了各种门禁系统,人脸识别系统在各个公司的应用之外,在游戏领域,强化学习也扮演着举足轻重的作用。

当前的强化学习技术除了使用在游戏 AI 领域之外,也在机器人控制,推荐系统等领域有着很多应用,也取得了不少商业价值。但强化学习的学习还是存在一定的门槛,除了一些在线的 tutorial 和零零散散的资料之外,其实还是需要一本相对完整和优秀的教材来辅助高校的老师和学生,只有这样,强化学习才能够成为一门课进入高校课堂。

上海交大的强化学习团队教师张伟楠,沈键,俞勇合力撰写了一本关于强化学习的,理论与实践相结合的书籍《动手学强化学习》。本书的每个章节除了必要的理论介绍,公式推导之外,还包含了相关的 Python Notebook。Notebook 中包含了算法过程和可运行代码,方便读者阅读相关内容并立刻进行实践。

《动手学强化学习》

《动手学强化学习》是一本相对完整的书籍,读者并不需要知道太多的预备知识就可以直接上手这门课。本书包括三个部分:

  • 第一部分:强化学习基础;
  • 第二部分:强化学习进阶;
  • 第三部分:强化学习前沿。

在第一部分,作者们介绍了强化学习的基本原理,多臂老虎机,马尔可夫决策过程,动态规划算法等内容;在第二部分,作者介绍了 DQN 算法及其改进算法,策略梯度算法,Actor-Critic 算法等诸多算法,让作者能够在第一部分的基础上更进一步的理解强化学习;在第三部分,作者们撰写了前沿的强化学习算法,包括离线强化学习,多智能体强化学习等内容,让读者在之前的基础上迅速进入到强化学习的前沿领域。

本书的另外一个亮点就是 Python Notebook 的代码丰富完善,读者可以一边阅读强化学习的基础知识,一边进行代码的开发工作。基于理论和实战相结合的办法,读者可以尽快掌握强化学习的实战方法。学习这本书需要读者有一定的 Python 开发基础,并且这本书有相应的强化学习视频,方便读者尽快掌握这本书。