ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

30天从零开始学AI应用开发(Day 17):ChromaDB 上手:给本地文档建一个“外挂大脑”

30天从零开始学AI应用开发(Day 17):ChromaDB 上手:给本地文档建一个“外挂大脑” 这是系列的第 17 篇。整个系列写给零基础、想入行 AI 的朋友每天一篇30 天后你会做出 3 个能写进简历的项目。这篇解决什么问题昨天你把文字变成了坐标也感受到了“意思相近的两句话相似度更高”。今天要解决一个新问题这些坐标存哪儿总不能每问一次就重新算一遍全部资料的坐标吧那也太慢了。我们需要一个能存向量、能快速找出最近邻居的地方。这个东西叫向量数据库。今天要用的 ChromaDB 是最好上手的向量数据库不用装服务器、不用配环境pip 装完就能用。今天结束的时候你会拥有一个真的能“提问就返回相关段落”的外挂大脑。一、向量数据库就是给坐标建的索引普通数据库擅长的是“精确匹配”查 ID 为 1001 的用户、查名字叫张三的记录。但我们要的是“找离这个坐标最近的五个点”这是完全不同的一类查询。向量数据库就是为这类查询设计的。打个比方普通数据库像字典按字查向量数据库像图书馆的书架索引你说“我想找讲历史的”它能把相关的几排书指给你。名字听起来高深你别被它唬住。今天你会看到用起来只有三个动作建库、塞数据、查数据。二、装好建个库先装包pipinstallchromadbChroma 的一大好处是默认在本地存文件不需要启动任何服务。建库的代码就三行importchromadb# 数据存在当前目录的 chroma_db 文件夹里重启也不会丢clientchromadb.PersistentClient(path./chroma_db)# 建一个集合collection可以理解成一张表collectionclient.get_or_create_collection(namemy_docs)注意 get_or_create 这个名字有就打开没有就建。所以这段代码重复运行也没问题第二次会直接打开已有的库。三、塞数据三步一份往库里存东西要准备三样documents原文存进去方便后面拿出来给 AI 用embeddings向量Chroma 可以自己算但为了统一建议我们显式传ids每条的唯一编号必须用来自查和更新fromopenaiimportOpenAI oaiOpenAI(api_key你的密钥,base_urlhttps://api.deepseek.com)defembed(text):复用昨天的函数把文字变成向量roai.embeddings.create(modelembedding-model-name,inputtext)returnr.data[0].embedding# 假设这是你切好的资料片段chunks[公司差旅费报销流程先提交申请单出差结束后五个工作日内提交发票。,差旅标准市内交通每天不超过 100 元住宿费按城市级别报销。,员工请假流程提前一天在系统提交申请由直属主管审批。,]# 批量入库一个文件对应一份资料collection.add(documentschunks,embeddings[embed(c)forcinchunks],# 逐条算向量ids[fdoc_{i}foriinrange(len(chunks))]# 生成唯一编号)print(入库完成共,collection.count(),条)关键在 ids 这一步。它就相当于每份资料的门牌号重复的 id 会被当成同一条覆盖掉所以生成时要保证唯一。四、查数据问一句拿回相关段落这一步是见证时刻。你直接用大白话提问看它能不能把对的段落捞出来question出差住宿怎么报销resultcollection.query(query_embeddings[embed(question)],# 把问题也变成向量n_results2# 只要最相近的 2 条)print(查到的资料)fordocinresult[documents][0]:print(-,doc)跑一下你会看到它返回的是差旅报销和差旅标准那两条请假那条没有被选上。注意提问里用的是“住宿报销”原文里写的是“住宿费按城市级别报销”字面上并不完全一致但依然被准确找到了。这就是昨天讲的向量检索的威力。五、把检索和回答接起来现在把两头连上就有了一个最小的 RAGdefask(question):# 第一步检索resultcollection.query(query_embeddings[embed(question)],n_results2)context\n.join(result[documents][0])# 把资料拼成一段# 第二步让 AI 基于资料回答promptf请只根据下面的资料回答问题资料里没有就说“资料中没有提到”。 不要使用资料之外的知识。 资料{context}问题{question}responseoai.chat.completions.create(modeldeepseek-chat,messages[{role:user,content:prompt}])returnresponse.choices[0].message.contentprint(ask(出差住宿怎么报销))提示词里那两句约束是灵魂所在只根据资料回答、资料里没有就说不知道。这是 RAG 治幻觉的关键也是 Day 8 讲的“把隐性要求变成显性要求”的实战。试着问一个资料里没有的问题比如“年假有多少天”它应该老实告诉你资料里没写而不是编一个数出来。常见报错排查报错一chromadb 装不上卡在编译依赖。优先升级 pip 再装。如果还是不行指定清华源pip install chromadb -i https://pypi.tuna.tsinghua.edu.cn/simple。报错二入库时提示 embeddings 维度不一致。说明不同批次用了不同的 Embedding 模型。同一个集合里所有向量必须来自同一个模型检查一下调用代码。报错三query 返回的结果不太相关。三个可能一是切分太粗一段太长混了多个主题二是检索条数太少试试加大 n_results三是文档本身不含答案。切分的问题 Day 18 专门讲。报错四ids 重复导致数据被覆盖。生成 id 时带上序号或者文件名别只用内容做 id。报错五数据没保存住重启后没了。检查是不是用了临时客户端。想要持久化必须用 PersistentClient 并指定 path。今天的作业把你的一份真实资料笔记、手册、常见问题都可以切分成几段入库然后问它三个问题两个资料里有的一个资料里没有的。把结果贴到评论区尤其是最后那个问题的回答看看它有没有老实说“资料里没有”。明天预告Day 18《文档切分与检索优化RAG 效果好坏的分水岭》。今天库建起来了但效果只能说能用。为什么有时候它答得准有时候答非所问问题多半出在切分上。明天讲清楚切分的原则、怎么定每段长度、怎么提升召回率。这一篇的内容直接决定你的项目能不能拿出手。————————————————*系列目录30天从零开始学AI应用 开发
返回列表