GLM 接入 LangChain 怎么配:从 base_url 到 Agent
数据截至 2026-08,价格与限额以各官网为准。本文只讲计费与接入机制,不列具体价格数字。
先把结论摆在最前面:智谱官方文档里的 LangChain 集成方案,并没有提供一个叫「ChatZhipu」的专属类,走的是 langchain_openai 的 ChatOpenAI——你把 openai_api_base 指向智谱的 v4 接口地址,把 openai_api_key 换成智谱平台申请的 Key,模型名填成智谱的模型名,剩下的链、模板、记忆、Agent、流式回调全都是 LangChain 原生那一套,一行都不用改。 所以这件事的难点从来不在「怎么接」,而在两个容易被跳过的细节:一是 langchain_community 的版本门槛,官方专门用警告框标出来了;二是 openai_api_base 那个地址的尾部形态,官方示例里是带尾斜杠的完整路径,抄的时候不要自作主张删改。这篇按官方文档的实际编排顺序,把从装包到 Agent 的每一步过一遍。
第一步:确认环境是否够得着门槛
官方在「环境要求」一节列了两条硬约束,都是版本,不是行情数字,可以直接照抄:Python 需要 3.8 或更高版本;langchain_community 需要在 0.0.32 以上。第二条后面还单独跟了一个警告框,原文的说法是请确保 langchain_community 的版本在 0.0.32 以上,以获得最佳的兼容性和功能支持。
这个约束值得多说一句。很多人的机器上 LangChain 是很久以前装的,langchain 主包升过、langchain_community 却因为依赖锁定停在老版本。官方只说了版本要在 0.0.32 以上才能获得最佳的兼容性和功能支持,至于版本不够时会以什么形式暴露出来,文档里没有说明。所以别把这条当成可选建议——在动手配 Key 之前先把两个版本查一遍,是成本最低的一步。
官方也给了验证安装的办法,就是在安装完成后用一行 python -c 把 langchain.__version__ 打印出来。这行命令的价值不在于看版本号本身,而在于确认你 pip 装包的那个解释器,和你后面跑脚本的那个解释器是同一个——多环境混用导致的「明明装了却 import 不到」,在这一步就能暴露。
第二步:按官方给的两组命令装包
官方把安装拆成了「基础安装」和「完整安装」两块,内容其实有重叠。基础安装那组是先装 langchain、langchainhub、httpx_sse,再单独装 langchain-openai;完整安装那组是把这四个包写在同一条 pip 命令里一次装完。
这里有两个包容易被忽略。langchainhub 是后面拉 Agent 提示模板要用的——官方的 Agent 示例里出现了 hub.pull,不装这个包那一行就跑不起来。httpx_sse 则是另一回事:官方把它写进了两组安装命令里,但没有说明它在这条链路上承担什么。智谱在别的文档里单独讲过 SSE 这种调用方式——客户端发起请求后可以流式地实时获取到模型生成的内容直到推理结束,官方推荐用它来做和用户直接交互的场景。不过「装 httpx_sse 就是为了支撑流式」这层因果关系,LangChain 集成页里并没有写,我不替官方补。稳妥的做法是直接照抄那条完整安装命令,四个包一次装齐,省得回头缺哪个补哪个。
langchain-openai 这个包是整条路径的关键。它提供的 ChatOpenAI 才是官方文档里用来承载 GLM 的那个类。这也解释了为什么装依赖那一节的注释直接写着「安装 OpenAI 兼容包」——智谱的这条 LangChain 路线,本质上是复用了 OpenAI 兼容层。关于这层兼容到底覆盖到哪、边界在哪,可以另看 GLM 的 OpenAI 兼容层边界,那篇讲的是同一层机制的另一个侧面。
第三步:拿 Key,并且别把它写进代码
官方给的取 Key 流程是四步:访问智谱开放平台、注册并登录账户、在 API Keys 管理页面创建 Key、复制备用。
接着官方跟了一个提示框,建议把 API Key 设置为环境变量,用 export ZAI_API_KEY=YOUR_API_KEY 的方式替代硬编码到代码里,以提高安全性。这个环境变量名 ZAI_API_KEY 值得记一下,因为它在后面的基础配置示例里被 os.getenv 读了出来,两处是对应的。
要注意官方示例的写法:环境变量是被显式地用 os.getenv("ZAI_API_KEY") 取出来,再传给 openai_api_key 这个参数的。至于 langchain_openai 本身会不会自动去读某个约定名字的环境变量,官方文档里没有找到相关说明。好在示例这种「显式取值再传参」的写法根本不依赖那类隐式约定,跟着抄就不会踩空;变量名你要换成别的也行,只要取出来传进去。真正重要的是别把 Key 字面量留在代码里。Key 的分发、轮换、泄漏后的处置属于跨厂商通用话题,站内另有专门一篇讲这个。
第四步:创建 LLM 实例,四个参数看清楚
官方的「基础配置」示例里,ChatOpenAI 一共传了四个参数:temperature、model、openai_api_key、openai_api_base。同一节给了两种写法,区别只在于 openai_api_key 是写字面量还是走 os.getenv,其余完全一致。
openai_api_base 是这一步的核心。官方示例里填的是智谱开放平台的 v4 接口路径,末尾带斜杠。抄的时候整段复制,别手敲。这个地址由域名、/api/paas/v4/ 这段路径前缀、以及末尾那个斜杠三部分组成,任何一处和官方示例对不上,请求就不是发往你以为的那个端点了。地址写错之后客户端具体会抛出什么错误,官方文档没有说明,所以别指望靠报错信息反推——把你那一行和文档里的示例逐字符比一遍,更快也更可靠。
model 填智谱这边的模型名,官方示例里用的是 GLM 系列的一个具体型号。这里提醒一句:模型名是会随产品迭代变的,你抄示例的时候要以官方文档当前版本和你账号下实际可用的模型列表为准,不要把某个示例里的型号当成永久有效的常量。
temperature 是采样温度。官方在 OpenAI 兼容那一页对参数区间有专门说明,其中一条比较反直觉:temperature 参数的区间是开区间,do_sample = False(也就是 temperature 取 0)在 OpenAI 调用方式下并不适用。换句话说,你在别处养成的「要确定性输出就把温度压到 0」这个习惯,在这条路径上不成立。默认值以官方文档当前版本为准。
第五步:从一次对话到一条链
官方的基础示例是最朴素的形态:from langchain.schema import HumanMessage, SystemMessage,拼一个消息列表,直接把 llm 当可调用对象传进去,然后读 response.content。这写法能跑,但属于 LangChain 的老式用法。
往上一层是提示模板。官方用 ChatPromptTemplate.from_messages 构造模板,里面用花括号占位符写变量,然后用管道符把 prompt 和 llm 串成 chain,最后 chain.invoke 传一个字典进去。需要说清楚的是,官方把「简单对话」「使用提示模板」「对话记忆管理」三个示例并列摆在那里,并没有给出哪种更推荐的排序,下面是我自己的取舍:管道式这一种更值得优先用,因为它把「提示怎么写」和「模型是谁」拆成了两个独立对象,以后换模型只动 llm 那一行,模板一个字都不用碰。另外从示例本身也能看出一点差别——简单对话那段是把消息列表直接传给 llm 调用的,而模板这段走的是 chain.invoke 加一个字典,变量填充的位置从代码里挪到了模板里。
对于 GLM 来说,这个解耦有个额外好处:提示模板的稳定性直接关系到上下文缓存能不能命中。系统提示每次都拼成一样的前缀,和每次都拼得略有不同,在计费上是两回事。这块可以看 GLM 上下文缓存怎么才能命中。
第六步:对话记忆用官方示例里的哪几个类
官方的记忆示例组合了这么几样东西:ChatPromptTemplate 配合 SystemMessagePromptTemplate、MessagesPlaceholder、HumanMessagePromptTemplate 拼出带历史位的模板;ConversationBufferMemory 负责存历史,构造时传了 memory_key 和 return_messages;最后用 LLMChain 把 llm、prompt、memory 串起来,并把 verbose 打开。
这里有一处对应关系必须一致:MessagesPlaceholder 的 variable_name 和 ConversationBufferMemory 的 memory_key 填的是同一个字符串。官方文档没有说明这两处填得不一致会发生什么,所以别去赌它的行为。配之前把两行放在一起对一眼,比事后回来查省事得多。同一段示例里还有一处类似的对应:HumanMessagePromptTemplate 模板里的占位符名字,和后面 conversation.invoke 传进去的那个字典的键,用的也是同一个字符串,改名字的时候要一起改。
官方在实践建议里还提到了一条和记忆直接相关的:用 ConversationBufferWindowMemory 限制历史长度,并定期清理不必要的对话历史、实施对话摘要机制。这条建议对 GLM 尤其要当回事,因为无限增长的对话历史意味着每一轮的输入都在变长,而输入长度是直接影响计费的。一个只跑了几十轮的演示脚本感觉不出来,挂到线上跑一天就很明显了。
第七步:Agent 和自定义工具
官方的 Agent 示例骨架是这样的:从 langchain.agents 导入 AgentExecutor 和 create_react_agent,工具用的是 langchain_community 里的 Tavily 搜索,提示模板通过 hub.pull 从 LangChain Hub 拉一个 react 模板下来,然后 create_react_agent(llm, tools, prompt) 造出 agent,再包进 AgentExecutor 执行。注意这个示例需要单独设置搜索工具自己的密钥环境变量,它和智谱的 Key 是两码事。
自定义工具那一段更实用:用 @tool 装饰器就能把一个普通函数变成工具。官方给的两个例子,函数体第一行都写了一句中文说明,一个是「获取指定城市的天气信息」,一个是「获取股票价格」。文档并没有解释这句说明会被怎么使用,但两个示例一致地这么写,照着给每个工具都补一句意思明确的说明,是零成本的事,没必要省。
还有一处细节值得留意:官方在自定义工具这一段的 AgentExecutor 里额外传了 max_iterations,而前面那个 Tavily 搜索的 Agent 示例里没有传。文档没有解释这个参数的含义,但给 Agent 的执行轮次加一个上界,本身就是通用的工程做法——轮次不封顶,模型调用次数就不封顶,成本自然也没有上界。生产环境里我建议显式设上,而不是依赖任何默认行为。
要说明的是,工具调用在 GLM 上不止这一条路。智谱在自己的 Agent API 文档里把 ReAct 展开成 Reasoning + Acting,描述为一种由模型根据用户问题自主决定是否调用工具的推理引擎;而模型侧还有一条结构化的 function calling 路径,写法完全不同,见 GLM function calling 怎么写。至于 create_react_agent 在实现机制上和 function calling 到底差在哪、在 GLM 上该怎么二选一,LangChain 集成页里没有给出任何对比说明,需要自己按场景权衡。
第八步:打开流式输出
流式在官方示例里是两个参数的事:ChatOpenAI 构造时传 streaming=True,同时在 callbacks 里放一个 StreamingStdOutCallbackHandler。前者控制传输方式,后者决定收到的增量往哪儿吐。示例是往标准输出打,真实应用里你会换成自己的回调,把增量推给前端。
前面提到装包时要装 httpx_sse,原因就在这里。流式响应断在半截怎么办、增量怎么拼回完整文本,属于另一个话题,这里不展开。
官方实践建议里,哪几条是真有用的
文档末尾的实践建议分了性能优化、错误处理、内存管理、安全性四组。抛开泛泛而谈的部分,有三条是可以直接落到代码里的:启用 LangChain 的缓存机制、给请求设置合理的超时时间、实施重试机制和指数退避。
第三条尤其重要。官方「错误处理」那一组一共列了四条:实施重试机制和指数退避、设置合理的超时时间、记录详细的错误日志、提供降级方案。这四条其实是一套连着的:日志决定你事后能不能分辨是哪一类错误,超时和重试决定单次请求怎么收场,降级方案兜住重试也救不回来的那部分请求。文档里没有说明经过 LangChain 这层封装之后,底层的 HTTP 状态码在应用层还能不能原样看到——正因为不确定,「记录详细的错误日志」才不该当成客套话,你事后能拿到多少线索,取决于你在调用处主动记了什么。限流触发之后的退避策略是通用能力,见 遇到 429 该怎么处理。
官方文档没说的部分
诚实交代几处边界,免得你去文档里白找:
第一,这份 LangChain 集成文档只给了 Python 路径,JavaScript/TypeScript 版本的 LangChain 怎么配,官方文档里没有找到相关说明。
第二,通过 ChatOpenAI 这条路径能不能透传 GLM 特有的扩展参数(比如思考模式相关的字段),LangChain 集成页面里没有提及。OpenAI 兼容页面里展示过用 extra_body 传扩展字段的写法,但那是直接用 OpenAI SDK 的示例,不是 LangChain 的,能不能平移过来官方没有说明。
第三,向量检索、Embedding 在 LangChain 里怎么接 GLM,这份文档没有涉及。
第四,官方在文末的备注里说 LangChain 是一个快速发展的框架,建议定期更新到最新版本,并表示会持续优化与 LangChain 的集成。言下之意,上面这些示例的写法本身也有时效性,隔一段时间回去核对一次是必要的。
最容易栽的坑
把前面几节里需要「两处对齐」的地方汇总一遍,配之前逐条核对,比出了问题再回头翻要省事:ConversationBufferMemory 的 memory_key 和 MessagesPlaceholder 的 variable_name 要一致;提示模板里的占位符和 invoke 传进去的字典键要一致;langchain_community 的版本要越过 0.0.32 这道门槛;openai_api_base 要和官方示例逐字符一致,包括末尾那个斜杠;langchainhub 得装上,否则 hub.pull 那一行没法执行。这几处的共同点是:写错了在编辑器里都看不出来,而官方文档也没有说明它们各自会以什么形式暴露出来。
所以配完之后,别急着写业务逻辑。先跑通最朴素的那个单轮对话示例,确认地址和 Key 是通的;再加提示模板,确认变量能填进去;再加记忆,确认第二轮问答里模型确实记得第一轮说了什么;最后才上 Agent。一层一层加,出了问题你知道是刚加的那一层的事。跳着来的话,一个报错背后可能挂着三个原因。