资讯动态

实战指南:如何用ChromaDB快速搭建你的第一个LLM应用(附Python代码)

发布时间:2026/8/23 19:19:25 来源:尧图企业网站定制
近期, 和几位刚刚涉猎大模型应用开发领域的朋友进行交流, 发觉了这样一个颇为常见的情形: 大家借助API能够迅速实现对模型的调用, 进而生成文本, 然而, 一旦提及要致使模型“记住”同时“理解”自身所持有的私有数据, 像是公司文件、个人记录, 或者产品知识仓库, 往往就会陷入一种不知从何处着手的状态, 背后所蕴含的核心难题, 实际上就是怎样促使大模型在访问以及利用非结构化的文本信息方面具备高效性。擅长处理表格数据的传统数据库, 在文本的 “语义” 方面却毫无办法。而向量数据库的用武之地就在这里。简单讲, 向量数据库是为处理 “嵌入 向量” 这种高维数据量身设计的数据库。存入 “苹果” 这个词或者 “apple” 这个单词它并不在意, 它在乎的是经过模型计算后, 这两个词代表其语义 的数学向量彼此是不是相似。当你提出“一种常见的水果, 呈现红色或者绿色”这样的询问时, 它能够迅速找寻到跟这个问题的向量表现最为接近的“苹果”向量, 进而达成基于语义的搜索以及检索行为。这对于构建检索增强生成即RAG应用、智能客服、个性化推荐各类场景而言, 是非常关键重要的。在林林总总的众多选择选项之中, 凭借其极为简约的API设计、与生态的无缝和谐集成以及对开发者的友善友好性, 它成为为数众多良多初学者以及快速急速原型开发的优先选择。它并非像那般属于托管服务, 需要额外另行付费, 也不像Faiss那样更倾向偏向底层算法库, 需要更多诸多配置。提供了一种开箱即用的嵌入式数据库体验, 使得你能够在短短几分钟内, 将语义搜索能力集成到你的程序或者脚本之中。今天, 我们直接抛开复杂的理论, 立即上手, 借助代码一步步去构建一个能够理解你个人文档的迷你LLM应用。## 1. 环境准备与核心概念扫盲在开始编写代码以前, 花费几分钟去理解几个核心概念, 能够让你后续的每一步都变得更加清晰。首先, 什么是“嵌入”? 你能够把它想象成文本的“数字指纹”。具有优秀特质的嵌入模型, 像是text--ada-002, 又或者是开源的BGE、-系列等, 能够把一段文字转变成一个具备固定长度的数字列表, 也就是向量。这个向量存在神奇之处, 在于语义相似的文本, 其向量于数学空间中的距离, 通常以余弦相似度去衡量, 也会十分接近。注意, 选择嵌入模型乃是影响应用效果的关键一步。对于入门而言, 我们推荐使用all--L6-v2模型, 它有着体积小、速度快的特点, 并且在多语言语义相似度任务方面表现良好, 极为适合本地测试。接下来要进行的是向量数据库的核心工作, 也就是近似最近邻搜索。当你拥有成千上万个文档向量之后, 用户提出了一个问题, 此时我们需要从所有向量当中迅速找出与问题向量最为相似的那几个。要是逐个进行比较的话, 效率将会是灾难性的。向量数据库内部采用了像HNSWSmall World这类高效索引算法, 这般能在毫秒级时间内达成海量向量的检索。我们的实战目标是搭建一个本地知识问答系统。假设你身为一名健身教练, 有着一堆私人的训练方法笔记采用TXT格式。我们会讲授“读懂”这些笔记, 而后你能够以自然语言进行提问, 像是“怎能改进深蹲姿势? ”, 此系统能够自动从笔记里找出最为相关的片段, 并整合成为一个连贯的回应。首先, 得保证你的环境, 建议版本在3.8以上已然就绪, 接着安装必备的库: -这里我们安装作为向量数据库, -库会为我们给予本地运行的嵌入模型, 无需依靠外部API, 便利且毫无成本。用最开头的起始阶段来做初始化数据库与文档加载之事, 虽开启头端困难重重, 可使用开头极为简单便利。由此有持久化以及内存这两种模式供其选择。针对首次之实验而言, 我们能够从内存模式着手开启进程, 此模式虽然运行速度较快, 然而一旦程序关闭之后数据便会消逝不见。而如果等到你确定流程顺畅运行无误且畅通之后, 再去切换成为持久化模式就根本不费吹灰之力了。首先让我们去创建出一个对象, 并且指定一个集合。集合存在这种情况, 它是其中用来存储相关文档以及向量的基础单元, 你能够将其类比成传统数据库里的一张表格。 # 创建一个临时的、内存中的客户端。这段内容存在较多混乱和错误表述, 按照要求尽量规范改写如下: 数据不会被存储至磁盘要((等于引号内的双引号加逗号, 等于空值)), 创建一个集合, 若存在同名的, 先删除而后创建, 以此确保实验环境是干净的, 为空值, 尝试, 依据名称, 等于, 依据名称, 打印输出集合某某创建成功的提示语句, 现在, 我们需要一些数据, 假设你的健身笔记存放于一个名为点txt的文件里, 每行是一条笔记, 或者是一个包含多个TXT文件的目录。 这段内容实在比较混乱, 可能无法达到非常精准的改写要求, 你可以进一步补充说明内容以便更准确处理。为对那种真实场景予以模拟, 我凭借手动方式去创建几条示例笔记, 即: # 模拟的健身笔记数据 。进行深蹲之际, 应当要保持背部处于笔直状态, 脚尖微微去做那种向外展开, 然后下蹲至致使大腿跟地面呈现平行的时候。卧推的关键要点在于让肩部下沉, 胸部要挺起来, 杠铃往下放的时候要接触到中下胸的位置, 推起的时候其轨迹大致呈现出弧线状。硬拉开始启动之前, 要深深地吸入一口气, 把核心部位收紧, 以腿部以及臀部作为主导来发力, 将杠铃紧紧地贴着小腿把它拉起来。像跑步或者跳绳这类有氧运动, 每周开展3至5次, 每次持续的时间要超过30分钟能够有效地去提升心肺功能。蛋白质的摄入对于肌肉的修复是极其重要的, 建议健身的人群每天每公斤体重摄入1.5至2克的蛋白质。如弓步走、高抬腿之类训练前的动态拉伸, 能够激活肌肉, 继而降低受伤的风险。每个动作保持15至30秒的训练后的静态拉伸, 都有助于缓解肌肉带来的紧张, 进而起到促进恢复的作用。7至9小时那样充足的睡眠乃是肌肉生长以及身体恢复的重点所在, 绝对不可以被忽视。# 为每条文档生成一个唯一的IDids 存在文档的情况下, 紧接着的下一步便是要把它们给转化成向量, 在此这个地方我们引入一个库用于在本地生成嵌入。## 3. 第二步: 生成嵌入向量并且存入数据库, 这可是将文本“喂”给数据库的关键的核心步骤。然后我们选用一个即便轻量级然而效果还挺不错的模型all--L6 - v2。在首次运行的时候它会自动去下载模型大概80MB。s # 加载嵌入模型 (all--L6 - v2)打印出“嵌入模型加载完毕。”。, 你提供的内容有些混乱不太清晰准确完整呀, 勉强按照要求改写就是: “)# 针对每一个文档来生成嵌入向量 通过这么做().() # 之后把它转变为列表的格式进行查看print(f已对有着 {长度} 的条款状文档生成嵌入向量, 向量维度: {长度})此刻, 我们手里有这样三样物品: 原本的文本、与之相符的IDids以及经过计算得出的向量。已然到了该把它们存进去的时候。add方法在此起着密钥般的作用: # 将文档、ID和嵌入向量添加入集合之中.add(,,idsids)print(文档以及向量已经成功被存入集合。” 但这样的改写感觉很生硬且并不能很好地表达确切想法, 建议你检查下原始内容是否准确清晰后再让我改写。”这儿存在着至关重要的一则细节: 属于我们的情况是, 在外部开展向量的计算工作, 之后借助参数予以传入。同时也对“自动嵌入”功能予以支持, 也就是说, 你单单只是传入文档以及 ID, 它借助集成的嵌入函数像是调用 API于后台替你进行计算。然而针对于本地开发以及控制成本而论, 先在外部进行计算而后存入的这种方式是更为透明且灵活的方式。若要验证数据有没有存入, 我们能够开展一回简易的计数查询: # 查看集合里的文档数量count .count()print(f此刻集合中存放的文档数量是: {count})万一一切都顺利, 你会瞧见数量跟你增添的文档数相同。到此, 你的私人知识库已达成了向量化存储。## 4. 第三步: 实施语义搜索与问答检索数据库建好了, 现在来测试它的“搜索”能力。在数据库中搜索最相似的文档向量之前, 首先要把问题转化为向量, 这是检索经历的两步中的第一步, 就如同用户提出问题, 像是“深蹲做完后膝盖有点疼, 可能是啥原因”, 现在又有新的提问“深蹲时膝盖疼痛可能的原因是什么”。).(), 注意输入是列表, 2. 在集合中进入查询, 等于.query(等于, 查询向量等于3, 返回最相似的3条结果。, , # 规定返回的内容)# 3. 剖析并且呈现结果print(f\n针对问题: {})print(搜寻到的最为契合的文档片段: )for i, (doc, dist) in (zip(。,执行这段代码, 你会发觉返回的并非直接针对“膝盖疼原因”的笔记, 缘由在于我们先前的笔记里不存在这一条。然而系统返回了最为相关的“深蹲姿势要点”。这恰好展现了语义搜索的魅力——它依据“深蹲”这个核心语义寻找到了最为相关的资料。在实际运用中, 你的知识库需要尽可能全面地涵盖用户可能会问到的问题领域。越小的距离值, 意味着相似度越高。默认采用的是余弦距离, 其取值处在0到2之间, 0表示的是完全相同。当下, 我们有检索到的相关文档片段, 怎样把它们变为给用户的答案呢? 这便需要引入大语言模型去“消化”这些片段并组织语言。对于我们所选用的用来进行调用的GPT模型, 在此以其例来说明你是需要自行去为自己准备相对应的API Key才行的: os, 假设你所拥有的API Key已经被设置在了环境变量当中。 os.()def (, ):要结合经过检索后所得到的文档上下文的情况, 借助LLM来生成所需要的答案# 把检索得来的文档进行拼接从而形成上下文 \n\n.join()# 构建而出给予LLM的提示词 f请依据以下所提供的关于健身知识方面的上下文, 来对用户所提出的问题进行回答。请你明确一下具体需求, 你提供的这段“try: ..(modelgpt-3.5-turbo, # 或gpt-4”不太完整且表述混乱, 不太清楚要怎么针对性改写。什么, 等于0.7, 等于500, 等等, 就如同e一样, f双引号范围内“调用语言模型时出错: ”加上{e}, 然后是“# 使用检索到的文档生成答案 ” , 嗯, 总之就是这样。 (, )打印\n 乘以50, 打印生成的回答: , 打印, 打印乘以50, 这个函数便是RAG检索增强生成的核心所在, 它先是借助向量数据库检索出相关知识, 而后把这些知识当作“参考资料”跟用户问题一同提交给大模型, 要求模型依据此来生成答案, 这大幅降低了模型“胡编乱造”的可能性, 提升了回答的准确性以及可信度。## 5. 进阶技巧: 关于元数据过滤与生产环境部署基础的问答流程已被顺畅跑通, 不过在实际的项目里 , 你很快就会碰到更为复杂的需求, 像你的笔记或许会划分成 “训练技巧”、“营养学”、“恢复方法” 等不一样的类别 , 你期望仅仅搜索某一个类别的笔记 , 此时 , 就需要运用到的元数据过滤功能 , 我们在增添文档时 , 能够同时额外附上一些元数据: # 假定我们给每条文档添加类别以及创建年份 。为了演示元数据, 要创建出一个新的集合, 其内容是.(nameeta)。在添加文档的时候, 要把元数据包含进去, 具体做法是.add(,,,idsids)。当下, 我们能够开展带有过滤条件的查询操作。举例来讲, 要是只想去搜索“恢复方法”这个类别之下的笔记: 进行带元数据过滤的查询, 具体的操作是.query(,5,where{: {$eq:恢复方法}}, 这里的过滤条件要求等于“恢复方法”。, )打印“在‘恢复方法’类别之下的检索所得结果: ”, 对于文档, 元数据, 在压缩之中。,):print(f- {doc}类别{meta}, 年份{meta}的过滤语法极为灵活, 它支持等于$eq这种情况, 还支持不等于$ne, 大于$gt、小于$lt以及逻辑与或$and, $or等操作, 借助这些能让你精准地定位到所需的信息。当应用从实验朝着生产迈进时, 你得去考虑持久化存储, 性能优化以及可维护性这些方面。把内存模式切换成持久化模式是相当简单的: # 生产环境: 使用持久化客户端 .(path./) # 数据会被保存在本地的./目录# 获取或者创建集合。数据会持久化在磁盘之上。等于, 点tion, 括号内名称为下划线base, 后续的add操作, 以及query操作, 与之前完全一致, 对于更大的数据集而言, 你可能需要关注索引策略, 默认的索引设置, 对中小型数据集, 这指的是数万到数十万条文档, 已经足够高效, 如果数据量继续增长, 可以考虑调整创建时的配置, 或者为未来版本中可能提供的更高级索引参数, 另一个生产级考量是嵌入模型的选择。全——L6 - v2适宜入门, 然而针对于中文场景或者更高精度需求, 能够切换至——L12 - v2对多语言予以支持所占体积更大或者BGE系列中文模型。仅仅只需更换所加载的模型名称就行, 代码的其他部分大致保持不变。最终, 一个完备的应用并非只会拥有命令行界面。你能够借助或Flask把上述核心功能包装成API, 利用或迅速构建出一个交互式的Web界面。如此一来, 非技术方面的同事也能够轻松地使用这个知识问答系统了。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价