ARTICLE DETAIL

资讯详情

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

LangChain 入门实战:从零搭建可切换 OpenAI 与 Gemini 的 AI 对话助手

LangChain 入门实战:从零搭建可切换 OpenAI 与 Gemini 的 AI 对话助手 1. 为什么我建议你从 LangChain 开始搭建第一个 AI 应用如果你最近在折腾大语言模型大概率会遇到一个尴尬的局面模型 API 调用会了提示词也写得像模像样但一旦想把“调用模型”这件事做成一个能跑起来的小应用代码就开始乱成一锅粥。今天接 OpenAI明天想换 Gemini 试试效果后天又想加个本地知识库检索结果每换一个环节就要重写一遍胶水代码。LangChain 出现的意义就是把这堆胶水活给标准化了。我自己是从最原始的requests.post直接怼 API 那会儿过来的后来陆续用过几套编排框架最后在多数中小项目里还是回到 LangChain。原因很朴素它的抽象层次刚好卡在“够用但不至于把你绑死”的位置。你可以只用它的ChatModel封装也可以一路用到 Agent、Tool、Memory、Retriever 全套。对初学者来说它最大的价值不是功能多而是它把大模型应用里那些反复出现的模式变成了有名字、有文档、有社区共识的组件。你学的不只是 LangChain而是整个 LLM 应用开发的心智模型。这篇内容面向的是刚入门、或者被各种框架名词绕晕的开发者。我会用 Python 为主线把 LangChain 的核心概念、OpenAI 与 Gemini 的接入方式、以及一个能真正跑起来的实战项目从头讲一遍。中间会穿插我自己踩过的坑比如 API Key 的环境变量管理、模型切换时的参数差异、流式输出的处理细节。看完你应该能独立搭出一个带对话记忆、能切换模型、结构清晰的小应用而不是停留在“Hello World”级别的 demo。需要先说明一点LangChain 的版本迭代非常快网上很多教程还是 0.0.x 时代的写法直接抄会报一堆 deprecation 警告。我下面给出的写法以较新的langchain与langchain-openai、langchain-google-genai这些拆分包为准这也是目前官方推荐的组织方式。如果你看到from langchain.llms import OpenAI这种老写法基本可以判断那篇教程有点年头了。2. 环境准备与依赖安装把地基打牢再动手2.1 Python 版本选择与虚拟环境LangChain 对 Python 版本有要求目前主流版本建议Python 3.9 到 3.12。我实测下来 3.10 和 3.11 最稳3.12 也没问题但如果你还在用 3.8某些新版本的依赖会装不上。Windows 用户去 python.org 下载安装包时记得勾选“Add Python to PATH”这一步漏了后面pip命令会找不到是新手最常见的第一个坑。虚拟环境这件事我必须强调。很多人图省事直接全局pip install结果项目 A 要 langchain 0.1项目 B 要 0.3互相打架。正确做法是每个项目一个独立环境python -m venv venv # Windows venv\Scripts\activate # macOS / Linux source venv/bin/activate激活后命令行前面会出现(venv)前缀这时候装的包都只属于这个项目。我个人的习惯是连pip本身也先升级一下python -m pip install --upgrade pip避免旧版 pip 解析依赖时出幺蛾子。2.2 核心依赖包清单与安装LangChain 现在拆成了多个包不要一股脑装langchain就完事。下面是我常用的最小组合pip install langchain langchain-core langchain-community pip install langchain-openai pip install langchain-google-genai pip install python-dotenv这里解释一下每个包的分工理解了你就不会装错包名作用是否必需langchain-core核心抽象如消息、提示模板、Runnable必需langchain高层编排链、Agent 等必需langchain-community社区集成各种第三方工具按需langchain-openaiOpenAI 官方集成用 OpenAI 时必需langchain-google-genaiGoogle Gemini 集成用 Gemini 时必需python-dotenv读取 .env 文件管理密钥强烈建议注意不要把 API Key 硬编码在代码里也不要把.env文件提交到 Git。我见过太多人因为把 key 推到公开仓库第二天收到账单的案例。2.3 API Key 的获取与安全存放OpenAI 的 key 在平台后台的 API Keys 页面创建格式是sk-开头。Gemini 的 key 在 Google AI Studio 里生成。两个平台都提供一定的免费额度足够你学习和做小项目验证。拿到 key 之后在项目根目录建一个.env文件OPENAI_API_KEYsk-你的key GOOGLE_API_KEY你的gemini key然后在代码里用dotenv加载from dotenv import load_dotenv load_dotenv()LangChain 的集成包会自动从环境变量里读取对应的 key你不需要手动传。这一点设计得挺贴心但也容易让人困惑“我明明没传 key 它怎么就能用了”。记住这个约定OPENAI_API_KEY对应 OpenAIGOOGLE_API_KEY对应 Gemini。3. LangChain 核心概念拆解别被名词吓到3.1 从“消息”说起ChatModel 的输入输出LangChain 里最基础的单位是消息Message。一次对话就是一组消息的列表每条消息有角色和内容。角色主要有三种SystemMessage设定模型的人设和规则比如“你是一个严谨的 Python 助教”HumanMessage用户说的话AIMessage模型回复的内容为什么不用简单的字符串因为多轮对话需要区分谁说了什么字符串表达不了这个结构。你可以把消息列表想象成聊天记录的数组每条记录带一个“谁说的”标签。from langchain_core.messages import SystemMessage, HumanMessage messages [ SystemMessage(content你是一个 Python 专家回答要简洁), HumanMessage(content列表推导式和生成器表达式有什么区别) ]3.2 Prompt Template把可变部分抽出来硬编码提示词是新手通病。LangChain 的ChatPromptTemplate让你把提示词做成模板变量用花括号占位from langchain_core.prompts import ChatPromptTemplate prompt ChatPromptTemplate.from_messages([ (system, 你是一个{role}用{style}的风格回答), (human, {question}) ])这样同一个模板可以复用于不同角色、不同风格不用复制粘贴改字符串。模板还支持partial预填部分变量比如把 role 固定成“Python 专家”只留 question 给用户输入。3.3 Chain 与 LCEL用管道符串起流程LangChain 表达式语言LCEL是现在的主流写法核心就是用|把组件串起来chain prompt | model | parser result chain.invoke({role: Python 专家, style: 通俗, question: 什么是装饰器})这个|读作“然后”数据从左往右流。prompt输出消息列表model接收消息输出 AIMessageparser把 AIMessage 转成纯字符串。这种写法的好处是每个环节都可以单独测试、替换。比如你想把 model 从 OpenAI 换成 Gemini只改这一处就行其他代码不动。3.4 Memory让对话记住上下文默认情况下每次调用模型都是独立的它不记得你上一句说了什么。要实现多轮对话需要把历史消息一起传进去。LangChain 提供了多种 Memory 组件较新版本推荐用RunnableWithMessageHistory配合ChatMessageHistoryfrom langchain_core.runnables.history import RunnableWithMessageHistory from langchain_community.chat_message_histories import ChatMessageHistory store {} def get_session_history(session_id): if session_id not in store: store[session_id] ChatMessageHistory() return store[session_id] conversation RunnableWithMessageHistory(chain, get_session_history)这里的session_id是关键它区分不同用户的对话。生产环境要把store换成 Redis 或数据库否则进程重启历史就没了。4. 接入 OpenAI 与 Gemini一次写通两家4.1 OpenAI 模型初始化与参数详解from langchain_openai import ChatOpenAI llm ChatOpenAI( modelgpt-4o-mini, temperature0.7, max_tokens1000, timeout30, max_retries2 )几个参数值得展开说。temperature控制随机性0 最确定1 最发散。写代码、做数据提取用 0 到 0.3创意写作可以到 0.8 以上。max_tokens限制输出长度注意它和输入长度共享模型的总上下文窗口设太大可能触发超限错误。timeout和max_retries是生产环境必备网络抖动时自动重试能省很多事。模型名这块要留意OpenAI 的模型更新频繁gpt-4o-mini性价比高适合练手gpt-4o能力更强但贵。别用已经下线的老模型名会直接报错。4.2 Gemini 模型初始化与差异点from langchain_google_genai import ChatGoogleGenerativeAI gemini ChatGoogleGenerativeAI( modelgemini-1.5-flash, temperature0.7, convert_system_message_to_humanTrue )Gemini 有个特殊参数convert_system_message_to_human。早期 Gemini 对 system 角色的支持不完善需要把 SystemMessage 转成 HumanMessage 才能正常工作。新版本模型已经支持 system 指令但如果你遇到 system 消息被忽略的情况把这个参数打开往往能解决。另一个差异是 Gemini 的模型命名风格不同gemini-1.5-flash快而便宜gemini-1.5-pro能力更强。选型逻辑和 OpenAI 类似练手用 flash正式任务看需求升级。4.3 用工厂模式统一管理多模型项目里同时用两家模型时最忌讳到处if provider openai。我习惯写一个简单的工厂函数def get_llm(provideropenai, **kwargs): if provider openai: return ChatOpenAI(modelgpt-4o-mini, **kwargs) elif provider gemini: return ChatGoogleGenerativeAI(modelgemini-1.5-flash, **kwargs) else: raise ValueError(f不支持的 provider: {provider})这样切换模型只改一个参数测试不同模型效果时特别方便。你甚至可以写个脚本同一个问题分别丢给两家模型对比输出质量。5. 实战项目搭一个可切换模型的对话助手5.1 项目结构与设计思路我们要做的是一个命令行对话助手具备三个能力多轮记忆、模型切换、流式输出。目录结构如下chat_assistant/ ├── .env ├── main.py ├── llm_factory.py └── requirements.txt设计上把模型创建、对话逻辑、入口分开方便后续扩展成 Web 服务。核心思路是用 LCEL 串起 prompt、model、parser再套一层历史管理。5.2 完整代码实现与逐段说明先写llm_factory.pyimport os from dotenv import load_dotenv from langchain_openai import ChatOpenAI from langchain_google_genai import ChatGoogleGenerativeAI load_dotenv() def get_llm(provideropenai, temperature0.7): if provider openai: return ChatOpenAI( modelgpt-4o-mini, temperaturetemperature, timeout30, max_retries2 ) elif provider gemini: return ChatGoogleGenerativeAI( modelgemini-1.5-flash, temperaturetemperature, convert_system_message_to_humanTrue ) raise ValueError(f未知 provider: {provider})再写main.pyfrom langchain_core.prompts import ChatPromptTemplate from langchain_core.output_parsers import StrOutputParser from langchain_core.runnables.history import RunnableWithMessageHistory from langchain_community.chat_message_histories import ChatMessageHistory from llm_factory import get_llm prompt ChatPromptTemplate.from_messages([ (system, 你是一个乐于助人的 AI 助手回答准确且简洁。), (placeholder, {history}), (human, {input}) ]) llm get_llm(openai) chain prompt | llm | StrOutputParser() store {} def get_history(session_id): if session_id not in store: store[session_id] ChatMessageHistory() return store[session_id] conversation RunnableWithMessageHistory( chain, get_history, input_messages_keyinput, history_messages_keyhistory ) def chat(): session_id default print(对话助手已启动输入 quit 退出。) while True: user_input input(\n你: ) if user_input.strip().lower() quit: break response conversation.invoke( {input: user_input}, config{configurable: {session_id: session_id}} ) print(f\n助手: {response}) if __name__ __main__: chat()这段代码里(placeholder, {history})是历史消息的插入点RunnableWithMessageHistory会自动把历史填进去。input_messages_key和history_messages_key要和模板里的变量名对上对不上会报 KeyError这是很常见的配置错误。5.3 流式输出改造上面的写法要等模型全部生成完才显示体验不够好。改成流式很简单把invoke换成streamfor chunk in conversation.stream( {input: user_input}, config{configurable: {session_id: session_id}} ): print(chunk, end, flushTrue)flushTrue很重要否则输出会缓冲看起来还是一卡一卡的。流式输出对长回答的体验提升非常明显用户能立刻看到模型在“打字”。6. 常见问题与排查技巧实录6.1 认证与网络类问题新手最常撞的就是认证错误。AuthenticationError一般有三种原因key 写错、key 没被加载、账户额度用完。排查顺序是先确认.env文件在项目根目录且load_dotenv()在导入模型前调用再打印os.getenv(OPENAI_API_KEY)[:8]看前几位对不对。网络超时是另一类高频问题。表现是Timeout或ConnectionError。先确认基础网络能通再检查是不是代理配置干扰。如果你在公司网络里防火墙可能拦了 API 域名这种情况需要找网络管理员确认。6.2 版本兼容与依赖冲突LangChain 生态更新快ImportError和DeprecationWarning特别多。我的经验是看到from langchain.llms import ...这种老路径直接换成新包路径。如果装完报某个依赖版本冲突先pip list看看实际装了什么版本再用pip install 包名版本号锁定。下面这张表是我整理的高频报错对照报错信息可能原因解决方向AuthenticationErrorkey 错误或未加载检查 .env 与加载顺序RateLimitError请求过频或额度耗尽降低频率、检查账单Timeout网络慢或超时设太短调大 timeout、检查网络KeyError: history模板变量名不匹配核对 key 名称ModuleNotFoundError包没装或装错包按拆分包清单重装ContextLengthExceeded输入加输出超窗口截断历史或换大窗口模型6.3 对话记忆失效的排查有时候你会发现模型“失忆”了明明配了 Memory 却不记得上一句。九成是session_id没传对或者每次调用都新建了 history 对象。检查get_history函数是不是用了全局store缓存而不是每次return ChatMessageHistory()。后者每次都是新的空历史自然记不住。另一个隐蔽的坑是历史无限增长。对话轮次多了之后历史消息会撑爆上下文窗口。生产环境要做截断比如只保留最近 N 轮或者用摘要的方式压缩早期对话。LangChain 有trim_messages工具可以做这件事值得花时间研究。7. 从能跑到好用几个提升质量的经验7.1 提示词工程的实际技巧提示词不是越长越好。我试过把一堆规则堆进 system 消息结果模型反而抓不住重点。有效的做法是结构化用编号列出规则把最重要的放前面。比如“1. 回答用中文2. 代码要能直接运行3. 不确定时明确说不确定”。比一大段散文式的描述管用得多。还有一个技巧是给例子。模型对 few-shot 示例的敏感度很高给一两个输入输出样例效果往往比写十条规则还好。这在做格式固定的任务比如提取 JSON时尤其明显。7.2 成本与性能的平衡练手阶段用便宜模型完全够gpt-4o-mini和gemini-1.5-flash的价格都很友好。真正上线前再评估是否需要升级。控制成本的几个手段限制max_tokens、截断历史、缓存重复问题的回答。LangChain 支持接缓存层相同问题直接返回缓存结果能省不少钱。性能方面流式输出是体感提升最大的一项。另外把模型调用放在异步流程里可以避免阻塞主线程。LangChain 的ainvoke、astream就是干这个的Web 服务里基本都要用异步版本。7.3 后续可以扩展的方向这个对话助手只是个起点。往上加 RAG检索增强生成接一个向量数据库就能让它基于你的私有文档回答问题。往上加 Tool 和 Agent就能让它调用外部函数、查天气、算数学。往上加 Web 框架就能变成一个有界面的产品。我的建议是不要一上来就堆功能。先把“模型调用 记忆 流式”这条主线跑通、跑稳再逐个加模块。每加一个模块都单独测试出问题好定位。LangChain 的组件化设计本来就是为这种渐进式开发准备的用好这一点你的项目会越搭越顺。最后分享一个我自己的习惯每换一个模型或改一次提示词都拿同一组测试问题跑一遍记录输出质量。时间长了你会积累出一套自己的评估集选型和调优时心里特别有底。这比凭感觉“好像变好了”靠谱得多。
返回列表