展开本页目录
开始前准备什么
- Python 3.10+;建议为示例单独创建虚拟环境。
- 已创建自己的 apizt API Key,并确认 glm-5.3 权限。
- 能区分普通文字调用与模型供应商特有的 reasoning、文件或内置工具字段。
- 固定依赖
- 显式模型配置
- 运行最小链
- 核对元数据
- 增加能力
2026-10-23 核验材料;实际执行范围、结果与限制见下方记录。
补充:原有练习资料与下载
LCEL 翻译链、usage 与截断检查;无内置 Key。
langchain-openai 1.6.7 / openai 2.54.0。
LangChain:Prompt、模型与解析链实跑
本地LCEL链返回12;真实网关分支429,分别记录通过与阻点。
· 真实LangChain LCEL经本地模型解析JSON7/5/12、退出0;随后同一真实SDK使用apizt HTTPS/gemini-2.5-flash、max_tokens64/max_retries0/timeout30单次请求明确HTTP429当前分组上游饱和,停止且未重投。不能把本地通过当公网网关通过。
已取得下列真实结果;仍有内容质量或功能范围需要按本页检查项复核。
- 运行环境
- langchain-openai1.7.2/langchain-core1.7.0;独立练习目录;原创虚构输入;网关凭据仅置私密环境,未发布Key
1. 固定SDK依赖
在虚拟环境安装langchain-openai,固定完整依赖版本。
2. 显式指定本地调用配置
ChatOpenAI显式设置本地base_url=http://127.0.0.1:11435/v1、model=tutorial-qwen3-proof、api_key=ollama(本地忽略的占位值)。
3. 执行三段LCEL链
把7支蓝笔与5支红笔的原创输入交给PromptTemplate,用LCEL三段链invoke。
4. 解析并核对实际结果
保存真实模型原始字符串、SDK版本与退出码,再独立比较total=12;格式不合规需按失败展示。
5. 单独复核公网接入
切换apizt时必须另行使用其真实Base URL/Key/准确模型ID,不能用本地通过证明公网账户和模型已通过。
6. 保存本次原始结果
公网分支显式ChatOpenAI base_url=https://api.apizt.com/v1,api_key只读环境变量,model=gemini-2.5-flash,max_tokens64、max_retries0、timeout30。本次真实返回429当前分组上游饱和;保存错误requestID并停止,输出token上限不是费用上限。
这次实际得到什么
- 本地真实LCEL链返回并解析blue7/red5/total12,exit0。
- 真实apizt HTTPS/gemini-2.5-flash、max_retries0请求明确HTTP429当前分组上游饱和。
- 公网路径已停止,本地通过不等于公网通过。
使用这份结果时注意
- 只说明当前测试Key/分组/模型这一时点;不是全站不可用诊断。
- 输出token上限不是费用上限;未验证公网成功生成或工具能力。
固定依赖和运行环境
此示例固定 langchain-openai==1.6.7 与 openai==2.54.0,适配包声明 Python >=3.10。下载两个文件后,在虚拟环境安装依赖并设置自己的 Key。tokenba_MODEL 可覆盖默认模型,tokenba_BASE_URL 可用于测试目标地址。
这里用自己的 tokenba_* 变量,并显式传入构造器,避免同时存在 OPENAI_API_BASE 与 OPENAI_BASE_URL 时产生地址覆盖。不要在仓库中保存实际 Key。
terminal
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -r framework-langchain-requirements.txt
export tokenba_API_KEY="YOUR_tokenba_API_KEY"
python framework-langchain.py完整示例:保留数字的翻译链
ChatPromptTemplate 把输入映射为 system 与 human 消息,LCEL 的 prompt | model 返回 AIMessage。先保留这个对象,以便检查 usage_metadata 和 finish_reason;如果马上转成纯字符串,会丢掉这里需要核对的元数据。
默认 glm-5.3 的样例把 max_tokens 放进 extra_body 控制试跑输出预算。当前 ChatOpenAI 会转换普通 max_tokens 参数,因此不要照抄其他型号的 token 参数;换模型时核对实际请求体与通道要求。
framework-langchain.py
import os
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
def main():
model = ChatOpenAI(
api_key=os.environ["tokenba_API_KEY"],
base_url=os.getenv("tokenba_BASE_URL", "https://api.apizt.com/v1"),
model=os.getenv("tokenba_MODEL", "glm-5.3"),
use_responses_api=False,
stream_usage=False,
timeout=60,
max_retries=0,
extra_body={"max_tokens": 1024},
)
prompt = ChatPromptTemplate.from_messages([
("system", "你是产品文案编辑。保持数字与型号原样,只翻译给定文本。"),
("human", "翻译成中文:{text}"),
])
result = (prompt | model).invoke({"text": "Plan A includes 100 requests per day."})
print("answer:", result.content)
print("usage:", result.usage_metadata)
print("finish_reason:", result.response_metadata.get("finish_reason"))
if not isinstance(result.content, str) or not result.content.strip():
raise RuntimeError("未收到文字答案;先检查模型、协议和通道。")
if result.response_metadata.get("finish_reason") == "length":
raise RuntimeError("输出被截断;先核对账单,再调整输出预算。")
if __name__ == "__main__":
main()明确走 Chat,而不是由功能隐式换协议
use_responses_api=False 明确选 Chat Completions,适合这条基础文字链。添加 Responses 内置工具、previous_response_id 或文件能力后,请按迁移教程验证 /responses;同一个地址前缀不能证明两个端点都可用。
ChatOpenAI 主要面向官方 OpenAI 格式。第三方响应里的 reasoning_content、reasoning_details 等扩展字段不保证被保留。需要这些信息时,采用能处理该字段的供应商集成,或对照原始响应自行适配,不能把缺失字段当作模型没有推理。
流式先验收结束,再采集 usage
基本请求成功后,可以使用 model.stream(messages) 逐段读取消息。先保留全部 chunk、结束状态和异常,确认中文没有断字、最后一段完整。流式 usage 是否存在取决于实际端点。
当前样例 stream_usage=False。如果当前通道已经支持 stream_options.include_usage,再显式改为 True 并验证最终 usage chunk。缺失 usage 应标记未知,不使用零值填补。
streaming-check.py · 在已有 model 后使用
messages = [("human", "用两条要点解释 API 请求验收。") ]
complete = None
for chunk in model.stream(messages):
complete = chunk if complete is None else complete + chunk
if isinstance(chunk.content, str):
print(chunk.content, end="", flush=True)
print()
if complete is None:
raise RuntimeError("没有收到任何 chunk")
print("finish_reason:", complete.response_metadata.get("finish_reason"))
print("usage:", complete.usage_metadata)工具与 Schema 逐项增加
| 需求 | LangChain 接入点 | 额外验收 |
|---|---|---|
| 函数工具 | bind_tools | 工具参数可解析,执行结果以正确 tool_call_id 回传。 |
| 结构化字段 | with_structured_output | 确认使用的 method,再校验类型、必填项和拒绝响应。 |
| RAG | Retriever → Prompt → Model | 引用真实片段,控制召回与历史预算,缺证据时拒答。 |
| Responses 能力 | 单独配置并验证 | /responses、状态保留与内置工具支持逐项检查。 |
- 需求
- 函数工具
- LangChain 接入点
- bind_tools
- 额外验收
- 工具参数可解析,执行结果以正确 tool_call_id 回传。
- 需求
- 结构化字段
- LangChain 接入点
- with_structured_output
- 额外验收
- 确认使用的 method,再校验类型、必填项和拒绝响应。
- 需求
- RAG
- LangChain 接入点
- Retriever → Prompt → Model
- 额外验收
- 引用真实片段,控制召回与历史预算,缺证据时拒答。
- 需求
- Responses 能力
- LangChain 接入点
- 单独配置并验证
- 额外验收
- /responses、状态保留与内置工具支持逐项检查。
先检查请求,再更换框架配置
| 现象 | 检查项 | 恢复动作 |
|---|---|---|
| 请求去了 api.openai.com | 构造器是否显式传入 base_url、是否用了另一个 model 实例 | 打印不含 Key 的目标前缀,消除环境变量覆盖。 |
| 401 / model not found | Key 与精确 model | 对照控制台权限与模型目录。 |
| unsupported max_completion_tokens | 最终请求体与所选型号参数 | 样例使用 extra_body 的 max_tokens;不要同时提交两种上限。 |
| 流式有文字但 usage 为空 | 通道是否支持 include_usage | 保留未知 usage,对照控制台调用记录。 |
| 超时后又生成了一次 | SDK、链外层或调用者的重试 | 首调 max_retries=0;查账后再决定重新提交。 |
| reasoning 字段不见了 | 是否为供应商扩展字段 | 不要当成普通 content,使用适配器或保存脱敏原始响应。 |
- 现象
- 请求去了 api.openai.com
- 检查项
- 构造器是否显式传入 base_url、是否用了另一个 model 实例
- 恢复动作
- 打印不含 Key 的目标前缀,消除环境变量覆盖。
- 现象
- 401 / model not found
- 检查项
- Key 与精确 model
- 恢复动作
- 对照控制台权限与模型目录。
- 现象
- unsupported max_completion_tokens
- 检查项
- 最终请求体与所选型号参数
- 恢复动作
- 样例使用 extra_body 的 max_tokens;不要同时提交两种上限。
- 现象
- 流式有文字但 usage 为空
- 检查项
- 通道是否支持 include_usage
- 恢复动作
- 保留未知 usage,对照控制台调用记录。
- 现象
- 超时后又生成了一次
- 检查项
- SDK、链外层或调用者的重试
- 恢复动作
- 首调 max_retries=0;查账后再决定重新提交。
- 现象
- reasoning 字段不见了
- 检查项
- 是否为供应商扩展字段
- 恢复动作
- 不要当成普通 content,使用适配器或保存脱敏原始响应。
本次补测:先完成搜索要解决的问题,再进入下一步
设置 timeout 不等于只请求一次;框架和 SDK 重试叠加可能增加费用。
补测安装并运行 OpenAI SDK 的本地负例;没有把它说成 LangChain 新版本原生通过。
- 保留固定版本与完整 AIMessage,不要立刻转成纯文本。
- 先显式关闭框架和底层客户端自动重试,再用本地429 fixture统计请求次数。
- 对照真实成功请求的 request ID、model、usage;本地429不能写成 apizt 当次真实故障。
新增补测结果;与原有原生工具记录分别保存
{
"local_sdk_requests": 1,
"live_tokenba_http": 200,
"max_retries": 0
}怎样确认已经完成
- 翻译保留了 100 和 Plan A,答案非空且不是 length 截断。
- 读取 AIMessage 后再进入纯文字处理,usage 缺失不当成零。
- 模型、目标前缀和 Chat 协议是显式配置。
- 每次重试都记录,框架执行成功与实扣分开核对。
常见问题
ChatOpenAI 支持自定义 base_url 就代表所有模型能力都支持吗?
不代表。基础消息格式可兼容,供应商扩展字段、原生工具、缓存与文件参数需要另外适配。模型官方能力、网关支持和框架解析是三个独立环节。
LangChain 需要单独的 OpenAI Key 吗?
该自定义地址样例使用自己的 apizt API Key。显式传入 api_key 与 base_url,不需要把 apizt Key 配到官方 OpenAI 平台。
为什么默认关闭重试?
用于首调验收,便于确认一次请求产生的输出与费用。生产重试需有次数上限、错误分类和任务记录;超时并不证明服务端没有执行。

