LangChain 单元测试怎么写:Fake LLM、Mock 与录制回放
个人主页 for_ever_love__ 欢迎各位大佬莅临其他栏目: 大模型开发从0到1 其他栏目: iOS项目总结大全 其他栏目: 我想学python了 其他栏目: iOS UI 文章目录LangChain 单元测试怎么写Fake LLM、Mock 与录制回放一、测试策略分三层二、FakeListLLM按顺序返回预设答案三、FakeChatModel模拟对话模型四、Fake 的配套组件4.1 FakeEmbeddings4.2 FakeRetriever4.3 GenericFakeChatModel模拟流式五、怎么验证prompt 里有什么六、用 Mock 验证调用了几次七、录制回放一次性拿到真实响应八、什么该真跑九、一份 pytest 组织建议十、常见坑十一、小结LangChain 单元测试怎么写Fake LLM、Mock 与录制回放LLM 应用难测试输出不确定、调用要钱、还慢。于是很多人干脆不写测试改一行 prompt 全靠手动试。这篇讲怎么用Fake LLM把测试做成秒级、免费、可重复以及哪些该 mock、哪些该真跑。一、测试策略分三层层测什么用不用真模型速度单元测试链的结构、格式、路由分支不用Fake LLM毫秒集成测试真实调用能否跑通用少量秒级效果评测答案质量用测试集分钟级90% 的测试应该在第一层——免费、快、稳定。只有少量用例放第二三层。二、FakeListLLM按顺序返回预设答案fromlangchain_community.llms.fakeimportFakeListLLMfromlangchain_core.promptsimportChatPromptTemplatefromlangchain_core.output_parsersimportStrOutputParser llmFakeListLLM(responses[答案A,答案B,答案C])print(llm.invoke(第一个问题))# 答案Aprint(llm.invoke(第二个问题))# 答案Bprint(llm.invoke(第三个问题))# 答案Cprint(llm.invoke(第四个问题))# 答案A循环它不看输入按顺序吐答案。这正好适合测试链的结构对不对deftest_chain_structure():llmFakeListLLM(responses[最终结果])chain(ChatPromptTemplate.from_template(问题{q})|llm|StrOutputParser())resultchain.invoke({q:任意问题})assertresult最终结果这个测试验证的是链能跑通、输出能解析至于答案对不对不是这一层要管的。三、FakeChatModel模拟对话模型需要返回AIMessage比如测试工具调用时用它fromlangchain_community.chat_models.fakeimportFakeMessagesListChatModelfromlangchain_core.messagesimportAIMessage modelFakeMessagesListChatModel(responses[AIMessage(content你好),AIMessage(content,tool_calls[{name:get_weather,args:{city:北京},id:call_1}],),])测试工具调用链路特别有用不用真调模型就能验证我的循环能不能正确执行工具、把结果塞回去。deftest_tool_loop():modelFakeMessagesListChatModel(responses[AIMessage(content,tool_calls[{name:search,args:{q:test},id:c1}]),AIMessage(content最终答案),])agentbuild_agent(model,tools[search_tool])resultagent.invoke({messages:[(user,查一下test)]})assert最终答案inresult[messages][-1].content四、Fake 的配套组件除了 LLM其他依赖也能 fake4.1 FakeEmbeddingsfromlangchain_community.embeddingsimportFakeEmbeddings embFakeEmbeddings(size384)vectorsemb.embed_documents([a,b])print(len(vectors[0]))# 384它的向量是基于文本哈希生成的所以同样的文本永远得到同样的向量——这让向量检索相关的测试变得可重复。deftest_retrieval():vsFAISS.from_documents(docs,FakeEmbeddings(size128))resultsvs.similarity_search(某个问题,k3)assertlen(results)34.2 FakeRetrieverfromlangchain_core.retrieversimportFakeRetrieverfromlangchain_core.documentsimportDocument retrieverFakeRetriever(documents[Document(page_content预设文档1,metadata{source:a.md}),Document(page_content预设文档2,metadata{source:b.md}),])docsretriever.invoke(任何问题)# 永远返回这两条测试 RAG 链的组装逻辑时非常好用——你只想验证检索结果有没有正确拼进 prompt不想真的建索引。4.3 GenericFakeChatModel模拟流式fromlangchain_community.chat_models.fakeimportGenericFakeChatModelfromlangchain_core.messagesimportAIMessageChunk modelGenericFakeChatModel(messageslambda:AIMessageChunk(content逐字))可以自定义生成逻辑用来测试流式处理。五、怎么验证prompt 里有什么很多时候你想测的是「检索到的文档有没有被正确拼进 prompt」。这时不需要看最终输出直接把 prompt 渲染出来deftest_context_in_prompt():promptChatPromptTemplate.from_messages([(system,只依据上下文回答。\n\n上下文\n{context}),(human,{question}),])messagesprompt.format_messages(context【文档1】二线城市 450 元,question住宿标准,)textmessages[0].contentassert450 元intextassert只依据上下文intext这是最实用的一类测试——快、稳、直击要害。比调用真模型看它答得对不对高效得多。六、用 Mock 验证调用了几次有些逻辑要验证的是调用行为fromunittest.mockimportMagicMockdeftest_calls_llm_once():mock_llmMagicMock()mock_llm.invoke.return_value结果chainprompt|mock_llm|StrOutputParser()chain.invoke({q:x})assertmock_llm.invoke.call_count1deftest_no_call_when_cached():mock_llmMagicMock()mock_llm.invoke.return_value结果cachedCachedChain(mock_llm)cached.invoke({q:x})cached.invoke({q:x})# 同样的输入assertmock_llm.invoke.call_count1# 第二次应命中缓存测缓存、测重试、测降级用 Mock 数调用次数是标准做法。七、录制回放一次性拿到真实响应有时候你既想要真实响应又不想每次都真调。办法是录一次之后回放importjsonfrompathlibimportPath FIXTURESPath(tests/fixtures)classRecordReplayLLM:有 fixture 就回放没有就真调并录下来def__init__(self,real_llm,name):self.realreal_llm self.pathFIXTURES/f{name}.jsondefinvoke(self,prompt,**kw):keystr(prompt)[:200]datajson.loads(self.path.read_text(encodingutf-8))ifself.path.exists()else{}ifkeyindata:returndata[key]resultself.real.invoke(prompt,**kw)data[key]result self.path.write_text(json.dumps(data,ensure_asciiFalse,indent2),encodingutf-8)returnresult第一次跑真调用并落盘之后全部走 fixture——免费且稳定。使用时注意fixture 要提交到 git团队共享prompt 改了要删掉旧 fixture 重录否则测的是过时的响应敏感数据别录进去。八、什么该真跑单元测试覆盖不到的留少量真跑importpytestpytest.mark.slow# 标记为慢测试CI 可选跳过deftest_real_end_to_end():验证真实模型能跑通不验证答案质量resultreal_chain.invoke({question:报销标准})assertisinstance(result,str)assertlen(result)0# 只断言能跑通不断言内容对不对真跑的测试只验证不崩不验证答对——后者属于效果评测用测试集打分见评测那篇。九、一份 pytest 组织建议tests/ ├── conftest.py # 共享的 fake 组件 ├── fixtures/ │ └── llm_responses.json # 录制的响应 ├── test_prompt.py # prompt 渲染快 ├── test_chain.py # 链结构Fake LLM ├── test_tools.py # 工具逻辑 ├── test_agent.py # Agent 流程Fake ChatModel └── test_e2e.py # 真跑标 pytest.mark.slow# conftest.pyimportpytestfromlangchain_community.llms.fakeimportFakeListLLMpytest.fixturedeffake_llm():returnFakeListLLM(responses[测试答案])pytest.fixturedeffake_retriever():returnFakeRetriever(documents[Document(page_content测试文档,metadata{source:test.md}),])十、常见坑坑说明忘记把 fake 换回来上线后返回固定字符串——上线前全局搜 FakeFake 顺序搞错FakeListLLM按顺序消费多调一次就错位测试断言内容对不对那是评测的事单测只管结构对不对fixture 过期改了 prompt 必须重录只测 happy path也要测工具报错解析失败这些分支第一条最危险建议在 CI 加一条检查grep-rFakesrc/echo生产代码里出现 Fakeexit1||exit0十一、小结分三层单测Fake快免费→ 集成少量真跑→ 效果评测测试集打分FakeListLLM按顺序吐答案验证链结构而非内容FakeMessagesListChatModel能模拟tool_calls测工具循环配套FakeEmbeddings同文本同向量可重复、FakeRetriever固定返回测拼装逻辑验证prompt 里有什么用format_messages直接断言最实用测调用行为缓存/重试/降级用Mock 数call_count想要真实响应又不想每次花钱 →录制回放⚠️上线前全局搜一遍 Fake防止调试组件进生产。到这里 LangChain 的工程实践部分告一段落。下一篇进入 RAG 深水区MultiVectorRetriever。

相关新闻

Kubernetes Python 客户端 V1beta1DeviceAllocationResult 模型详解:DRA v1beta1 设备分配结果字段与序列化指南

Kubernetes Python 客户端 V1beta1DeviceAllocationResult 模型详解:DRA v1beta1 设备分配结果字段与序列化指南

后端云原生容器编排 【免费下载链接】python Official Python client library for kubernetes 项目地址: https://gitcode.com/gh_mirrors/python1/python 点击查看 免费下载 本文围绕 Kubernetes 官方 Python 客户端(本仓库,含同步 kuberne…

2026/10/12 0:16:07 阅读更多 →
基于Python+FaceNet的课堂人脸识别签到系统设计与实践

基于Python+FaceNet的课堂人脸识别签到系统设计与实践

简介:基于Python与FaceNet的课堂学生签到系统毕业设计资源包,面向计算机相关专业本科生和需要完成人脸识别类课题的研究者,可帮助解决课堂点名效率低、代签等问题;包内含完整Python源码、数据集及详细文档,源码已经本地…

2026/10/12 0:16:07 阅读更多 →
YOLOv8道路病害检测工程化落地全链路方案

YOLOv8道路病害检测工程化落地全链路方案

简介:本资源是一套基于YOLOv8开发的道路病害检测平台完整源码及配套文档,面向计算机专业本科生、毕业设计与课程设计学习者,解决道路裂缝、坑槽等典型病害的自动化识别与可视化展示问题。资源共94个文件,涵盖24个Python后端核心模…

2026/10/12 0:16:07 阅读更多 →

最新新闻

图解AI应用架构设计:从数据流到组件范式的完整指南

图解AI应用架构设计:从数据流到组件范式的完整指南

做AI应用架构设计这几年,最让我头疼的从来不是技术选型,而是把架构"画"出来。有一次评审会,我盯着投影仪上一张AI应用架构图看了五分钟,愣是没找到"用户请求"是从哪个框进去的。七层嵌套的容器、三十几个带箭…

2026/10/12 3:40:10 阅读更多 →
视觉风格 zine 详解:pptx-master 的 Riso 孔版印刷小刊风演示文稿规范

视觉风格 zine 详解:pptx-master 的 Riso 孔版印刷小刊风演示文稿规范

AI 技能人工智能 【免费下载链接】ppt-master AI 把任意文档生成真正可编辑的 PowerPoint —— 原生形状与动画、演讲者备注可合成音频旁白、还能参考你自己的 .pptx 模板,而不是一张张图片 何雨果出品 项目地址: https://gitcode.com/hugohe3/ppt-master 点击查看…

2026/10/12 3:40:10 阅读更多 →
Pagefind 贡献开发指南:从仓库架构、构建流程到测试套件的完整上手路径

Pagefind 贡献开发指南:从仓库架构、构建流程到测试套件的完整上手路径

搜索引擎前端开发工具 【免费下载链接】pagefind Static low-bandwidth search at scale 项目地址: https://gitcode.com/gh_mirrors/pa/pagefind 点击查看 免费下载 Pagefind 是一款为大规模静态站点提供低带宽搜索的开源方案(仓库根目录 README.md 描…

2026/10/12 3:40:10 阅读更多 →
Claude Code接入MCP搜索服务,实现实时联网查询最新技术资讯

Claude Code接入MCP搜索服务,实现实时联网查询最新技术资讯

自己平时写代码最烦什么?不是需求改来改去,也不是测试环境挂了,而是 Claude Code 在对话里一本正经地跟我说“我无法实时访问互联网,因此无法确认最新信息”。明明只需要查一下某个 API 的最新版本号、某个依赖包现在停在哪个大版…

2026/10/12 3:40:10 阅读更多 →
2026软件测试趋势:从自动化执行到智能质量保障

2026软件测试趋势:从自动化执行到智能质量保障

2026年,如果你还在把“软件测试”定义成点按钮、跑脚本、提bug,那么大概率已经能感受到一种隐约的撕裂感。一边是AI辅助开发把编码效率拉高了几个台阶,另一边是业务对质量的要求从“不出错”变成了“随时可变更、秒级可上线”。在这样的大背景…

2026/10/12 3:40:10 阅读更多 →
数据结构 - > 排序算法

数据结构 - > 排序算法

1. 排序的概念1.1 常见的排序算法1.2 排序算法的评价指标复杂度:评价排序算法的第一大指标就是时间复杂度和空间复杂度,它衡量算法的时间效率和空间效率。稳定性:假定在待排序的数据元素中有两个元素 Ri 和 Rj,它们对应的关键字为…

2026/10/12 3:39:10 阅读更多 →

日新闻

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

在数码相机、高清显示屏与现代矢量图形技术高度发达的今天,画面可以做到绝对的锐利、平滑与无瑕。然而,当一张秋日手账插画或拍立得照片过于“平整无瑕”时,往往会散发出一种冰冷生硬的“数码塑料感(Digital Plasticity&#xff0…

2026/10/12 0:00:59 阅读更多 →
活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

在现代网页与移动端设计中,横排(Horizontal Layout)早已经成为了绝对的主流。然而,当我们翻开泛黄的线装古籍、宋版木刻诗集,或是欣赏一张茶道雅集的手写便签时,那种**自上而下纵向书写、自右向左逐列铺展&…

2026/10/12 0:00:59 阅读更多 →
周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

每到周日的晚上八点到十点,很多人心里都会悄悄亮起一盏警示灯。 在心理学上,这种现象有一个专门的称谓——“周日夜晚焦虑症(Sunday Scaries)”。明天又是周一,闹钟又要重新在七点响彻卧房;脑海里仿佛有一个…

2026/10/12 0:00:59 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/12 0:16:30 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/12 0:16:43 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 10:45:37 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 14:36:53 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 14:36:54 阅读更多 →