【LangChain】4.快速上手-编码

【LangChain】4.快速上手-编码
4. 快速上手-编码1. 调用大模型的基本流程抛开链式结构不谈调用大语言模型的基本逻辑分为三步定义/接入大模型构造消息调用模型获取结果定义大模型——选择并配置要使用的大模型如 GPT-4o-mini构造消息——组合系统提示和用户输入调用模型——将消息传递给模型获取响应下面围绕这个流程逐步展开代码编写。2. 申请 API Key 并配置环境变量2.1 申请 API Key以 OpenAI 为例前往 platform.openai.com需科学上网注册或登录账号。进入 Settings → API keys 页面点击 “Create new secret key” 按钮创建新密钥将生成的 API Key 保存在本地后续接入时需要用到。2.2 配置环境变量将 API Key 配置到系统环境变量中避免在代码中直接暴露密钥。环境变量名称OPENAI_API_KEY# Windows 系统setOPENAI_API_KEYyour-api-key-here# Linux/macOS 系统exportOPENAI_API_KEYyour-api-key-hereTip:重启编译器如果在编译器如 VS Code、PyCharm打开后才配置环境变量需要重启编译器才能读取到最新的环境变量。LangChain 的ChatOpenAI默认从系统环境变量OPENAI_API_KEY读取密钥无需在代码中显式传入。3. 定义大模型3.1 安装依赖包pipinstall-Ulangchain-openai-U表示升级到最新版本首次安装可不带此选项。3.2 定义模型fromlangchain_openaiimportChatOpenAI modelChatOpenAI(modelgpt-4o-mini)ChatOpenAI会从环境变量OPENAI_API_KEY自动读取密钥。如果环境变量未配置也可显式传入modelChatOpenAI(modelgpt-4o-mini,api_keyyour-api-key-here# 不推荐硬编码)Note:远程调用通过 API Key 调用 OpenAI 模型属于远程调用模型在 OpenAI 服务器上运行非本地部署。3.3 ChatOpenAI 常用参数ChatOpenAI提供了丰富的初始化参数来控制模型行为参数说明model模型名称如gpt-4o-mini、gpt-5temperature采样温度。值越高回答越天马行空越低越保守max_tokens最大输出令牌数None表示由模型自动决定timeout请求超时时间秒max_retries请求失败时的最大重试次数api_keyAPI 密钥默认从环境变量OPENAI_API_KEY读取base_urlAPI 请求的基础 URL用于兼容第三方服务商organizationOpenAI 组织 ID默认从环境变量OPENAI_ORG_ID读取temperature采样温度temperature 是控制模型输出随机性的核心参数# 保守模式适合代码生成modelChatOpenAI(modelgpt-4o-mini,temperature0)# 创意模式适合故事创作modelChatOpenAI(modelgpt-4o-mini,temperature1.5)max_tokens最大输出令牌数与 Token 概念max_tokens控制模型单次回复的最大长度。理解它需要先了解Token的概念。Token 是自然语言处理中文本的基本计量单位并非简单对应一个词或一个字英文1 Token ≈ 4 个英文字符 ≈ 0.75 个单词中文1 个汉字 ≈ 1.5 ~ 2 个 Token这意味着中文调用大模型消耗的 Token 更多成本也更高。这也是用英文调用大模型更省钱说法的底层原因。# 限制输出为约 10 个 Token约 5~6 个汉字modelChatOpenAI(modelgpt-4o-mini,max_tokens10)超时与重试modelChatOpenAI(modelgpt-4o-mini,timeout30,# 30 秒超时max_retries3,# 失败重试 3 次)3.4 通过 base_url 接入兼容模型如 DeepSeek许多第三方模型兼容 OpenAI 的 API 格式可通过base_url和api_key直接使用ChatOpenAI接入modelChatOpenAI(base_urlhttps://api.deepseek.com/v1,api_keyyour-deepseek-api-key,modeldeepseek-chat,)Note:base_url 中的 v1此处v1是 OpenAI 兼容 API 的前缀与模型版本无关。DeepSeek 原生 API 不带此路径加v1是为了兼容 OpenAI 的调用格式。4. 定义消息LangChain 使用标准化的消息类型来区分不同角色常见的消息类型有以下几种消息类型角色说明SystemMessage系统提示通常作为输入消息序列的第一条用于设定 AI 的行为和任务HumanMessage用户消息来自用户的输入传递给模型进行处理AIMessageAI 回复模型返回的响应消息4.1 定义消息列表fromlangchain_core.messagesimportHumanMessage,SystemMessage messages[SystemMessage(contentTranslate the following from English into Chinese),HumanMessage(contenthi!),]SystemMessage定义 AI 的角色和行为如将英文翻译为中文HumanMessage用户的实际输入内容如hi!之后只需构造新的HumanMessage如 “my name is xiaoming”系统提示词无需重复编写模型会自动结合系统消息进行处理。5. 调用大模型在上面的代码中model是 LangChainRunnable可运行接口的实例提供了标准化的交互方式。对于什么是 Runnable 我们在下一小节中学习5.1 使用 .invoke() 调用resultmodel.invoke(messages)print(result)输出结果content你好! additional_kwargs{refusal: None} ...5.2 输出说明result的类型为AIMessage包含以下关键字段字段说明用途场景content消息的内容——模型返回的文本结果提取最终答案additional_kwargs额外有效负载如工具调用编码工具调用场景response_metadata响应元数据请求 ID、模型版本、服务商原始返回数据调试、日志、获取请求上下文usage_metadata资源消耗本次调用消耗的 Token 数量成本计算、监控、预算控制Tip:response_metadata vs usage_metadataresponse_metadata侧重于响应本身的信息如请求 ID、模型版本usage_metadata侧重于资源消耗的量化信息如input_tokens、output_tokens、total_tokens输出示例格式化后# response_metadata{model_name:gpt-4o-mini-2024-07-18,system_fingerprint:fp_...,finish_reason:stop,logprobs:None}# usage_metadata{input_tokens:20,output_tokens:2,total_tokens:22}6. 输出解析有时我们只关心模型返回的文本内容而非完整的AIMessage对象。LangChain 提供了输出解析器Output Parser来提取和格式化结果。6.1 使用 StrOutputParserfromlangchain_core.output_parsersimportStrOutputParser parserStrOutputParser()result_strparser.invoke(result)print(result_str)# 输出: 你好StrOutputParser将AIMessage解析为最可能的字符串输出只保留content部分。后续还会学习其他类型的输出解析器用于输出 JSON、结构化数据等格式。7. 链式执行以上每一步都需要手动调用.invoke()先调模型取结果再调解析器。LangChain 提供了链式执行能力将多个组件串联一次调用即可得到最终结果。7.1 定义链chainmodel|parser|管道操作符是 LangChain Expression Language (LCEL) 的核心语法model | parser表示将model的输出作为parser的输入。7.2 执行链resultchain.invoke(messages)print(result)# 输出: 你好链的执行流程链式方式LCELmessageschainchain.invoke最终结果传统方式手动编排messagesmodel.invoke取 resultparser.invoke最终结果Tip:链的顺序链按照从前到后的顺序执行先执行第一个组件model再将结果传递给下一个组件parser。顺序不能颠倒。7.3 链式 vs 非链式对比对比项传统方式链式方式调用方式每个组件手动.invoke()定义链后一次.invoke()代码量较多需手动传递中间结果简洁组件通过 7.4 Runnable 接口一切组件的基础为什么model、parser、chain都可以调用.invoke()因为它们都实现了Runnable 接口。理解 Runnable关键在于理解为什么需要它。下面从面临的问题→解决方案→设计理念这条线展开。7.4.1 为什么需要 Runnable——旧 Chain 时代的痛点在 LangChain 早期版本0.0.x中核心抽象是各自独立的 Chain 类如LLMChain、SequentialChain、RetrievalQA存在几个突出问题痛点具体表现接口不统一LLMChain用.run()Retriever用.get_relevant_docs()OutputParser用.parse()——每个组件有自己的一套调用方式组合困难链与链之间靠input_variables/output_variables字段名匹配改一个字段名牵一发动全身流式/批量/异步支持零散每个组件各自实现不原生开发者需手动封装扩展性差想加一个重试机制或日志中间件需要继承重写整个 Chain 类可观测性缺失无法统一注入回调、追踪、标签调试困难这些问题的根源在于组件之间缺乏统一的交互协议。就像 U 盘、键盘、显示器各自用不同的接口——每次连接都在找不同的口、找不同的转接头。Runnable 就是 LangChain 的USB-C 标准。7.4.2 Runnable 是什么——统一执行协议Runnable 是LangChain 所有可执行组件的统一抽象接口它不仅仅是一个基类更是一套协议Protocol。任何实现了这个协议的对象都承诺提供以下五组核心方法能力方法说明典型场景同步调用invoke单个输入 → 单个输出实时交互、测试异步调用ainvoke异步单次调用FastAPI 等高并发服务批处理batch批量输入 → 批量输出自动线程池并发批量文档处理流式stream输出在生成时逐块返回聊天界面打字机效果组合pipe/ 通过 LCEL 串联多个 Runnable关键认识LangChain 中几乎所有核心组件本质上都是 Runnable 实例# 以下都是 Runnable——调用方式完全相同promptChatPromptTemplate.from_template(讲个关于{topic}的笑话)modelChatOpenAI(modelgpt-4o-mini)parserStrOutputParser()chainprompt|model|parser# 链本身也是 Runnableprompt.invoke({topic:程序员})# → PromptValuemodel.invoke(messages)# → AIMessageparser.invoke(ai_message)# → strchain.invoke({topic:程序员})# → str最终结果7.4.3 为什么这样设计1. 统一接口Prompt、Model、Parser、Retriever 无论内部多复杂对外一律只认.invoke()。昨天用 GPT今天换 DeepSeek明天换本地模型——调用代码零改动。这就是 7.4.2 中一个 .invoke() 走天下的底层逻辑。2.一次定义四种执行模式chainprompt|model|parser# 只定义一次chain.invoke(x)# 单次执行chain.batch([x1,x2])# 批量执行自动线程池并发chain.stream(x)# 逐 token 流式awaitchain.ainvoke(x)# 异步如果组件没实现流式框架自动把invoke结果包成迭代器 yield 出来。组件可以按需升级上层代码零感知。例如一个 LLM 可能只实现了.invoke()一次性返回完整结果但调用方使用.stream()时LangChain 会自动将# 底层实现伪代码defstream(self,input):resultself.invoke(input)# 调用同步方法yieldresult# 包装成单步迭代器返回当该 LLM 后来原生实现了流式接口后只需把真实实现挂到_stream方法上调用方代码完全不用改——这就是零感知的含义接口统一上下游解耦。理解 Runnable 后下面两件事会变得很自然学一个新组件时不需要重新学它的调用方式——只要是 Runnableinvoke / batch / stream就是肌肉记忆调试时可以专注在组合逻辑对不对而非这个组件的调用语法是什么这些设计思想在下一节7.5 多种定义链的方式中马上就会用到。7.5 多种定义链的方式除了|管道操作符LangChain 还提供了另外两种定义链的方式fromlangchain_core.runnablesimportRunnableSequence# 方式一管道操作符最推荐最直观chainmodel|parser# 方式二RunnableSequencechainRunnableSequence(firstmodel,lastparser)# 方式三.pipe() 方法参考 Linux 管道设计chainmodel.pipe(parser)三种方式效果完全相同。方式一最简洁直观推荐日常使用。.pipe()方法的设计参考了 Linux 系统的管道pipe机制LCEL 借此实现了优雅的组件编排。8. 完整代码示例fromlangchain_core.messagesimportHumanMessage,SystemMessagefromlangchain_core.output_parsersimportStrOutputParserfromlangchain_openaiimportChatOpenAI# 1. 定义大模型默认从环境变量读取 OPENAI_API_KEYmodelChatOpenAI(modelgpt-4o-mini)# 2. 定义消息列表messages[SystemMessage(content请帮我进行翻译由英文翻译成中文),HumanMessage(contentmy name is xiaoming)]# 3. 定义输出解析器parserStrOutputParser()# 4. 定义链并执行chainmodel|parser resultchain.invoke(messages)print(result)# 输出: 我叫小明总结通过本节的快速上手编码我们完成了接入大模型——使用ChatOpenAI定义 GPT 模型通过 API Key 远程调用构造消息——使用SystemMessage和HumanMessage构造符合 LangChain 规范的消息列表调用模型——使用.invoke()方法获取模型响应理解AIMessage的结构输出解析——使用StrOutputParser提取纯文本结果链式执行——使用 LCEL 的|操作符将组件串联一次调用即可得到最终结果Runnable 接口——理解 LangChain 所有组件的标准化接口掌握invoke/batch/stream等核心方法ChatOpenAI 参数调优——掌握 temperature、max_tokens、Token 概念、超时重试及第三方兼容接入接下来将深入学习聊天模型的高级定义方式init_chat_model工厂函数、本地部署以及模型工具调用能力。