news 2026/6/7 5:04:06

LangChain实战:从零搭建可落地的RAG应用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
LangChain实战:从零搭建可落地的RAG应用

1. 这不是又一篇“LLM框架科普”,而是一份能让你今天就跑通第一个智能体的实操手记

LangChain 这个词,过去两年在技术社区里被反复咀嚼、拆解、包装,最后塞进各种“5分钟上手”“保姆级教程”的标题里。但现实是,绝大多数初学者点开那些文章,看到from langchain.llms import OpenAI就卡住了——不是因为代码难,而是根本不知道这行代码背后在调度什么、为什么非得这么写、如果换本地模型该怎么改、提示词写崩了到底错在哪一层。我带过二十多个从零开始做 LLM 应用的团队,90% 的人第一周都在和LLMChain的输入输出结构、DocumentLoader的分块逻辑、RetrievalQA的链路断点死磕。这不是能力问题,是信息断层:官方文档讲的是“它能做什么”,而真实项目要解决的是“它为什么在这里卡住”。这篇笔记不讲抽象概念,不画架构图,只还原一个完整闭环——从你本地装好 Python 环境开始,到最终跑出一个能读你 PDF 报告、准确回答“第三页提到的预算调整幅度是多少?”的可执行程序。核心关键词全部落地:LangChain、LLM 应用开发、RAG 实现、提示工程、向量数据库、Chain 编排、本地大模型接入。适合三类人直接抄作业:刚学完 Python 基础想碰 AI 的开发者;业务部门需要快速验证智能客服/知识库原型的产品经理;以及被老板催着“两周内上线一个能查内部文档的聊天框”的技术负责人。下面所有步骤,我都用 macOS M2 芯片笔记本实测过,Windows 用户只需把pip install换成pip3 install,Linux 用户注意关闭 SELinux 权限限制,其余完全一致。

2. 为什么必须绕开“先学原理再动手”的陷阱?LangChain 的设计本质是“胶水层”而非“引擎”

2.1 别被“Chain”这个词骗了:它不是流程编排器,而是错误隔离器

很多人第一次看 LangChain 文档,会被SequentialChainRouterChain这些名词吓住,以为要先搞懂“链式调用”的函数式编程范式。其实完全相反——LangChain 的核心价值,恰恰在于它主动放弃对底层模型调用的精细控制,转而用预设的错误处理边界来降低调试成本。举个最典型的例子:当你用原生openai.ChatCompletion.create()调用 GPT-4,如果提示词里混入了未转义的{字符,API 直接返回 400 错误,你得翻日志、查文档、手动拼接字符串去定位;而 LangChain 的PromptTemplate类会在format()阶段就抛出KeyError,明确告诉你“你传入的变量字典里缺了context这个 key”。这不是功能增强,是把运行时错误提前到开发时捕获。我统计过团队里 137 个失败的 LangChain 项目,82% 的问题出在input_variables和实际传入参数不匹配,而 LangChain 的模板校验机制让这类问题平均排查时间从 47 分钟缩短到 6 分钟。所以别纠结“Chain 是什么”,先记住:每一个 Chain 类型,本质上都对应一种常见错误场景的封装LLMChain封装的是“提示词与模型交互”的错误边界,RetrievalQA封装的是“检索结果与问答逻辑耦合”的错误边界,SQLDatabaseChain封装的是“自然语言转 SQL 的语法容错”边界。理解这点,你就能跳过 70% 的源码阅读。

2.2 向量数据库不是可选项,而是 LangChain 的“呼吸系统”

新手常问:“我能不能不用 Chroma 或 FAISS,直接用列表存文本?”答案是:可以跑通 demo,但必然在第二周崩溃。原因在于 LangChain 的RetrievalQA链路默认依赖向量相似度计算,而这个计算过程有三个硬性要求:

  1. 实时性:用户提问后,必须在 800ms 内完成从千万级文档中召回 Top-3 相关片段(这是行业公认的响应延迟阈值);
  2. 一致性:同一段文本,无论经过多少次split_documents()分块、embed_documents()编码,生成的向量必须完全一致;
  3. 可解释性:当召回结果错误时,你需要能反向追踪“为什么这段文字被判定为相关”,这就要求向量空间具备线性可分性。

普通列表或 SQLite 全文搜索完全无法满足这三点。以我实测的某金融报告数据集为例:用 SQLite 的MATCH查询 10 万条记录平均耗时 2.3 秒,且无法解释“为什么‘流动性风险’这个词会匹配到‘资本充足率’段落”;而 Chroma 在 M2 MacBook 上加载相同数据集后,单次查询稳定在 320ms,且通过.get(where={"source": "report_q3.pdf"})可直接定位原始文档来源。更关键的是,Chroma 的collection.add()方法强制要求传入ids参数——这看似多此一举,实则是为后续的“向量-文档映射一致性”埋下伏笔。很多团队踩坑就是因为跳过这步,导致retriever.get_relevant_documents("预算调整")返回的文档 ID 和原始 PDF 页码对不上,最后花三天时间重跑 embedding。所以请牢牢记住:LangChain 的 RAG 流程里,向量数据库不是存储组件,而是整个应用的“状态同步中枢”。它确保了从文档切分、向量化、检索、到最终答案生成,所有环节操作的都是同一套 ID 映射体系。

2.3 提示工程在 LangChain 里不是“写文案”,而是“定义接口契约”

传统认知里,提示词(Prompt)是给模型“下指令”的文本。但在 LangChain 中,PromptTemplate的真正作用是在 LLM 输入层建立强类型契约。看这个真实案例:某医疗 SaaS 团队要用 LangChain 构建患者咨询助手,原始提示词是:

“你是一个医生,请根据以下病历回答问题:{context}。问题:{question}”

他们发现模型经常忽略{context}里的关键检查项,比如把“肌酐值 180μmol/L”误判为正常。后来我把提示词改成:

prompt = PromptTemplate( input_variables=["context", "question"], template="你是一名三甲医院肾内科主治医师。请严格按以下格式回答:\n【诊断依据】{context}\n【回答】<仅基于上述依据作答,禁止编造>\n问题:{question}" )

效果立竿见影。区别在哪?不是语气更专业,而是通过【诊断依据】和【回答】这两个强标记,把非结构化文本变成了结构化输入接口。LangChain 的LLMChain在调用时,会自动将context变量内容注入到【诊断依据】标签下,而模型在训练时已见过大量类似标记的医疗问答数据,天然倾向遵循该格式。这揭示了一个关键事实:LangChain 的提示模板,本质是给 LLM 构建一个“可控的微调环境”。它不改变模型权重,但通过格式约束,让模型在固定语义空间内工作。所以别再纠结“怎么写提示词”,先问自己:“我要让模型输出的结构,能否用两个英文方括号【】清晰界定?这个界定是否和业务系统的字段名完全一致?”——这才是 LangChain 提示工程的第一性原理。

3. 从零搭建一个真实可用的 RAG 应用:不跳过任何一个“坑位”的全流程

3.1 环境准备:为什么必须用 conda 而不是 pip?M1/M2 芯片的隐藏陷阱

很多教程直接写pip install langchain,结果用户在 Apple Silicon Mac 上安装llama-cpp-python时卡死在building wheel for llama-cpp-python。这不是网络问题,是编译器链不兼容。正确姿势是:

# 1. 创建独立环境(避免污染全局Python) conda create -n langchain-dev python=3.10 conda activate langchain-dev # 2. 强制指定 arm64 架构编译(M1/M2 必须!) arch -arm64 conda install -c conda-forge llama-cpp-python # 3. 安装 LangChain 及其向量数据库依赖 pip install langchain chromadb tiktoken unstructured PyPDF2

关键点解析:

  • 为什么用 condallama-cpp-python依赖libomp并行计算库,conda 的conda-forge渠道已预编译适配 arm64 的二进制包,而 pip 默认下载 x86_64 版本,需本地编译(M2 芯片编译耗时超 22 分钟且大概率失败);
  • 为什么arch -arm64:Apple Silicon 的 Rosetta 2 转译层对 OpenMP 支持不完善,强制指定架构可绕过转译,实测启动速度提升 3.7 倍;
  • unstructured必装原因:它比PyPDF2多支持 27 种文档格式(含扫描版 PDF 的 OCR),且partition_pdf()方法自动识别表格区域,这对处理财报、合同等结构化文档至关重要。

提示:如果你用 Windows,把conda换成miniconda,并在安装llama-cpp-python前执行set USE_CUDA=0禁用 CUDA 编译,否则会因找不到nvcc编译器报错。

3.2 文档加载与切分:别迷信“chunk_size=512”,你的 PDF 页边距决定一切

加载 PDF 不是loader.load()一行代码就完事。我测试过 127 份不同来源的 PDF(财报、白皮书、内部制度),发现PyPDF2加载时有三大致命缺陷:

  1. 页眉页脚污染:自动提取的文本包含“第 3 页 共 12 页”等页码信息,导致 embedding 向量偏离主题;
  2. 表格断裂:跨页表格被切成两段,"2023年营收|2024年预测"变成"2023年营收""2024年预测"两个孤立短语;
  3. 字体编码丢失:中文 PDF 的 CID 编码未正确映射,出现 `` 符号。

解决方案是用unstructured替代:

from unstructured.partition.pdf import partition_pdf from langchain.text_splitter import RecursiveCharacterTextSplitter # 关键参数:strategy="hi_res" 启用 OCR,languages=["chi_sim"] 支持简体中文 elements = partition_pdf( filename="annual_report.pdf", strategy="hi_res", languages=["chi_sim"], infer_table_structure=True, # 自动识别表格边界 include_page_breaks=True # 保留页码标记,便于后续溯源 ) # 文本切分不是按字符数,而是按语义块 text_splitter = RecursiveCharacterTextSplitter( chunk_size=800, # 注意:这里不是 token 数,是字符数! chunk_overlap=100, # 重叠区必须覆盖句子主干,避免切碎长句 separators=["\n\n", "\n", "。", "!", "?", ";", ","] # 中文优先按标点切分 )

为什么chunk_size=800?因为实测发现:中文文档平均每 100 字构成一个完整语义单元(如“Q3 净利润同比增长 12.3%,主要受益于新客户拓展”),800 字刚好覆盖 3-5 个完整句子,既保证上下文连贯,又避免单块过大导致 embedding 失真。而chunk_overlap=100不是随便写的——它必须大于中文平均句长(实测 42 字),才能确保“同比增长 12.3%”这样的关键数据不被切到两块里。我在某券商的研报处理中,把 overlap 从 50 改到 100 后,问答准确率从 63% 提升到 89%。

3.3 向量化与存储:Chroma 的 collection 名称不是随便起的,它决定你的调试效率

创建向量数据库时,90% 的新手会写:

from langchain.vectorstores import Chroma db = Chroma.from_documents(documents, embedding_model)

这会导致两个严重后果:

  1. 无法复现问题:每次运行都生成随机 collection 名,你昨天调试好的检索逻辑,今天重启后 collection 已变,根本无法对比结果;
  2. 生产环境灾难:没有显式指定persist_directory,数据库存在内存里,程序一退出数据全丢。

正确写法:

import os from langchain.vectorstores import Chroma # 强制指定 collection 名和持久化路径 PERSIST_DIR = "./chroma_db" os.makedirs(PERSIST_DIR, exist_ok=True) db = Chroma( collection_name="finance_reports_q3", # 业务含义明确! embedding_function=embedding_model, persist_directory=PERSIST_DIR ) db.add_documents(documents) # 注意:不是 from_documents() db.persist() # 必须显式调用,否则不写入磁盘

collection_name的命名规则必须包含:业务域+数据源+时间范围。比如hr_policies_2024product_manual_v2.3。这样做的好处是:当你发现finance_reports_q3的召回结果不准,可以直接rm -rf ./chroma_db/finance_reports_q3删除该集合重跑,不影响其他业务线数据。另外,add_documents()from_documents()多一个关键能力:它返回document_ids列表,你可以用这些 ID 做精准删除或更新——这是生产环境必备的运维能力。

3.4 检索器配置:search_kwargs里的k=3不是魔法数字,它和你的提示词长度强绑定

RetrievalQAretriever参数常被简单设置为db.as_retriever(search_kwargs={"k": 3})。但k=3的选择逻辑,直接决定最终答案质量。我们来算一笔账:

  • 假设你的提示词模板长度为 420 tokens(含 system prompt + few-shot examples);
  • 模型最大上下文为 4096 tokens(如 Llama-2-13B);
  • 那么留给context的 tokens 空间最多为4096 - 420 = 3676
  • 如果每块文本平均 280 tokens,则最多能塞入3676 / 280 ≈ 13块;
  • k=13会导致检索结果过多,噪声增大,模型容易混淆重点。

所以工业级实践是:k值 =max_context_tokens / (avg_chunk_tokens * 1.5)。其中1.5是冗余系数,用于应对长句溢出。按上面例子:3676 / (280 * 1.5) ≈ 8.7 → k=8。但还要叠加业务规则:

  • 对财务数据类问答,k必须 ≤5(避免不同年份数据混淆);
  • 对法律条款类问答,k必须 ≥7(条款常分散在多个章节)。

因此最终代码应为:

retriever = db.as_retriever( search_type="similarity_score_threshold", # 启用分数阈值过滤 search_kwargs={ "k": 5, "score_threshold": 0.35 # 实测:低于 0.35 的相似度基本不可信 } )

score_threshold=0.35是关键——它把k=5变成动态值。如果检索出的 5 块文本里,只有 2 块分数 >0.35,那retriever只返回这 2 块,避免低质 context 污染答案。我在处理某银行合规文档时,开启该阈值后,幻觉率下降 41%。

3.5 链式调用实现:RetrievalQA.from_chain_type()的四个必填参数,每个都藏着业务逻辑

RetrievalQA.from_chain_type()看似简单,但四个参数全是业务决策点:

qa_chain = RetrievalQA.from_chain_type( llm=llm, # 1. 模型选择:不是“哪个快”,而是“哪个符合业务安全策略” chain_type="stuff", # 2. chain_type:决定 context 如何喂给模型 retriever=retriever, # 3. 检索器:已配置好 score_threshold return_source_documents=True, # 4. 是否返回溯源:影响前端展示逻辑 chain_type_kwargs={"prompt": prompt} # 5. 提示词:必须和 retriever 的 k 值匹配 )

逐个拆解:

  1. llm参数:如果你用OpenAI(model_name="gpt-3.5-turbo"),必须确认公司允许外传数据;若用本地LlamaCpp(model_path="llama-2-13b.Q4_K_M.gguf"),则需在初始化时加n_gpu_layers=1(M2 芯片最多用 1 层 GPU 加速,多设反而降速);
  2. chain_type选型stuff是最常用,把所有 context 拼成一段喂给模型;map_reduce适合长文档总结,但会增加 300ms 延迟;refine适合多轮追问,但首次响应慢;新手无脑选stuff
  3. return_source_documents=True:这个布尔值决定前端能否显示“答案来自第 3 页”,对金融、法律类应用是刚需,否则用户无法验证答案可信度;
  4. chain_type_kwargs:这里的prompt必须和retriever.k匹配。如果k=5,你的提示词模板里context变量就要预留 5 个插槽,比如:
    【参考材料1】{context1} 【参考材料2】{context2} ... 【参考材料5】{context5}
    否则LLMChain会因变量名不匹配直接报错。

注意:from_chain_type()返回的对象是BaseRetrievalQA,它有个隐藏方法qa_chain.combine_documents_chain.llm_chain.prompt.input_variables,可以实时查看当前提示词需要哪些变量——这是调试时最常用的自查手段。

4. 生产环境避坑指南:那些官方文档绝不会告诉你的 7 个血泪教训

4.1 Embedding 模型不是越贵越好:BGE-M3 和 text-embedding-3-large 的实测对比

很多团队一上来就买 OpenAI 的text-embedding-3-large($0.13/1M tokens),结果发现中文问答准确率还不如免费的BGE-M3。原因在于:

  • text-embedding-3-large是通用模型,在中文金融术语(如“永续债”“商誉减值”)上的向量距离拉不开;
  • BGE-M3是专为多语言优化的开源模型,对中文长尾词 embedding 效果提升 2.3 倍。

我用某上市公司的 2023 年报做测试:

检索问题BGE-M3 准确率text-embedding-3-large 准确率
“2023年研发投入占营收比例”92.4%76.1%
“应收账款周转天数变化趋势”88.7%63.5%
“海外子公司数量及分布”95.2%81.3%

关键结论:中文场景下,优先用BAAI/bge-m3(HuggingFace 模型 ID),它支持 1024 维向量,且query_instruction_for_retrieval参数可定制为“请作为财务分析师检索:”,这比通用 embedding 提升 17% 召回精度。部署时只需:

from langchain.embeddings import HuggingFaceEmbeddings embeddings = HuggingFaceEmbeddings( model_name="BAAI/bge-m3", model_kwargs={'device': 'cpu'}, # M2 芯片用 CPU 更稳 encode_kwargs={'normalize_embeddings': True} )

提示:normalize_embeddings=True必须开启,否则向量模长不一致,Chroma 的余弦相似度计算会失真。

4.2 本地大模型的n_ctx参数不是越大越好:M2 芯片的物理内存墙

LlamaCpp加载llama-2-13b.Q4_K_M.gguf时,很多人设n_ctx=4096,结果程序直接 OOM(内存溢出)。这是因为:

  • n_ctx=4096表示模型最多处理 4096 tokens 的上下文;
  • 但 M2 MacBook Pro 16GB 内存中,约 4.2GB 被 macOS 系统占用;
  • llama-2-13b量化后仍需 7.8GB 内存,加上 Python 进程、Chroma 数据库,总需求超 13GB;
  • n_ctx设为 4096 时,模型会预分配全部 KV Cache 内存(约 2.1GB),瞬间压垮内存。

实测安全值:

模型尺寸M2 8GB 内存M2 16GB 内存M2 32GB 内存
7B Q4_K_Mn_ctx=2048n_ctx=3072n_ctx=4096
13B Q4_K_Mn_ctx=1024n_ctx=2048n_ctx=3072

所以正确初始化是:

from langchain.llms import LlamaCpp llm = LlamaCpp( model_path="./models/llama-2-13b.Q4_K_M.gguf", n_ctx=2048, # M2 16GB 的黄金值 n_threads=6, # M2 CPU 有 8 核,留 2 核给系统 n_gpu_layers=1, # 仅启用 1 层 GPU 加速 verbose=False # 关闭日志,否则每 token 打一行,拖慢速度 )

verbose=False是关键——开启后,每生成一个 token 就打印一次 debug 日志,实测让响应速度下降 40%。

4.3 提示词里的system_message不是摆设:它决定模型的“人格基线”

ChatOpenAILlamaCppsystem_message参数常被忽略,但它实际控制模型的底层行为模式。比如:

  • system_message="You are a helpful assistant."→ 模型倾向补充信息,可能编造不存在的财报数据;
  • system_message="You are a financial analyst. Answer only with facts from the provided context. If no context supports the answer, say 'Not found in documents'."→ 模型严格遵循事实,幻觉率下降 68%。

更狠的技巧:在system_message里嵌入格式约束。例如:

system_message = """You are a compliance officer at a bank. Answer questions ONLY in this format: [CONFIDENCE: 0-100] [ANSWER: your answer here] [PAGE: page number from source document] If the question cannot be answered from the context, set CONFIDENCE to 0 and ANSWER to 'Insufficient data'. """

这样做的好处是:前端可以直接用正则r"\[CONFIDENCE: (\d+)\]"提取置信度,动态决定是否显示“答案可能不准确”的提示。我在某支付机构的风控知识库中,用此方案将用户投诉率降低了 53%。

4.4 Chroma 的where过滤不是 SQL:它只支持基础条件,复杂查询必须预处理

db.similarity_search("预算调整", where={"year": "2023"})看似强大,但 Chroma 的where过滤器只支持:

  • 等值匹配({"status": "active"});
  • 数值比较({"page": {"$gte": 5}});
  • 字符串包含({"content": {"$contains": "风险"}});

不支持AND/OR逻辑、正则表达式、模糊匹配。所以当你要查“2023 年 Q3 的预算调整”,不能写where={"year": "2023", "quarter": "Q3"}(Chroma 会报错),而必须:

  1. 先用db.get(where={"year": "2023"})拿到所有 2023 年文档 ID;
  2. 再用db.get(ids=ids_2023)加载这些文档;
  3. 在内存里用 Python 筛选doc.metadata["quarter"] == "Q3"

虽然多一步,但这是唯一可靠方式。我建议把这种预处理逻辑封装成FilteredRetriever类:

class FilteredRetriever: def __init__(self, vectorstore, filters): self.vectorstore = vectorstore self.filters = filters # {"year": "2023", "doc_type": "report"} def get_relevant_documents(self, query): # Step 1: 粗筛 ids = self.vectorstore.get(where=self.filters)["ids"] # Step 2: 精排 docs = self.vectorstore.get(ids=ids) # Step 3: 用 embedding 重排序(可选) return self._rerank_by_similarity(docs, query)

4.5 LangChain 的CallbackHandler不是日志工具,而是性能诊断仪

StreamingStdOutCallbackHandler常被当作“让回答逐字显示”的玩具,但它真正的价值是定位性能瓶颈。比如:

from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler handler = StreamingStdOutCallbackHandler() # 开启详细回调 qa_chain = RetrievalQA.from_chain_type( llm=llm, chain_type="stuff", retriever=retriever, callbacks=[handler], # 关键! ... )

运行时你会看到:

> Entering new RetrievalQA chain... Loading chunk 1/5... [✓] Retrieving from vectorstore... [✓] (240ms) Formatting prompt... [✓] (12ms) Calling LLM... [✓] (1840ms) > Finished chain.

这些[✓]后的时间戳,就是各环节耗时。如果Calling LLM占 95% 时间,说明模型太重,该换小模型;如果Retrieving from vectorstore超 500ms,说明 Chroma 配置有问题(如没设score_threshold);如果Formatting prompt超 50ms,说明你的PromptTemplate里用了复杂jinja2逻辑,该简化。这才是CallbackHandler的正确打开方式。

4.6 生产环境必须禁用verbose=True:它会吃掉 30% 的吞吐量

verbose=True在调试时很有用,但上线后必须关掉。原因:

  • 每次LLMChain调用,verbose会触发print()输出 12 行 debug 信息;
  • print()是系统调用,涉及文件描述符锁,高并发下会成为性能瓶颈;
  • 实测:QPS 从 12 降到 8.4,下降 30%。

更隐蔽的坑是:verbose=True会强制LLMChain记录完整的promptresponse到内存,导致内存泄漏。某团队线上服务跑了 3 天后 OOM,最后发现是忘了关verbose。解决方案:

# 开发环境 llm = ChatOpenAI(verbose=True, temperature=0) # 生产环境(用环境变量控制) import os llm = ChatOpenAI( verbose=os.getenv("DEBUG_MODE", "false").lower() == "true", temperature=0 )

用环境变量开关,避免代码里硬编码。

4.7 最后一道防线:用OutputParser拦截模型幻觉,而不是靠人工审核

RetrievalQA返回的result["answer"]是纯文本,但业务系统需要结构化数据。很多人用正则提取,结果遇到“同比增长 12.3%”和“环比下降 5.7%”时,正则写崩溃。正确做法是用CommaSeparatedListOutputParser

from langchain.output_parsers import CommaSeparatedListOutputParser parser = CommaSeparatedListOutputParser() # 修改提示词,明确要求输出格式 prompt = PromptTemplate( input_variables=["context", "question"], template="你是一个财务分析师。请严格按以下格式回答:\n【数值】{context}\n【格式】用逗号分隔的纯数字,不要单位,不要文字\n问题:{question}" ) # 然后用 parser.parse(result["answer"]) 得到 ['12.3', '5.7']

但这还不够。终极方案是自定义OutputParser,在parse()方法里加入业务规则校验:

class FinancialOutputParser(BaseOutputParser): def parse(self, text: str) -> dict: try: # 提取所有数字 numbers = re.findall(r"-?\d+\.?\d*", text) if len(numbers) == 0: return {"error": "No numbers found", "raw": text} # 业务规则:财务数据必须在 -100 到 10000 之间 valid_nums = [float(n) for n in numbers if -100 <= float(n) <= 10000] return {"values": valid_nums, "raw": text} except Exception as e: return {"error": str(e), "raw": text} parser = FinancialOutputParser() result = parser.parse(qa_chain.run("2023年净利润增长率")) # result = {"values": [12.3], "raw": "同比增长 12.3%"}

这才是生产环境该有的健壮性。

5. 实战问题排查速查表:从报错信息反推根因的 12 个高频场景

报错信息(精简)根本原因30 秒定位法修复命令
KeyError: 'context'PromptTemplateinput_variablesformat()传入字典 key 不匹配prompt.input_variablesformat()参数名是否完全一致print(prompt.input_variables); print(list(kwargs.keys()))
ValueError: max_tokens must be < 4096LlamaCppn_ctx设太大,超出模型支持上限查模型文件名中的ctx标识(如llama-2-13b.Q4_K_M.gguf的 ctx=4096)n_ctx=min(4096, your_value)
ChromaError: Collection not foundChroma()初始化时collection_namepersist_directory不匹配进入./chroma_db目录,ls看实际 collection 名collection_name="your_actual_name"
ModuleNotFoundError: No module named 'llama_cpp'llama-cpp-python未正确安装(M1/M2 常见)运行python -c "import llama_cpp",报错则重装arch -arm64 pip install llama-cpp-python --no-cache-dir
IndexError: list index out of rangeretriever.get_relevant_documents()返回空列表,但代码假设有结果qa_chain前加docs = retriever.get_relevant_documents(query); print(len(docs))if len(docs)==0: return "No relevant documents"
UnicodeDecodeError: 'utf-8' codec can't decode bytePDF 文档含非 UTF-8 编码(如 GBK)file annual_report.pdf查编码,或改用unstructuredpip install unstructured
RuntimeError: The size of tensor a (2048) must match the size of tensor b (1024)embedding_model输出维度和 Chroma collection 维度不一致embedding_model.embed_query("test").shapedb._collection._embedding_function重建 Chroma DB,确保维度一致
ConnectionRefusedError: [Errno 61] Connection refusedChroma服务未启动(当用chromadb.Client()时)运行chroma run --path ./chroma_db启动服务改用Chroma(persist_directory=...)本地模式
`ValidationError: Input
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/7 4:58:28

深度学习-t-SNE

降维大杀器&#xff1a;如何用 t-SNE 把高维数据“拍”扁得既好看又好懂&#xff1f; 在数据科学的世界里&#xff0c;我们经常会遇到拥有几十甚至上百个特征&#xff08;维度&#xff09;的数据集。人类的大脑顶多能理解三维世界&#xff0c;面对百维数据&#xff0c;除了看表…

作者头像 李华
网站建设 2026/6/7 4:58:26

LISP递归

在 LISP&#xff08;以及 Scheme 等方言&#xff09;中&#xff0c;递归&#xff08;Recursion&#xff09; 拥有至高无上的地位。 因为经典 LISP 提倡纯粹的函数式编程风格&#xff0c;它没有专门的循环结构&#xff08;如 for 或 while&#xff09;。在 LISP 里&#xff0c;所…

作者头像 李华
网站建设 2026/6/7 4:56:14

Julia与Python数据处理性能实测:7类金融场景对比分析

1. 这不是“谁取代谁”的站队问题&#xff0c;而是数据工程师每天都在做的权衡“Can Julia replace Python?”——这个标题一出来&#xff0c;我就在好几个技术群看到有人立刻截图发问&#xff1a;“是不是以后不用学Python了&#xff1f;”“Julia真能干掉Python&#xff1f;…

作者头像 李华
网站建设 2026/6/7 4:53:55

LangGraph实战:构建具备ReAct与分层记忆的AI智能体工作流

1. 项目概述&#xff1a;这不是在搭积木&#xff0c;而是在给AI装上“思考回路”你有没有试过让大模型写一封客户投诉回复&#xff0c;结果它逻辑跳脱、前后矛盾&#xff0c;甚至自己编造出根本不存在的订单号&#xff1f;或者让它分析一份销售报表&#xff0c;它能准确提取数字…

作者头像 李华
网站建设 2026/6/7 4:53:53

高中数学教资资料推荐|科三知识点和模拟卷整理

高中数学教资资料推荐&#xff5c;科三知识点和模拟卷整理资料全科都有高中数学教资资料推荐&#xff5c;科三知识点模拟卷 PDFhttps://pan.quark.cn/s/39315a03df45 第 1 题 高中数学科三 学科知识深度一般&#xff08; &#xff09; A. 高于初中&#xff0c;含函数、导数、立…

作者头像 李华