LangChain 核心组件实操

📅 2026/6/19 1:33:11 👤 管理员 👁 次浏览
LangChain 核心组件实操
很多刚接触大模型开发的同学都会遇到三个共性麻烦换个模型就要重写一遍调用代码来回适配接口很折腾提示词每次都手写大段重复内容改个规则要翻遍所有代码模型输出的都是自然语言想取个数据还得写正则拆分又麻烦又容易错LangChain 的核心组件就是专门解决这些问题的。它把大模型应用拆成了一块块标准化“积木”学会组合这几块基础积木就能快速搭出稳定可控的小应用。本文只讲最核心的 3 个组件配新手友好的实操案例看完就能动手跑通。一、模型调用一套代码兼容所有大模型解决什么问题不同厂商的大模型OpenAI、DeepSeek、本地开源模型接口规范都不一样如果每次换底座都要重写业务逻辑开发效率会非常低。LangChain 做了一层统一封装不管底层用哪家的模型上层调用方式完全一致。换模型只需要改一行初始化代码业务逻辑丝毫不动。先搞懂两个基础概念现在主流大模型基本都是对话模型ChatModel也就是接收“带角色的对话列表”返回一条回复。另一种纯文本生成的 LLM 已经很少用了新手重点掌握对话模型即可。对话里的三种角色不是单纯的“身份标签”而是有明确的约束优先级system全局规则比如“你是一个编程入门助教说话要通俗”全程生效优先级最高user用户当前的问题/指令推动对话前进assistant模型之前的回复用来让模型记住上下文不然它下一轮就“失忆”了新手实操5行代码跑通对话我们用最常见的兼容 OpenAI 接口的模型做演示全程只需要“初始化→构造消息→调用→取结果”四步。fromlangchain_openaiimportChatOpenAIfromdotenvimportload_dotenvimportos# 加载密钥把密钥存在.env文件里不要硬写在代码里load_dotenv()# 1. 初始化模型换模型只改这里的参数llmChatOpenAI(api_keyos.getenv(API_KEY),base_urlos.getenv(BASE_URL),modeldeepseek-v4-flash,temperature0.3# 数值越小回答越严谨越大越有创意)# 2. 构造对话消息messages[{role:system,content:你是编程入门助教用大白话解释概念不超过3句话},{role:user,content:什么是Python的变量}]# 3. 调用模型resultllm.invoke(messages)# 4. 取回复内容print(result.content)核心要点统一的invoke()方法是 LangChain 所有组件的通用调用方式后面的模板、解析器也都用这个方法想换成本地开源模型只需要把初始化部分换成 HuggingFace 相关代码后面的调用逻辑完全不变多轮对话的本质每次把新的用户问题和模型回复都追加到消息列表里再传给模型二、提示词模板告别重复写提示词解决什么问题比如你想做一个“编程概念解释器”每次都要把“你是助教、要用大白话、不超过3句话”这些规则重写一遍不仅麻烦还容易漏写规则导致输出不稳定。提示词模板的作用就是把固定规则和动态参数拆开模板写一次每次只传不同的参数就行。基础模板参数化复用我们把上面的例子改成模板版把“概念名称”和“受众”做成可替换的参数fromlangchain_core.promptsimportPromptTemplate# 1. 定义模板用{参数名}占位promptPromptTemplate(input_variables[concept,audience],template请用{audience}能听懂的大白话解释什么是{concept}不超过3句话。)# 2. 传入参数生成完整提示词full_promptprompt.format(conceptPython变量,audience初中生)print(full_prompt)# 3. 传给模型调用resultllm.invoke([{role:user,content:full_prompt}])print(result.content)下次想解释“函数”给“小学生”听只需要改format()里的参数模板本身不用动。后续想调整回答风格也只改模板一处所有调用都会同步生效。进阶模板给示例让输出格式更听话光靠文字指令模型经常输出格式乱飘。比如你想让它按固定格式生成动漫推荐只说“按格式输出”没用直接给它看2个示例效果会好很多这就是少样本提示模板。fromlangchain_core.promptsimportFewShotPromptTemplate,PromptTemplate# 1. 准备2个示例examples[{name:千与千寻,recommend:治愈系动画天花板适合全年龄段观看},{name:灵能百分百,recommend:热血又温柔的反套路番适合喜欢成长向的观众}]# 2. 定义每个示例的展示格式example_promptPromptTemplate(input_variables[name,recommend],template动漫{name}\n推荐语{recommend})# 3. 组装少样本模板few_shot_promptFewShotPromptTemplate(examplesexamples,example_promptexample_prompt,suffix动漫{new_name}\n推荐语,input_variables[new_name])# 生成提示词并调用full_promptfew_shot_prompt.format(new_name进击的巨人)resultllm.invoke([{role:user,content:full_prompt}])print(result.content)核心要点基础模板解决“重复写提示词”的问题适合参数化的简单需求少样本模板解决“输出格式不稳定”的问题凡是需要固定结构的输出都可以用实际项目里示例一般存在 JSON 文件里不会硬写在代码中方便批量维护三、输出解析把自然语言变成程序能用的数据解决什么问题模型默认输出的是一大段自然语言但业务代码需要的是能直接用的结构化数据比如字典、列表。没有解析器的话你得自己写正则、切字符串来提取信息又麻烦又容易出错。输出解析器就是专门做这个转换的它会引导模型按指定格式输出再自动转成程序能直接处理的数据类型。1. 最基础StrOutputParser它的作用很简单把模型返回的AIMessage对象转成纯字符串。别小看这个转换LangChain 里组件串联的时候类型不统一会出各种问题。它是所有链式调用的基础底座。fromlangchain_core.output_parsersimportStrOutputParser parserStrOutputParser()# 链式调用提示词 → 模型 → 解析器chainprompt|llm|parser# 直接传参数调用一步到位拿到字符串结果resultchain.invoke({concept:Python列表,audience:初中生})print(result)print(type(result))# 纯字符串类型|是 LangChain 的链式语法意思是把前一个的输出传给后一个当输入不用手动一步步传参。2. 快速原型JsonOutputParser想让模型输出键值对直接拿到 Python 字典用这个解析器最快不需要提前定义数据结构自动引导模型输出 JSON。fromlangchain_core.output_parsersimportJsonOutputParser parserJsonOutputParser()# 模板里嵌入格式要求promptPromptTemplate(template请介绍一部动漫包含名称、类型、推荐理由3个字段。{format_instructions},input_variables[],partial_variables{format_instructions:parser.get_format_instructions()})chainprompt|llm|parser resultchain.invoke({})print(result)print(result[名称])# 直接按键取值它的优点是简单快捷缺点是不校验字段类型适合快速做 Demo。3. 工程首选PydanticOutputParser正式项目里推荐用这个。它需要你先定义一个数据模型明确每个字段的类型和说明解析器不仅会引导模型按格式输出还会自动校验结果格式不对直接报错稳定性高很多。fromlangchain_core.output_parsersimportPydanticOutputParserfrompydanticimportBaseModel,Field# 1. 定义数据模型classAnimeInfo(BaseModel):name:strField(description动漫名称)anime_type:strField(description动漫类型比如治愈、热血、悬疑)reason:strField(description推荐理由20字以内)# 2. 创建解析器parserPydanticOutputParser(pydantic_objectAnimeInfo)# 3. 模板链式调用promptPromptTemplate(template请推荐一部高分动漫。{format_instructions},input_variables[],partial_variables{format_instructions:parser.get_format_instructions()})chainprompt|llm|parser resultchain.invoke({})print(result)print(result.name)# 直接访问属性有代码提示