ARTICLE DETAIL

资讯详情

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

学 LangChain 前三章,我悟了:别人的理解永远是别人的,自己写一遍才是自己的

学 LangChain 前三章,我悟了:别人的理解永远是别人的,自己写一遍才是自己的 为什么写这篇跟着视频学 LangChain敲完代码觉得哦我懂了。真让我合上教程操作一遍手下的代码总是泛红于是我干了件事拿笔记本把前三章的知识点用自己的话手写一遍。写的时候才发现原来我以为懂的其实只是看过。prompt.invoke(dict)和chain.invoke(dict)的区别我能背但让我讲清楚为什么——卡壳。Message 类和 PromptTemplate 类长得像我一直以为是一回事——直到手写时才发现名字里就差了PromptTemplate几个字。这篇博客就是我的手写笔记整理版。配图全是我的手写原稿。第一章模型创建与调用一句话定位一切应用的起点——把模型变成可调用对象。核心知识点1. 模型创建fromlangchain.chat_modelsimportinit_chat_model llminit_chat_model(modelopenai:glm-4-flash,api_keyos.getenv(ZHIPUAI_API_KEY),base_urlhttps://open.bigmodel.cn/api/paas/v4/,temperature0.7,)init_chat_model是 1.x 官方推荐的统一初始化方式openai:前缀指定用 OpenAI 兼容协议。换厂商只改前缀和base_url。2. 三种调用方式方式返回适用场景llm.invoke(问题)AIMessage一次性问答llm.stream(问题)逐块文本打字机效果、长回答llm.batch([问题1,问题2])AIMessage 列表并发批量处理3..text属性1.x 新特性直接取文本不用再.content。两者等价优先用.text。4. 四种消息类型类型角色出现位置SystemMessage设定人设/规则通常开头出现一次HumanMessage用户输入用户输入AIMessage模型回复内容历史轮次的 AI 输出可能带 tool_callsToolMessage工具执行结果回填工具调用后第二章Message 与提示词模板一句话定位把写死的提示词变成带 {变量} 的可复用模板搞清填词和调模型是两步。我踩过的最大的坑模板(带{变量}) --invoke(dict)-- PromptValue(填好的消息) --llm.invoke-- AIMessage(回复) 填词一步 产物 调模型另一步prompt.invoke(dict)只填词不调模型它返回的是 PromptValue不是模型回复。要调模型得llm.invoke(filled)或者用链prompt | llm | parser。我一开始把填好的 PromptValue 再丢给以模板开头的链报类型不匹配——因为链要的是 dict不是 PromptValue。元组写法最常用promptChatPromptTemplate.from_messages([(system,你是一位{style}风格的翻译专家只输出译文。),(human,请把下面内容翻译成{language}\n{content}),])chainprompt|llm|StrOutputParser()chain.invoke({style:文艺,language:中文,content:Life is a journey...})简洁日常主力。消息模板类写法了解即可日常不用fromlangchain_core.promptsimportSystemMessagePromptTemplate,HumanMessagePromptTemplate promptChatPromptTemplate.from_messages([SystemMessagePromptTemplate.from_template(你是{role}。),HumanMessagePromptTemplate.from_template({content}),])我手写时特意标注了繁琐且无独特价值写代码几乎用不上。它和元组写法功能完全等价但字多一倍。元组能覆盖的场景没必要用它。知道有这回事就行别在这上面花时间。Message 类这才是真正的消息这是我手写时才理清的Message 类SystemMessage、HumanMessage 等是消息实例没有变量替换MessagePromptTemplate 类才是带占位符的模板。名字里就差了PromptTemplate几个字但完全是两种东西SystemMessage(content你是数学老师) 印好的成品书SystemMessagePromptTemplate.from_template(你是{role}) 活字印刷模具Message 类真正不可替代的场景是工具调用——tool_calls和ToolMessage的tool_call_id元组法表达不了。手动构造多轮对话历史fromlangchain_core.messagesimportSystemMessage,HumanMessage,AIMessage messages[SystemMessage(content你是数学老师回答简短。),HumanMessage(content3乘4等于多少?),AIMessage(content12。下一题。),HumanMessage(content那再加8呢?),]llm.invoke(messages).text# 模型知道再加8指的是 128partial 预填充固定变量promptChatPromptTemplate.from_messages([(system,今天是{date}你是{role}。),(human,{input}),]).partial(date2026年10月2日)日期、格式要求等固定内容提前填好调用只传变化部分。第三章结构化输出一句话定位让大模型输出可被代码直接使用的数据而不是一段需要正则解析的文本。核心思想用 Pydantic 定义表单让模型按表填。Pydantic 模型 → JSON Schema → function_calling 协议 → 模型被约束 → 返回严格符合 schema 的 JSON → 自动解析回 Pydantic 对象定义表单frompydanticimportBaseModel,FieldclassMovieReview(BaseModel):title:strField(description电影名称)score:floatField(description评分)one_line:strField(description一句话评价)Field(description...)里的文字会变成 JSON Schema 的 description是模型唯一能看到的填表指南。调用reviewllm.with_structured_output(MovieReview,methodfunction_calling,strictFalse,# glm-4-flash 必须 False).invoke(评价电影《星际穿越》)print(review.title)# 星际穿越print(review.score)# 9.4schema 传一次就绑定到对象上invoke 时只传用户提问不用每次传 schema。include_raw 调试看模型到底返回了什么raw_llmllm.with_structured_output(MovieReview,strictFalse,include_rawTrue)outraw_llm.invoke(评价电影《星际穿越》)# out 是字典三个 key# raw: 原始 AIMessage包含 tool_calls# parsed: 解析后的 Pydantic 对象# parsing_error: 解析异常或 None调试时用这个看模型的 tool_calls 长什么样比直接拿 parsed 对象更能理解底层。json_mode 兜底当function_calling模式对小模型如 glm-4-flash返回 None 时降级用 json_mode。但它只保证合法 JSON不保证字段名一致所以要手动把字段说明写进 promptfields_desc\n.join(f -{name}:{f.descriptionor无说明}forname,finMovieReview.model_fields.items())这里f是 FieldInfo 对象字段的元信息档案不是 Pydantic 模型实例。model_fields是 BaseModel 给的类属性存字段定义字典。总结1.Pydantic 模型 表单Field(description...)是模型的唯一填表说明2. 结构化输出首选with_structured_output(methodfunction_calling)国内小模型用strictFalse3. 小模型返回 None 时降级json_mode但要手动拼字段说明进 prompt4.json_mode必须在 prompt 里写死 JSON 格式说明否则模型会自由发挥5. schema 直接传类名不用传model_fields或model_json_schema()6. 调试用include_rawTrue看raw里模型到底返回了什么写在最后学技术最容易陷入的误区觉得看过 学会了。视频里老师讲得清楚代码也跟着敲了一运行没问题——但这些都是被动接收。真正检验懂没懂是能不能用自己的话讲出来、写出来。手写笔记的过程就是把别人的理解打碎、重组、再输出的过程。写不下去的地方就是没懂的地方。这篇博客里的每一个知识点都是我在笔记本上卡过壳、回头翻代码、再写通的。而对知识的输出是避开情绪幻觉的好方法踩过坑走过泥肿的包和干的泥是我自己的备忘录。输出才是最好的输入。如果你也在学 LangChain建议合上教程拿张纸试试能不能默写出prompt.invoke和chain.invoke的区别——大概率你会发现原来自己没那么懂。关于作者平顶山学院 2026 级计算机专业新生AI 工程方向自学者。爬虫起步正在啃 LangChain目标做出能落地的 AI 系统。我的代码仓库Gitee | 个人博客small-mo.netlify.app
返回列表