LangChain框架入门构建LLM应用的第一块积木上周帮团队排查一个生产事故日志里躺着一行诡异的报错openai.error.InvalidRequestError: Engine not found。同事盯着代码看了半小时死活想不通——明明昨天还能跑通的对话机器人今天怎么就找不到引擎了我扫了一眼他的代码发现他直接调用了OpenAI的原始API把模型名写死在enginetext-davinci-003里。问题出在OpenAI去年底就把这个模型退役了而他的代码里没有任何模型切换的抽象层。这就是典型的“裸调LLM”后遗症。当你手头只有一个API调用时换模型、加记忆、做链式调用每一步都得改核心代码。LangChain就是来解决这个问题的——它不生产大模型只是大模型的“适配器”和“胶水”。从一次痛苦的Prompt调试说起先看一个我早期踩过的坑。当时想做一个文档摘要工具代码长这样importopenaidefsummarize(text):responseopenai.ChatCompletion.create(modelgpt-3.5-turbo,messages[{role:system,content:你是一个文档摘要助手},{role:user,content:f请总结以下内容{text}}])returnresponse.choices[0].message.content这段代码的问题不是跑不通而是改不动。产品经理说“能不能加个输出格式要求”你得改prompt说“换个模型试试”你得改参数说“把历史对话也传进去”你得重写消息构造逻辑。两周后这个函数膨胀到80行里面塞满了if-else判断模型类型。LangChain的解法很直接把LLM调用拆成“模型”、“提示模板”、“输出解析器”三个独立组件。模型只管发请求模板只管拼字符串解析器只管格式化结果。各干各的互不干扰。安装与第一个Chain别急着pip install先确认Python版本。LangChain 0.1.x开始要求Python 3.8.1以上我见过有人在3.7环境里装了个旧版结果langchain.chains模块都导不进去。建议直接用3.10。pipinstalllangchain langchain-openai注意这里分开装了两个包。langchain是核心框架langchain-openai是OpenAI的集成包。别这样写# 别这样写这是旧版用法新版已废弃fromlangchain.llmsimportOpenAI新版应该这样fromlangchain_openaiimportChatOpenAI# 这里踩过坑环境变量OPENAI_API_KEY没设的话会直接抛认证错误llmChatOpenAI(modelgpt-4,temperature0.7)ChatOpenAI返回的是一个LLM对象但它还不能直接干活。你需要把它塞进一个Chain里。最简单的Chain叫LLMChainfromlangchain.promptsimportChatPromptTemplatefromlangchain.chainsimportLLMChain promptChatPromptTemplate.from_messages([(system,你是一个{role}请用{style}风格回答),(human,{input})])chainLLMChain(llmllm,promptprompt)resultchain.run(role技术顾问,style简洁,input什么是LangChain)print(result)看到没{role}、{style}、{input}这些占位符在运行时才填充。这就是模板化的威力——改prompt不用改代码改参数就行。别被“链”这个词吓到很多人第一次接触LangChain看到“链”就以为是链表或者责任链模式。其实LangChain的Chain就是一个可调用对象输入一个字典输出一个字典。LLMChain的输入是prompt变量输出是{text: ...}。但真正让Chain强大的是组合能力。比如我想先让LLM生成一个文章大纲再根据大纲写全文。传统写法要调两次API中间还得手动传参。用LangChain的SequentialChainfromlangchain.chainsimportSequentialChain# 第一个链生成大纲outline_promptChatPromptTemplate.from_messages([(human,请为{topic}写一个详细的大纲包含3个主要章节)])chain1LLMChain(llmllm,promptoutline_prompt,output_keyoutline)# 第二个链根据大纲写文章article_promptChatPromptTemplate.from_messages([(human,根据以下大纲写一篇完整的文章\n{outline})])chain2LLMChain(llmllm,promptarticle_prompt,output_keyarticle)# 串联起来full_chainSequentialChain(chains[chain1,chain2],input_variables[topic],output_variables[article])resultfull_chain({topic:AI大模型应用开发})print(result[article])这里有个容易翻车的地方output_key必须和下一个链的输入变量名一致。我见过有人把chain1的output_key写成outline_text但chain2的prompt里用的是{outline}结果运行时直接报KeyError。调试这种问题最烦人因为LangChain的错误信息有时候不够明确。Memory让LLM记住你是谁LLM本身是无状态的每次调用都是独立的。但很多应用需要上下文比如聊天机器人要记住之前说过什么。LangChain提供了多种Memory实现。最简单的ConversationBufferMemoryfromlangchain.memoryimportConversationBufferMemoryfromlangchain.chainsimportConversationChain memoryConversationBufferMemory()conversationConversationChain(llmllm,memorymemory)conversation.predict(input你好我叫张三)conversation.predict(input你还记得我叫什么吗)第二次调用时LLM会回答“你叫张三”。因为Memory把历史对话拼到了prompt里。但这里有个坑默认的ConversationBufferMemory会把所有历史都塞进去对话长了token会爆。生产环境一定要用ConversationSummaryMemory或者ConversationTokenBufferMemory前者用LLM总结历史后者按token数截断。我踩过最深的坑是Memory的return_messages参数。默认是False返回的是字符串拼接的历史。如果你用Chat模型最好设成True返回消息列表这样模型能更好理解对话结构。memoryConversationBufferMemory(return_messagesTrue)实战一个带记忆的客服机器人把上面这些拼起来写一个能记住用户信息的客服机器人fromlangchain_openaiimportChatOpenAIfromlangchain.promptsimportChatPromptTemplate,MessagesPlaceholderfromlangchain.memoryimportConversationSummaryMemoryfromlangchain.chainsimportLLMChain llmChatOpenAI(modelgpt-4,temperature0.3)promptChatPromptTemplate.from_messages([(system,你是一个电商客服态度友好回答简洁),MessagesPlaceholder(variable_namehistory),(human,{input})])memoryConversationSummaryMemory(llmllm,return_messagesTrue,memory_keyhistory# 这里踩过坑必须和MessagesPlaceholder的variable_name一致)chainLLMChain(llmllm,promptprompt,memorymemory)# 模拟对话chain.run(input我上周买的手机屏幕碎了能保修吗)chain.run(input订单号是JD20231234)chain.run(input我什么时候能收到换货)注意MessagesPlaceholder这个组件。它告诉LangChain“这里要插入历史消息”。如果不加这个Memory里的历史不会被拼进prompt机器人就会失忆。关于模型选择的个人建议LangChain支持几十种模型但别贪多。我个人的经验是原型阶段用ChatOpenAI的gpt-3.5-turbo速度快成本低生产环境如果预算够上gpt-4如果追求性价比试试Claude或者本地部署的Qwen千万别在同一个Chain里混用不同厂商的模型除非你清楚知道每个模型的输出格式差异另外temperature这个参数我建议设成0.3以下用于事实性任务如摘要、提取0.7以上用于创意性任务如写作、头脑风暴。设成0.0虽然确定性高但会让模型变得死板连同义词替换都不愿意做。调试技巧打开详细日志LangChain的调试信息默认是关闭的。当你遇到“模型返回了空字符串”或者“Chain执行顺序不对”时可以这样打开importlangchain langchain.debugTrue这会打印出每一步的输入输出包括prompt最终长什么样、模型返回了什么、Memory里存了什么。我调试Memory问题时全靠这个发现memory_key配错了。还有一个更细粒度的方式设置环境变量exportLANGCHAIN_VERBOSEtrue最后说几句LangChain不是银弹。它解决的是“LLM应用开发中的重复劳动”而不是“LLM本身的能力问题”。如果你的prompt写得稀烂换什么框架都没用。我见过有人用LangChain搭了个复杂的Agent结果LLM连基本的工具调用都做不对——问题不在框架在模型选型。入门阶段先掌握LLMChain、PromptTemplate、Memory这三个核心概念就够了。别一上来就研究Agent、Tool、Retriever那些是后面的事。先把积木搭稳再考虑盖高楼。下一期我会写LangChain的进阶玩法如何用OutputParser把模型输出转成结构化数据以及如何用Runnable接口替代老旧的Chain API。这两个东西能让你少写一半的异常处理代码。