尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Python+Ollama+Chroma+LangChain:打造能记住上下文的客服机器人

Python+Ollama+Chroma+LangChain:打造能记住上下文的客服机器人 用 Python Ollama Chroma LangChain 攒一个能记住上下文的客服机器人其实没有想象中那么难先说个场景我在本地跑过不少开源大模型也试过直接调用各种在线 API 来做问答。但真到了要做一个“能记住用户上一句说了什么”的客服系统时才发现事情没有想象中那么简单。纯粹调用模型接口只能做到一问一答用户说“刚才那个问题再解释一下”模型根本不知道“刚才”指的是什么。后来我把 Python、Ollama、Chroma、LangChain 这四个东西组合在一起才真正把“多轮对话”这件事跑通。这篇博文就是记录我从零开始搭建这套客服系统的全过程重点放在整体的技术选型思路、环境准备、第一个能跑起来的多轮对话版本以及我在实际开发中踩过的坑。如果你是刚接触 LangChain 或者本地部署大模型的新手这篇文章能帮你少走不少弯路。如果你已经有一定基础也可以重点看看第四部分的故障排查很多问题是我翻了不少 issue 才搞明白的。先说清楚这套组合是干什么的Ollama 负责在本地把大模型跑起来不依赖云端 API数据不用出内网LangChain 负责把“调用模型”这件事包装成标准的接口同时提供了处理对话历史、管理 Prompt 的工具Chroma 是一个轻量级的向量数据库用来存放客服知识库的向量索引让机器人能从文档里检索答案而不是每次都瞎编。Python 则是把这三者粘合在一起的胶水语言。整体可以理解成Python 是控制台Ollama 是大脑Chroma 是记忆仓库LangChain 是神经系统。1. 方案选型为什么偏偏是这四个组件1.1 为什么用 Ollama 而不是直接调云端 API我最早做客服机器人原型的时候用的是在线大模型 API。效果虽然不错但有几个问题始终绕不开第一是数据隐私客服对话里经常包含用户手机号、订单号这类敏感信息发送到云端总归不踏实第二是成本客服场景的请求量是不可控的一旦并发上来账单数字看得人心慌第三是网络依赖内网环境或者网络不稳定的情况下API 调用延迟会直接影响用户体验。Ollama 解决的就是这三个问题。它是一个本地模型运行时安装之后会自动拉起一个本地的 HTTP 服务默认监听 11434 端口。你只需要把模型下载到本地后续所有推理都在本机完成。我用一台 32GB 内存、无独立显卡的机器实测过跑 7B 级别的量化模型生成速度大概在每秒 10 到 15 个 token 左右做客服问答是够用的。如果有 NVIDIA 显卡速度会快很多但 CPU 也并不是完全不能跑。Ollama 还有一个很方便的点它对模型格式做了统一封装。你不需要自己处理 PyTorch 权重、分词器、推理脚本这些东西一条命令就能把模型拉下来跑起来。这对快速验证想法特别有利我可以先花十分钟把整个链路跑通再回头优化细节。1.2 为什么用 Chroma 而不是传统的数据库客服系统要回答的很多问题答案都藏在产品文档、帮助手册、FAQ 里。我的做法是把这些文档切分成小段然后转成向量存起来用户提问时先在向量库里做相似度检索找到最相关的几个片段再把这些片段和用户问题一起交给大模型生成答案。这种方案就是现在很流行的 RAG检索增强生成。向量数据库的选择上市面上有 Chroma、Milvus、Qdrant、Weaviate 等好几个。我选 Chroma 的理由非常简单对于单机版客服系统这个场景Chroma 是配置成本最低的。它是一个嵌入式数据库不需要单独部署服务端直接在 Python 进程内运行数据落到本地文件。而 Milvus 和 Qdrant 虽然功能更强大、支持分布式部署但需要额外维护一套服务对一个小型客服系统来说有点杀鸡用牛刀了。Chroma 的 API 设计也很直观核心操作就三个创建集合、往集合里添加文档、查询相似内容。我用一个不恰当的比喻来解释它和传统数据库的区别传统数据库像是一个 Excel 表格你往里存数据时要知道有哪些列而 Chroma 像是一个图书馆的索引卡你给它一本书它自动帮你把书里的章节、段落编号、关键词排序整理好你只需要说“我想找和这个主题相关的内容”它就能把最相关的书页递给你。1.3 LangChain 在这套系统里的真实价值说实话LangChain 刚出来的时候我也觉得它的抽象太多学起来费劲。但用多了之后我承认它在几个关键环节上确实帮我省了不少事。最实用的功能是多轮对话的消息历史管理。LangChain 提供了RunnableWithMessageHistory和ChatMessageHistory这样的组件能够把每次对话的输入输出追加到一个存储里在调用模型时自动拼接到 Prompt 中。如果没有这个能力我自己得维护一个会话列表每次请求时把所有历史消息找出来手动格式化放到 Prompt 里还要处理超过上下文长度时到底丢弃哪些历史的问题。LangChain 把这些基础逻辑封装好了我只需要配置一个 session ID就能实现多轮会话的隔离。LangChain 还有一套统一的模型接口。今天用 Ollama 跑本地模型明天想换成 OpenAI 的 GPT只需要改一行代码切换ChatOllama和ChatOpenAI下游的检索和 Prompt 逻辑完全不用动。这对以后系统迁移或者做双路备份非常利好。当然LangChain 也不是没有槽点。它的 API 在 0.1 到 0.2 版本之间有比较大的变化网上搜到的很多旧教程在新版本上直接跑不通。我看到网上很多人都在讨论 LangChain 和 LangGraph 的区别也有人在问 LangChain Agent 怎么用。以我目前做客服机器人这个项目来看LangChain 自带的能力已经足够LangGraph 那种复杂的状态机和多智能体编排等以后需要构建更复杂的对话流程时再引入不迟。新手入门还是建议先把核心概念吃透。2. 环境准备从零开始搭起开发环境2.1 Python 环境安装与配置这套系统的所有代码都是用 Python 写的所以第一步是把 Python 环境配置好。我推荐使用 Python 3.10 或 3.11 版本太老的版本对 LangChain 新版本支持不好太新的版本比如 3.13有些依赖库的预编译包可能还没跟上装起来容易出问题。Windows 用户直接去 Python 官网下载安装包安装时务必勾选“Add Python to PATH”选项不然命令行里敲python会提示找不到命令。macOS 用户建议用 Homebrew 安装brew install python3.11。Linux 用户用系统自带包管理器即可比如 Ubuntu 上是sudo apt install python3.11。装完之后打开终端Windows 上是 CMD 或 PowerShell输入python --version看到熟悉的版本号输出说明安装成功了。我习惯再确认一下 pip 的版本pip --version后续安装 Python 库就靠它了。这里我有一个小建议不要直接往系统 Python 里装依赖否则项目多了以后各种包版本冲突真的很烦人。我用的是 Conda 来管理不同的项目环境比如这个客服系统就单独建了一个环境conda create -n chat_cs python3.11 conda activate chat_cs提示如果公司网络限制比较多pip 安装第三方库超时的话可以临时切换为国内镜像源比如清华源pip install -i https://pypi.tuna.tsinghua.edu.cn/simple 包名。这只是把 Python 软件包的下载服务器改成访问更快的节点属于常规操作。2.2 Ollama 安装与模型下载Ollama 的安装分两步先装运行时再拉模型。运行时安装很简单去 Ollama 官网下载对应操作系统的安装包或者用官方脚本安装。装完以后在终端输入ollama --version确认安装成功。然后是模型下载。Ollama 支持很多开源模型我用的主力是qwen2.5:7b或者llama3.1:8b。对于客服场景这两个模型的指令跟随能力和中文理解能力都算不错而且参数量适中普通机器跑得动。下载命令非常直观ollama pull qwen2.5:7b如果你经常碰到模型下载中断、速度很慢的情况这里分享两个合规、靠谱的解决思路。第一个思路是换源。Ollama 的模型下载地址默认指向海外仓库国内访问确实不稳定。Ollama 支持通过环境变量OLLAMA_MODELS修改模型存储位置也有社区维护的镜像站点可以配置。也可以检查一下自己所在网络环境是否本身就存在限制考虑使用更稳定的网络方式来下载。第二个思路是离线导入。如果在线下载实在搞不定可以去一些国内公开的大模型社区比如某些提供模型文件直传的站点把模型文件下载下来然后用ollama create命令从本地配置文件导入到 Ollama 中。这个方法虽然稍微麻烦一点但胜在稳定、可控而且不受网络波动影响。我离线导入过一个 4.7GB 的量化模型文件按官方文档写一个Modelfile一句一行的配置然后执行导入实际上手并不复杂。模型下载完成后用ollama list可以看到已安装的模型列表和占用空间。我建议只保留日常要用的 1 到 2 个模型因为 7B 级别的模型动辄几个 GB硬盘空间消耗不小。2.3 Chroma 与 LangChain 的安装Chroma 和 LangChain 都通过 pip 安装。但这里有个版本兼容的问题我在第一次安装时就吃过亏。如果按照网上的老教程直接pip install chromadb langchain大概率会装到最新版本而最新版本的 LangChain0.3.x 之后把很多底层依赖拆分到了不同的子包中比如langchain-community、langchain-chroma导致代码里from langchain.vectorstores import Chroma直接报错。我的建议是装指定版本并且按照依赖关系分开装pip install langchain0.2.14 pip install langchain-community0.2.12 pip install langchain-chroma0.1.3 pip install chromadb0.5.5 pip install ollama这里简单解释一下为什么装langchain-chroma这个子包。0.2 版本之后的 LangChain 把向量数据库的集成从主包里拆出来了单独作为一个依赖包维护。如果你直接装最新版的chromadb配合最新版的langchain在导入时经常会碰到 API 签名对不上的问题。固定版本虽然看起来不潮流但对于一个要稳定跑起来的项目来说锁定版本永远是第一位的。等模型和代码都跑通了再去升版本也不迟。到这里开发环境就已经准备好了。我习惯先做一次冒烟测试写几行简单脚本确认每个组件都能正常调用import ollama response ollama.chat( modelqwen2.5:7b, messages[{role: user, content: 你好做一个自我介绍}] ) print(response[message][content])如果终端能正常输出模型的回复说明 Python、Ollama、模型这三层链路已经打通了。3. 第一个多轮对话版本从无状态到有记忆3.1 无状态对话的局限客服系统的核心交互形式是多轮对话。但很多人起步时写的第一版 QA 代码是无状态的也就是每次请求都是独立的不带任何历史信息from langchain_community.chat_models import ChatOllama llm ChatOllama(modelqwen2.5:7b) response llm.invoke(我今天买了一个电子产品出了问题需要退货) print(response.content)这种实现跑起来很简单但用户体验很差。用户接着问“怎么申请退货流程”时模型没有前文信息只能靠自己的常识回答可能完全不记得用户前面说了“电子产品出了问题”。要让机器人表现得像个真人客服必须把对话历史传给模型。3.2 用 LangChain 管理对话历史LangChain 提供的做法是把“对话历史存储”和“模型调用”组合在一起。核心思路是用ChatMessageHistory对象保存某个用户会话的消息列表每次调用模型之前把历史消息和当前问题拼成消息组调用模型返回答案后把新的一问一答追加到历史列表里。这里的会话隔离很重要。多个用户同时在线聊天时不能所有用户共享同一份历史那就串戏了。所以还需要一个 HashMap或者数据库表来按 session ID 存储不同的ChatMessageHistory实例。我画一张简化的流程图帮大家理解这个流程——用户带着 session_id 发来问题系统拿出这个 session 对应的聊天记录连同本次问题一起打包发给大模型模型返回答案后再更新聊天记录。注意这里所有收发都通过 LangChain 的接口完成所以代码本身不依赖具体某个模型。3.3 最小可行性代码实现下面是一份用 LangChain Ollama 实现的最简多轮对话代码你可以直接复制运行看看效果。from langchain_community.chat_models import ChatOllama from langchain.memory import ChatMessageHistory from langchain.schema import HumanMessage, AIMessage # 1. 初始化本地大模型 llm ChatOllama( modelqwen2.5:7b, temperature0.7, num_predict2048, ) # 2. 用字典保存不同 session 的聊天记录 sessions {} def get_session_history(session_id: str) - ChatMessageHistory: if session_id not in sessions: sessions[session_id] ChatMessageHistory() return sessions[session_id] def chat(session_id: str, user_input: str) - str: history get_session_history(session_id) # 3. 构造完整消息列表先历史后当前 messages history.messages [HumanMessage(contentuser_input)] # 4. 调用模型 ai_response llm.invoke(messages) # 5. 更新历史 history.add_user_message(user_input) history.add_ai_message(ai_response.content) return ai_response.content # 测试模拟同一个用户连续提问 print(chat(user_001, 我想退货怎么操作)) print(chat(user_001, 需要什么条件吗)) print(chat(user_002, 我要开发票))注意第二步和第五步的设计history.add_user_message和add_ai_message是在模型调用结束后才执行的。如果在调用前就把当前问题加进 history再结合第三步的history.messages [HumanMessage(contentuser_input)]就会造成当前问题出现两次模型就会懵。这个顺序问题是我最早踩过的坑之一建议大家写的时候特别注意。另外需要注意这段代码把所有聊天记录放在内存字典里服务重启之后历史就丢了。对于生产环境可以改成把聊天记录存到 Redis 或者数据库但核心逻辑完全一样。我做客服系统的第一版就是这么跑的先验证业务逻辑再考虑持久化。3.4 关于上下文长度的取舍把整段历史一股脑全传给模型短暂使用没有问题但聊得久了历史消息数量会越来越大。大模型的上下文窗口Context Window是有限的而且输入越长的 Token 数量推理耗时和费用也越高本地部署主要是耗时。所以必须对历史做截断或摘要。我采用的策略是只保留最近 N 轮对话。比如只取最近的 6 轮12 条消息超过的部分全部丢弃。实现也很简单MAX_TURNS 6 def trim_history(history: ChatMessageHistory): messages history.messages if len(messages) MAX_TURNS * 2: history.messages messages[-MAX_TURNS * 2:]在chat函数最开始调用一下trim_history(history)就可以了。如果要更精细地控制还可以按 Token 数而不是消息条数来裁剪这个后面聊到 Chroma 的时候再展开。对于最简单的客服场景按轮数截断已经足够用了。4. 接入 Chroma让机器人学会查资料4.1 什么是 Embedding为什么要向量化到目前为止机器人已经能记住上下文了但它回答问题时依然只能靠“脑袋里的知识”。如果用户问的是你们公司的退换货政策、产品使用说明模型肯定不知道因为这些知识不在它的训练数据里。这时候就需要把公司的知识库喂给模型。直接喂全文是行不通的模型上下文放不下。所以通常的做法是把知识库文档切成很多小段几百字一段然后用 Embedding 模型把每一段变成一个向量。通俗来说Embedding 就是“用一串数字表示一段文字的意思”。意思相近的两段话向量之间的距离比如余弦相似度也会比较近。用户来提问的时候系统先把用户的问题转成向量再到 Chroma 里查找和这个向量最接近的前 K 个文档片段。找到之后把这些片段作为“参考资料”和用户问题一起交给大模型。模型可以根据参考资料给出贴近事实的回答而不是漫无边际地编造。这就是 RAG 的基本思路。4.2 用 Chroma 构建知识库索引Chroma 在 LangChain 里的使用方式非常友好。下面演示一个完整流程先创建集合再把一批文档添加进去。我假设你的知识库在docs/目录下每个文件是一个 Markdown 或 TXT 文档。from langchain_community.embeddings import OllamaEmbeddings from langchain_community.vectorstores import Chroma from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain_community.document_loaders import DirectoryLoader # 1. 加载文档 loader DirectoryLoader(docs/, glob**/*.md) documents loader.load() # 2. 切分文档 text_splitter RecursiveCharacterTextSplitter( chunk_size500, chunk_overlap50, ) splits text_splitter.split_documents(documents) # 3. 初始化 Embedding 模型 embeddings OllamaEmbeddings(modelqwen2.5:7b) # 4. 构建向量库并持久化 vectorstore Chroma.from_documents( documentssplits, embeddingembeddings, persist_directory./chroma_db, )这段代码里有三个关键参数值得展开讲一下。第一个是chunk_size500也就是每段文本控制在 500 个字符左右。这个数值不是随便定的太小了会导致语义不完整太大了又会超出模型上下文窗口。我实测过在客服文档场景下500 到 800 字是一个比较合适的区间既能保持语义完整也能保证单次拼接进 Prompt 的 Token 数不会太多。第二个是chunk_overlap50表示相邻两个片段之间重叠 50 个字符。这是为了避免一个完整句子恰好被拦腰切断。比如“产品保修期为一年一年内出现非人为损坏可免费维修”如果被切成了“产品保修期为一年一年内出现”和“非人为损坏可免费维修”后一段单独拿出来检索时含义就不完整了。加一点重叠能有效降低这种问题。第三个是persist_directory./chroma_db指定数据库落盘目录。首次执行这段代码后向量库会持久化到磁盘下次启动不需要重新加载和 Embedding 一遍直接Chroma(persist_directory./chroma_db, embedding_functionembeddings)就能加载。注意LangChain 0.2.x 版本中Chroma.from_documents默认会持久化但建议显式传入persist_directory参数避免不同版本行为不一致导致数据丢失。另外Embedding 模型与提问时使用的模型推荐保持一致否则向量空间不一致检索效果会大打折扣。4.3 把检索结果拼接到对话流程里有了向量库之后多轮对话的核心逻辑就要升级了。用户发来消息时系统先做以下几步在 Chroma 里搜索与用户问题最相关的 3~5 个文档片段把这些片段拼接成一个“参考资料”字符串拼装 Prompt告诉模型“以下是从知识库中检索到的内容请基于这些信息回答用户问题”携带历史消息一起调用模型。这里有一个很关键的工程点检索的时候应该用当前这一轮的用户问题去检索而不是把历史消息也拼进去。原因是用户当前的问题往往是检索意图最明确的表述历史消息里的信息可能很零散混在一起反而降低检索精度。比如用户之前抱怨了半天物流慢当前这句“怎么退货”才是核心诉求。拼装 Prompt 的代码示例如下def build_prompt(question: str, retrieved_docs): context \n\n.join([doc.page_content for doc in retrieved_docs]) prompt f你是一名专业的客服助理。请根据以下知识库内容回答用户问题。 【知识库内容】 {context} 【用户的当前问题】 {question} 请用友好、简洁的语言回答。如果知识库中没有相关信息请如实说明不要编造。 return prompt至于如何做相似度检索LangChain 封装得比较好了retriever vectorstore.as_retriever(search_kwargs{k: 3}) docs retriever.invoke(user_input) prompt build_prompt(user_input, docs) full_messages history.messages [HumanMessage(contentprompt)]这样整个客服系统的信息链路就完整了知识库 → Chroma 检索 → 历史对话 → Prompt 组装 → Ollama 模型推理 → 返回答案 → 更新历史。用户问的问题系统能结合自己知识库里“私有”的资料来回答而且能记住多轮上下文。4.4 Chroma 以外的向量数据库什么时候考虑不少读者可能会问网上关于 Milvus、Qdrant 的讨论也很多我用 Chroma 是不是不够“先进”我理解这种疑虑但实际选型要看场景。如果只是做一个中小型客服系统知识库文档量在几万段以内并发查询量不高Chroma 完全够用而且部署简单到几乎没有成本。但如果你要做的是大规模知识库搜索比如千万级文档、高并发查询或者需要水平扩展、分布式部署那确实应该考虑 Qdrant 或 Milvus。Qdrant 的 Rust 底层性能非常强Milvus 在 GPU 加速、多副本方面做得比较深入。我的建议是先把 Chroma 和整套系统跑通把业务逻辑验证好。如果未来遇到性能瓶颈再把存储层从 Chroma 替换为 Qdrant因为上层 LangChain 的接口是统一的替换成本主要在数据迁移上代码逻辑几乎不用改。5. 常见问题与排查技巧实录5.1 Ollama 模型下载失败或速度慢这个问题太常见了。如果你执行ollama pull时一直卡住或者报连接超时首先看看模型存储目录是否空间不足用ollama list查看当前占用。其次检查本地网络到默认仓库的连接状况确实不稳定的情况下可以考虑使用国内社区提供的镜像源配置方式在ollama serve的文档里有或者从第三方下载模型文件后离线导入。这里补充一个离线导入的具体流程因为我认为这条路径最稳定。在公开模型社区找到对应模型的 GGUF 格式文件下载到本地写一个Modelfile内容大致为FROM ./qwen2.5-7b-instruct-q4_k_m.gguf执行ollama create qwen2.5 -f Modelfile等待导入完成执行ollama list确认模型已就绪。这个方式避开了在线下载的不稳定因素而且只要文件完整导入基本不会失败。提示模型文件动辄几个 GB下载时要留意磁盘剩余空间。另外量化等级 Q4_K_M 是性价比比较高的选择模型体积小、损失少。5.2 LangChain 导入报错“Cannot import name Chroma”这个报错在 0.2.x 版本比较常见原因是向量存储的包被拆分到了langchain-chroma。解决方法是先确认安装的是哪个版本pip show langchain-chroma如果没装执行pip install langchain-chroma0.1.3。导入语句也改成from langchain_chroma import Chroma而不是from langchain.vectorstores import Chroma。这是 LangChain 逐步模块化的必然结果以后可能有更多组件会被拆出来记住一个原则遇到导入报错时先查对应子包是否已安装再看版本兼容性。5.3 向量库检索结果不相关这个问题通常出在 Embedding 模型和数据切分方式上。如果你用的 Embedding 模型和问答模型是同一个 Ollama 上的模型但该模型不支持优质的中文语义表示检索效果会打折。建议换用专门的 Embedding 模型比如nomic-embed-text或bge-m3在 Ollama 上都能直接拉取。chunk_size设置不合理会导致检索片段太碎或太笼统。可以尝试把 500 改成 300 和 800 各测一轮用几组典型问题做对比看返回的文档片段是否包含真正的答案。如果所有检索结果都差不多可能是知识库本身的内容质量不高或者每段文本之间区分度低。客服场景的文档往往口语化和重复内容较多建议清洗一遍数据再建库。5.4 多轮对话中上下文混淆多轮对话最容易出现的问题是模型搞混了“历史里的用户”和“当前提问的用户”。检查点有四个是否每次会话传入的session_id稳定不变消息历史是否使用了ChatMessageHistory而不是普通 list模型调用时消息列表的顺序是否为“先历史后当前”是否出现了历史消息里用户曾经问过的问题被当成当前问题重复处理。我在一次调试中还发现如果服务端开了多线程并发处理同一个 session 的请求会存在轻微的竞态问题导致消息顺序错乱。解决办法是在内存字典的读写操作上加锁或者把 session 状态放到具备原子操作的 Redis 中。客服系统并发量通常不会特别大但提前考虑到这一点能省去后续很多麻烦。6. 系统优化的几个方向第一版跑通之后我强烈建议按下面的顺序逐步优化。第一接入更专业的 Embedding 模型。客服场景下语义相似度的准确性直接影响检索质量。我在实测中把qwen2.5:7b作为 Embedding 模型切换到bge-m3后检索相关性有明显提升而且bge-m3的推理速度更快占用更小。第二增加知识库的热更新能力。现在代码是启动时一次性加载所有文档。真实场景中产品政策经常变动总不能每次更新文档都重启服务。可以考虑把“新增文档 → 切分 → Embedding → 写入 Chroma”的流程做成一个独立的接口运营同学更新完文档后调用一下就能完成增量更新。Chroma 的add_documents方法天然支持增量写入核心代码并不复杂。第三对 Prompt 做更精细的设计。客服回答的语气、长度、是否允许转人工这些业务约束都应该体现在 Prompt 里。更高级的做法是用LangChain的PromptTemplate把系统人设、知识库上下文、历史对话、用户问题四个部分明确区分开并给每个部分不同的 System 和 User 角色标识。模型对角色区分越清楚越不容易“跑偏”。第四评估并决定是否引入 LangGraph。LangChain 本身已经支持基本的多轮对话和历史管理但如果你需要构建更复杂的客服流程比如多步骤意图识别、工具调用查订单状态、转接人工、条件分支等LangGraph 的状态图机制会更合适。它把对话流程建模为一个有向图每个节点是一个处理逻辑边是状态转移条件非常贴合“可配置、可观测”这个需求。我在我的项目里暂时没上 LangGraph因为当前场景用简单的链条就能解决。但如果你预见到流程复杂度会快速上升尽早了解 LangGraph 不是坏事。在我自己把这条链路完整跑通之前说实话我对“本地大模型能不能做客服机器人”是持怀疑态度的。但实际用下来Python Ollama Chroma LangChain 这套组合的配合比我想象中更顺畅。尤其是 Ollama 把本地模型调用简化成了几行代码Chroma 把知识库存储和检索封装成了现成接口LangChain 把模型切换和使用体验统一之后整个开发过程的核心难点就从“不会调 API”转移到了“如何设计一个好的 Prompt”和“如何整理知识库内容”上。最后再分享一个小技巧做知识库相关开发时准备一组覆盖核心业务场景的测试问题清单每次调整切分参数、更换模型或者修改 Prompt 之后都用同一组问题跑一遍回归测试人工判断回答质量。这样看起来传统但比什么自动化评估都好使能帮你快速感知到某个改动到底是变好了还是变差了。我在开发这套客服系统时这个习惯帮我少走了很多弯路。
返回列表