之前有介绍过ChatModels,但对于10月20日新更新的LangChain1.0.0+版本后,对于Models模型这里也有了很大的调整,以下我则进行详细介绍。
大型语言模型(LLM)是强大的 AI 工具,能够像人类一样解释和生成文本。它们功能多样,可以撰写内容、翻译语言、总结和回答问题,而无需针对每个任务进行专门训练。很多模型都支持一下功能:
文本生成 :LLMs能够生成类似人类书写的文本,可以用于写作内容、翻译语言、总结文本以及回答问题,且无需针对每个任务进行专门的训练。
工具调用 :许多模型支持调用外部工具,例如执行数据库查询或API调用,并将结果用于其响应中。这使得模型能够获取和处理外部数据,从而提供更准确和丰富的回答。
结构化输出 :模型可以按照预定义的格式生成响应,这有助于确保输出可以被后续处理流程轻松解析和使用。
多模态处理 :除了文本,一些模型还能够处理和返回其他类型的数据,如图像、音频和视频。这使得模型能够更全面地理解和生成信息。
推理能力 :模型能够执行多步推理以得出结论,这有助于解决复杂的、需要逐步分析的问题。
模型是智能体的推理引擎。它们驱动代理的决策过程,确定调用哪些工具、如何解释结果以及何时提供最终答案。您选择的模型的质量和能力直接影响代理的可靠性和性能。不同的模型擅长不同的任务——有些更擅长遵循复杂指令,有些更擅长结构化推理,有些支持更大的上下文窗口来处理更多信息。
Model模块的核心价值 提供了统一的接口来连接和使用各大语言模型(LLM)。
它主要解决了大模型应用开发中的几个关键挑战:
统一接口 :提供一致的调用方式,屏蔽 OpenAI、Anthropic、Google 等不同模型提供商的差异。
灵活配置 :支持精细调整模型参数(如温度、最大 tokens),控制输出的风格和随机性。
多种能力 :支持文本生成、工具调用、结构化输出等多种功能,满足不同场景需求。
易于切换 :可以轻松在不同模型之间切换,而不需要修改应用的整体架构,降低了迁移成本。
模型初始化 直接创建模型对象 这个是保留了之前ChatModels调用的方式,比如使用langchain_openai中的ChatOpenAI
1 2 3 4 5 6 7 from langchain_openai import ChatOpenAImodel = ChatOpenAI( model=os.getenv("llm_model" ), base_url=os.getenv("base_url" ), api_key=os.getenv("api_key" ), )
使用init_chat_model init_chat_model是 langchian 中封装的一个模型初始化方法,可用于快速对模型进行初始化,其内部还是调用相关的第三方库来初始化模型,也需要安装对应大模型接入的模型
官方文档详细介绍:https://reference.langchain.com/python/langchain/models/
1 2 3 4 5 6 7 8 9 from langchain.chat_models import init_chat_modelmodel = init_chat_model( model=os.getenv("llm_model" ), model_provider ="openai" , base_url=os.getenv("base_url" ), api_key=os.getenv("api_key" ) )
这种方式内置了很多模型调用在使用的时候,可以进行简化调用
1 2 3 4 5 from langchain.chat_models import init_chat_modelos.environ["DEEPSEEK_API_KEY" ] = os.getenv("api_key" ) model = init_chat_model("deepseek:deepseek-chat" )
模型参数配置
参数名
作用
范围 / 默认值
temperature
控制输出的随机性:值越高,输出越随机、有创造性;值越低,输出越确定、保守。
0.0–2.0,默认通常为 0.7
max_tokens
限制生成的最大 token 数量,控制回复长度。
不同模型有不同上限
timeout
设置请求超时时间(秒),防止请求无限等待。
默认通常为 30 秒
max_retries
设置请求失败时的最大重试次数。
默认通常为 2 或 3 次
model_provider
指定模型提供商(如 openai、anthropic),对自定义或非标命名模型尤其重要。
无默认值,非标模型必须显式指定
api_key / token
模型 API 的访问密钥,用于身份验证;如不提供,会尝试从环境变量读取。
—
base_url
指定 API 基础 URL,用于连接自定义部署的模型服务或代理服务器。
默认为各提供商的官方 API 地址
示例
1 2 3 4 5 6 7 8 model = init_chat_model( "claude-sonnet-4-5-20250929" , model_provider="anthropic" , temperature=0.3 , max_tokens=1500 , timeout=45 , max_retries=3 )
模型调用 1.invoke非流式
单条消息调用
1 2 response = model_client.invoke("今天天气如何" ) print (response)
多条消息调用
1 2 3 4 5 6 7 8 9 conversation = [ {"role" : "system" , "content" : "You are a helpful assistant that translates English to French." }, {"role" : "user" , "content" : "Translate: I love programming." }, {"role" : "assistant" , "content" : "J'adore la programmation." }, {"role" : "user" , "content" : "Translate: I love building applications." } ] response = model_client.invoke(conversation) print (response)
2. stream流式 流式传输(Streaming)功能
定义 :大多数模型可以在生成输出内容的过程中,逐步将内容以流的形式发送出来,而不是等到整个输出内容完全生成后再一次性返回。这种逐步生成并发送输出内容的方式被称为流式传输。
优势 :通过流式传输,用户可以实时看到模型生成的输出内容,尤其是在生成较长的响应时,这种实时性可以显著提升用户体验。例如,当模型正在生成一个长篇回答时,用户可以逐步看到回答的内容,而不是等待很长时间后一次性看到完整的回答。
1 2 for chunk in model.stream("Why do parrots have colorful feathers?" ): print (chunk.text, end="|" , flush=True )
在这段代码中,model.stream() 方法被用来调用模型,并传入一个查询字符串(如 “Why do parrots have colorful feathers?”)。返回的迭代器 chunk 包含了模型逐步生成的输出内容。通过循环,每次迭代都会获取一个输出片段 chunk.text,并将其打印出来。end=”|” 参数用于在每个输出片段之间添加一个分隔符(如 “|”),以便更清楚地看到输出内容的逐步生成过程。flush=True 参数确保每次打印的内容都能立即显示,而不是等到缓冲区满后再显示。
3.batch批量消息非流式 将多个独立的请求批量发送给一个模型,可以显著提升性能并降低成本,因为这些请求的处理可以并行 进行。
1 2 3 4 5 6 7 responses = model.batch([ "你是谁" , "今天是几月几日" , ]) for response in responses: print (response)
4.batch_as_completed批量消息流式 1 2 3 4 5 for response in model.batch_as_completed([ "你是谁" , "今天是几月几日" , ]): print (response)
Model Profiles 介绍 1. 功能定位 Model Profiles 是 LangChain 1.1 的重要改进,它允许聊天模型通过 .profile 属性,公开其支持的功能和能力 ,让应用程序可以动态感知模型的能力边界。
2. 核心价值
动态能力检测 :应用程序可以自动检测模型支持的功能(如是否支持工具调用、结构化输出等),无需在代码中硬编码这些信息,提升了灵活性。
统一信息来源 :这些能力数据来自 https://models.dev/ 这个开源项目,保证了信息的准确性和权威性,避免了开发者手动维护模型能力列表的麻烦。
自适应应用开发 :应用可以根据模型的实际能力动态调整行为,比如在不支持工具调用的模型上自动降级为纯文本交互,从而提供更好的兼容性和用户体验。
简单来说,Model Profiles 让 LangChain 应用变得更 “聪明”,它能自动知道 “这个模型能做什么”,而不是开发者手动告诉它,从而让代码更健壮、更易于维护。
核心应用场景总览 该功能的核心目标是让 AI 应用具备 “模型感知能力” ,不再按固定逻辑开发,而是根据调用模型的实际能力动态调整执行策略,实现兼容性、效率与成本的最优平衡。
动态能力检测
核心痛点 :开发时硬编码了工具调用、函数调用等功能,若切换到不支持该能力的轻量级模型,会直接报错。
功能价值 :应用启动或模型切换时,自动检测当前模型是否支持目标功能(如工具调用、多模态输入),若不支持则自动屏蔽或降级处理,避免程序异常。
自适应摘要策略
核心痛点 :不同模型的上下文窗口大小差异极大(如小模型 4k、大模型 128k),固定执行摘要步骤会造成资源浪费或输入超限。
功能价值 :根据 Model Profiles 读取的模型上下文窗口大小,自动决策:窗口足够大则直接输入完整文本,窗口不足则先执行文本摘要步骤,适配不同模型的输入限制。
智能输出格式选择
核心痛点 :部分模型支持原生 JSON 结构化输出,部分仅支持纯文本,固定用一种方式会导致解析失败或开发冗余。
功能价值 :自动识别模型是否支持原生结构化输出,支持则直接请求 JSON 格式(无需额外解析),不支持则通过提示词引导输出并适配文本解析逻辑,提升输出处理的准确性。
输入内容适配
核心痛点 :多模型开发中,部分模型仅支持文本输入,部分支持图文混合,且最大输入 token 数不同,固定输入格式会导致调用失败。
功能价值 :结合模型的模态支持能力 和最大输入限制 ,动态调整输入内容:过滤非支持模态的内容(如图像),并对超长文本进行裁剪或压缩,确保输入符合模型要求。
资源优化利用
核心痛点 :对所有任务都使用高算力、高成本的旗舰模型,造成资源浪费;用轻量级模型处理复杂任务,又会导致效果不佳。
功能价值 :根据模型能力分级匹配任务策略:简单任务(如文本分类)调用轻量级模型并采用基础算法,复杂任务(如逻辑推理)调用旗舰模型并启用高级策略,在保证效果的同时优化算力资源利用率。
场景总结
这些场景本质上围绕 “动态适配” 展开,Model Profiles 作为 “模型能力说明书”,让 LangChain 应用从 “静态硬编码” 升级为 “动态自适应”,大幅降低了多模型项目的开发维护成本,同时实现了资源的精细化利用。
Model Profiles的使用 核心使用流程
初始化模型
1 2 from langchain.chat_models import init_chat_modelmodel = init_chat_model("claude-sonnet-4-5-20250929" , model_provider="anthropic" )
这一步和普通的模型初始化没有区别,只是在 LangChain 1.1+ 中,返回的模型实例会自动带有 .profile 属性
访问 Model Profile
直接访问 .profile 即可得到一个包含该模型所有能力信息的字典 / 对象,里面的键就是各种能力标识,值是布尔值或具体数值。
读取具体能力
通过 profile.get('key') 的方式读取了多种能力,包括:
输入 / 输出限制:max_input_tokens、max_output_tokens
多模态支持:image_inputs、audio_inputs、video_inputs 等
功能支持:tool_calling、structured_output、reasoning_output 等
特殊输入支持:image_url_inputs、pdf_inputs 等
代码示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 """ LangChain 1.1+ Model Profiles 完整使用示例 功能:演示如何获取模型能力信息,并基于能力动态调整应用逻辑 前置条件: 1. 安装依赖:pip install langchain langchain-anthropic python-dotenv 2. 创建 .env 文件,配置 ANTHROPIC_API_KEY=你的密钥 """ import osfrom dotenv import load_dotenvfrom langchain.chat_models import init_chat_modelfrom langchain.schema import HumanMessage, SystemMessagefrom langchain.text_splitter import RecursiveCharacterTextSplitterload_dotenv() ANTHROPIC_API_KEY = os.getenv("ANTHROPIC_API_KEY" ) if not ANTHROPIC_API_KEY: raise ValueError("请在 .env 文件中配置 ANTHROPIC_API_KEY" ) def init_model_with_profile (model_name: str = "claude-sonnet-4-5-20250929" ): """ 初始化模型并获取其能力配置文件 """ model = init_chat_model( model=model_name, model_provider="anthropic" , temperature=0.3 , max_tokens=1000 , api_key=ANTHROPIC_API_KEY ) model_profile = model.profile print ("=" *80 ) print (f"模型 {model_name} 的能力配置:" ) print ("=" *80 ) print ("\n【输入输出限制】" ) print (f"- 最大输入 Token 数: {model_profile.get('max_input_tokens' , '未知' )} " ) print (f"- 最大输出 Token 数: {model_profile.get('max_output_tokens' , '未知' )} " ) print ("\n【多模态支持】" ) print (f"- 支持图片输入: {model_profile.get('image_inputs' , False )} " ) print (f"- 支持音频输入: {model_profile.get('audio_inputs' , False )} " ) print (f"- 支持视频输入: {model_profile.get('video_inputs' , False )} " ) print (f"- 支持图片URL输入: {model_profile.get('image_url_inputs' , False )} " ) print ("\n【核心功能支持】" ) print (f"- 支持工具调用: {model_profile.get('tool_calling' , False )} " ) print (f"- 支持结构化输出: {model_profile.get('structured_output' , False )} " ) print (f"- 支持推理输出: {model_profile.get('reasoning_output' , False )} " ) print ("\n【文件输入支持】" ) print (f"- 支持PDF输入: {model_profile.get('pdf_inputs' , False )} " ) return model, model_profile def adaptive_text_processing (model, model_profile, text: str ): """ 根据模型能力动态处理文本: 1. 如果模型输入限制不足,自动分割文本 2. 如果支持结构化输出,直接请求JSON格式 3. 否则返回纯文本 """ print ("\n" + "=" *80 ) print ("开始自适应文本处理..." ) print ("=" *80 ) text_length = len (text) estimated_tokens = text_length * 2 max_input_tokens = model_profile.get('max_input_tokens' , 4096 ) print (f"\n原始文本长度: {text_length} 字符 (估算 {estimated_tokens} tokens)" ) print (f"模型最大输入限制: {max_input_tokens} tokens" ) processed_text = text if estimated_tokens > max_input_tokens: print ("\n⚠️ 文本长度超过模型输入限制,自动分割..." ) text_splitter = RecursiveCharacterTextSplitter( chunk_size=int (max_input_tokens * 0.8 ), chunk_overlap=50 , length_function=lambda x: len (x) * 2 ) chunks = text_splitter.split_text(text) print (f"文本已分割为 {len (chunks)} 个片段" ) processed_text = chunks[0 ] messages = [ SystemMessage(content="你是一个专业的文本分析助手" ), HumanMessage(content=f"分析以下文本的核心观点:{processed_text} " ) ] if model_profile.get('structured_output' , False ): print ("\n✅ 模型支持结构化输出,请求JSON格式..." ) messages.append(HumanMessage(content="请以JSON格式返回,包含字段:核心观点、关键论据、总结" )) else : print ("\nℹ️ 模型不支持结构化输出,返回纯文本..." ) response = model.invoke(messages) print ("\n📝 模型输出结果:" ) print (response.content) return response if __name__ == "__main__" : model, profile = init_model_with_profile() test_text = """ LangChain 1.1 引入的 Model Profiles 功能是一项重要的升级,它允许开发者在运行时动态获取模型的能力信息。 这一功能解决了多模型开发中的核心痛点:不同模型的能力差异大,硬编码逻辑容易导致兼容性问题。 通过 Model Profiles,应用可以自动检测模型是否支持工具调用、结构化输出、多模态输入等能力, 并根据这些信息自适应调整处理策略,比如自动分割超长文本、选择输出格式等, 最终提升应用的兼容性和资源利用效率。 """ adaptive_text_processing(model, profile, test_text)
修改 Model Profile 数据 快速修复:直接传入自定义 Profile 在初始化模型时,通过 profile 参数直接传入一个自定义的字典,覆盖默认的能力数据:
1 2 3 4 5 6 7 8 custom_profile = { "max_input_tokens" : 100_000 , "tool_calling" : True , "structured_output" : True , } model = init_chat_model("..." , profile=custom_profile)
这种方式适合在模型初始化时就明确知道其能力,或需要快速覆盖默认数据的场景。
Model Profile 本质是一个普通字典,可以直接修改,但如果模型实例被共享,直接修改会影响所有使用者,因此推荐使用 model_copy 来创建副本并更新:
1 2 3 4 5 new_profile = model.profile | {"key" : "value" } model = model.model_copy(update={"profile" : new_profile})
这种方式更安全,适合在多线程、多实例或共享模型的场景中使用,确保状态隔离。
上游修复:从源头更新和维护 Profile 数据
数据来源与更新流程
Model Profile 的核心数据来自 models.dev 开源项目,LangChain 会在此基础上合并额外字段和覆盖规则,随包发布。更新流程分为三步:
更新源数据 :向 GitHub 上的 models.dev 仓库提交 PR,修正或补充模型能力数据。
更新增强配置 :向对应 LangChain 集成包提交 PR,修改 langchain_<package>/data/profile_augmentations.toml,添加额外字段或覆盖规则。
拉取并合并数据 :使用 langchain-model-profiles CLI 工具,从 models.dev 拉取最新数据,与本地增强配置合并,生成最终的 profiles.py 文件。
CLI 工具使用
安装工具
1 pip install langchain-model-profiles
执行刷新命令
1 langchain-profiles refresh --provider <provider> --data-dir <data_dir>
这个命令会:
从 models.dev 下载指定提供商(如 anthropic)的最新模型能力数据
合并 <data_dir> 中 profile_augmentations.toml 的增强内容
将合并后的配置写入 <data_dir> 中的 profiles.py
示例
在 LangChain 单体仓库的 libs/partners/anthropic 目录中:
1 uv run --with langchain-model-profiles --provider anthropic --data-dir .
这条命令会为 Anthropic 模型刷新最新的 Profile 数据。
核心要点
上游修复 vs 临时修改 :
临时修改(Option 1)适合快速解决应用内的问题,但只影响当前应用实例。
上游修复(Option 2)适合从根本上修正数据,让所有使用该模型的应用都受益。
维护者角色 :这个流程主要面向 LangChain 集成包的维护者,而不是普通应用开发者。
数据准确性 :通过 models.dev 和 CLI 工具,保证了 Profile 数据的准确性和时效性。
Model Profiles的注意点与价值 Model Profiles 的注意点
滞后性问题
Model Profiles 的数据依赖 models.dev 和 LangChain 集成包的更新,当模型提供商快速迭代新能力时,相关能力数据可能存在延迟,导致 Profile 信息与模型实际能力不一致。
核心属性已知性
对于专业开发者来说,在选型特定模型时,通常已经明确其核心属性(如上下文窗口大小、是否支持工具调用等),此时动态检测的必要性会降低,甚至可能增加不必要的开销。
Model Profiles 的潜在价值
动态模型选择
当应用需要根据用户需求、成本或性能条件动态切换模型时,Model Profiles 提供了统一接口来查询不同模型的能力,让系统可以自动选择最适合当前任务的模型。
跨模型兼容性
在需要同时支持多种模型提供商或模型变体的应用中,Model Profiles 可以抽象掉底层差异,让开发者无需为每个模型编写单独的适配逻辑。
自动适配策略
对于中间件或框架组件(如摘要中间件、路由组件),Model Profiles 提供了标准化的能力检测机制,让这些组件可以根据模型能力自动调整处理策略(如自动分割超长文本、选择输出格式)。
降低入门门槛
对于不熟悉特定模型细节的新手开发者,Model Profiles 提供了便捷的参考,让他们可以快速了解模型能力,减少查阅文档的成本,更快上手开发。
总结 Model Profiles 不是 “银弹”,它更适合多模型、动态切换、框架级开发 的场景,而在固定模型、专业开发的场景下,其价值会相对有限。开发者需要根据项目的实际需求,理性评估是否使用该功能。
模型结果结构化输出 我们可以要求模型以符合给定模式的格式提供其响应。这对于确保输出能够轻松解析并在后续处理中使用非常有用。LangChain 支持多种模式类型和强制结构化输出的方法。
例如,以下是以生产测试用例的大模型调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 from src.core.llms import model_clientmessage = [ {"role" : "user" , "content" : """ 请根据以下需求文档,生成3条正向的测试用例 📌 F1.3 用户信息修改 🧩 功能背景 用户可修改昵称、密码、头像、性别等基础信息。 🚶 主流程 1. 用户进入“个人中心” 2. 修改某字段并保存 3. 系统校验内容合法性(如昵称长度、头像格式) 4. 修改成功后刷新显示 ⚠ 异常流程 用户未登录:提示登录后操作 输入非法字符:提示不符合规范 📌 业务规则 昵称长度大于3 小于20,支持中英文 性别只能为“男 / 女 / 保密” 头像图片限制大小(2M以内),格式为 png/jpg/jpeg """ }] result = model_client.invoke(message) print (result.content)
输出内容为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 根据您提供的需求文档,以下是3条正向测试用例: --- ### **测试用例1:修改昵称(合法边界值)** * **用例ID:** TC_F1.3_001 * **用例标题:** 成功修改昵称为合法长度(4个字符) * **前置条件:** 1. 用户已登录。 2. 用户已进入“个人中心”页面。 * **测试步骤:** 1. 在昵称输入框中,输入一个长度为4个字符的昵称(例如:“测试昵”)。 2. 点击“保存”按钮。 * **预期结果:** 1. 系统提示“修改成功”。 2. 页面刷新后,显示的昵称更新为“测试昵”。 --- ### **测试用例2:修改性别(选择“女”)** * **用例ID:** TC_F1.3_002 * **用例标题:** 成功将性别修改为“女” * **前置条件:** 1. 用户已登录。 2. 用户已进入“个人中心”页面。 * **测试步骤:** 1. 在性别选择区域,选择“女”。 2. 点击“保存”按钮。 * **预期结果:** 1. 系统提示“修改成功”。 2. 页面刷新后,显示的性别更新为“女”。 --- ### **测试用例3:修改头像(上传合规图片)** * **用例ID:** TC_F1.3_003 * **用例标题:** 成功上传符合格式和大小限制的头像 * **前置条件:** 1. 用户已登录。 2. 用户已进入“个人中心”页面。 * **测试步骤:** 1. 点击“更换头像”按钮。 2. 从本地选择一张格式为JPG、大小为1.5M的图片。 3. 点击“保存”按钮。 * **预期结果:** 1. 系统提示“修改成功”。 2. 页面刷新后,显示的头像更新为新上传的图片。
是自然语言输出的,那么我想把以上的内容进行JSON格式的输出,要怎么做呢?
1. 使用 json Schme 来规范输出格式 JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,而 JSON Schema 是对 JSON 数据结构进行描述和约束的一种规范,用于定义 JSON 数据的结构、类型、格式等规则,以确保数据的正确性和一致性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 from src.core.llms import model_clientmessage = [ {"role" : "user" , "content" : """ 请根据以下需求文档,生成3条正向的测试用例 📌 F1.3 用户信息修改 🧩 功能背景 用户可修改昵称、密码、头像、性别等基础信息。 🚶 主流程 1. 用户进入“个人中心” 2. 修改某字段并保存 3. 系统校验内容合法性(如昵称长度、头像格式) 4. 修改成功后刷新显示 ⚠ 异常流程 用户未登录:提示登录后操作 输入非法字符:提示不符合规范 📌 业务规则 昵称长度大于3 小于20,支持中英文 性别只能为“男 / 女 / 保密” 头像图片限制大小(2M以内),格式为 png/jpg/jpeg """ }] json_schema = { "title" : "TestCase" , "description" : "测试用例" , "type" : "object" , "properties" : { "id" : { "type" : "string" , "description" : "用例编号" }, "name" : { "type" : "string" , "description" : "测试用例名称" }, "steps" : { "type" : "array" , "items" : { "type" : "string" }, "description" : "测试步骤列表" }, "expected" : { "type" : "array" , "items" : { "type" : "string" }, "description" : "预期结果断言列表" } }, "required" : ["id" , "name" , "steps" , "expected" ] } model_with_structure = model_client.with_structured_output( json_schema, method="json_schema" , ) result = model_with_structure.invoke(message) print ("类型:" , type (result))print ("************************************结果****************************" )print (result)
输出内容
1 2 3 4 类型: <class 'dict'> ************************************结果**************************** {'id': 'TC-F1.3-001', 'name': '修改用户昵称-正向测试', 'steps': ['1. 用户登录系统', '2. 进入个人中心页面', '3. 点击昵称修改按钮', "4. 输入新的昵称'张三测试'(长度4-20字符)", '5. 点击保存按钮'], 'expected': ['1. 系统校验昵称长度符合要求(大于3小于20)', '2. 系统校验昵称支持中英文', "3. 修改成功后页面刷新显示新昵称'张三测试'", '4. 系统提示修改成功']}
输出的是一个字典,这时可以根据字典进行数据转换等操作。
2. 使用pydantic(推荐方式) Pydantic 模型具有非常强大的功能。具体来说:
字段验证:它能够对数据的各个字段进行验证,确保数据的准确性和完整性,比如检查数据类型是否正确、格式是否符合要求等。
描述:可以为模型中的字段添加描述信息,这有助于更好地理解和使用模型,方便开发人员了解每个字段的含义和用途。
嵌套结构:支持构建嵌套的数据结构,即一个模型中可以包含其他模型作为其字段,这样可以更灵活地组织和表示复杂的数据关系。
Pydantic模型能提供自动验证功能,而TypedDict和JSON Schema则需要手动进行验证。
基础使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 from src.core.llms import model_clientmessage = [ {"role" : "user" , "content" : """ 请根据以下需求文档,生成3条正向的测试用例 📌 F1.3 用户信息修改 🧩 功能背景 用户可修改昵称、密码、头像、性别等基础信息。 🚶 主流程 1. 用户进入“个人中心” 2. 修改某字段并保存 3. 系统校验内容合法性(如昵称长度、头像格式) 4. 修改成功后刷新显示 ⚠ 异常流程 用户未登录:提示登录后操作 输入非法字符:提示不符合规范 📌 业务规则 昵称长度大于3 小于20,支持中英文 性别只能为“男 / 女 / 保密” 头像图片限制大小(2M以内),格式为 png/jpg/jpeg """ }] from typing import List from pydantic import BaseModel, Fieldclass CaseItem (BaseModel ): id : str = Field(..., description="用例编号" ) name: str = Field(..., description="测试用例名称" ) steps: List [str ] = Field(..., description="测试步骤列表" ) expected: List [str ] = Field(..., description="预期结果断言列表" ) model_with_structure = model_client.with_structured_output(CaseItem) result = model_with_structure.invoke(message) print (type (result))print ("************************************结果****************************" )print (result.model_dump())
输出结果
1 2 3 <class '__main__.CaseItem'> ************************************结果**************************** {'id': 'F1.3-TC-001', 'name': '用户修改昵称-正向测试', 'steps': ['1. 用户已登录并进入个人中心页面', '2. 点击昵称编辑按钮', "3. 输入合法的昵称'张三用户'(长度4-20个字符)", '4. 点击保存按钮'], 'expected': ['1. 系统校验昵称长度符合要求(大于3小于20)', '2. 系统校验昵称内容支持中英文', "3. 修改成功后页面刷新显示新的昵称'张三用户'", '4. 页面显示修改成功提示']}
输出的是一个CaseItem对象,对于厚度数据的内容就更好的处理
嵌套输出 如果生成多条数据或者数据中有字段嵌套,可以使用 pydantic 模型类定义字段时指定字段嵌套来实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 from src.core.llms import model_clientmessage = [ {"role" : "user" , "content" : """ 请根据以下需求文档,生成3条正向的测试用例 📌 F1.3 用户信息修改 🧩 功能背景 用户可修改昵称、密码、头像、性别等基础信息。 🚶 主流程 1. 用户进入“个人中心” 2. 修改某字段并保存 3. 系统校验内容合法性(如昵称长度、头像格式) 4. 修改成功后刷新显示 ⚠ 异常流程 用户未登录:提示登录后操作 输入非法字符:提示不符合规范 📌 业务规则 昵称长度大于3 小于20,支持中英文 性别只能为“男 / 女 / 保密” 头像图片限制大小(2M以内),格式为 png/jpg/jpeg """ }] from typing import List from pydantic import BaseModel, Fieldclass CaseItem (BaseModel ): id : str = Field(..., description="用例编号" ) name: str = Field(..., description="测试用例名称" ) steps: List [str ] = Field(..., description="测试步骤列表" ) expected: List [str ] = Field(..., description="预期结果断言列表" ) class CaseList (BaseModel ): cases: List [CaseItem] model_with_structure = model_client.with_structured_output(CaseList) result = model_with_structure.invoke(message) print (type (result))print ("************************************结果****************************" )print (result.model_dump())
输出结果
1 2 3 <class '__main__.CaseList'> ************************************结果**************************** {'cases': [{'id': 'TC-F1.3-001', 'name': '修改昵称-正向测试', 'steps': ['用户登录系统', '进入个人中心页面', '点击昵称编辑按钮', '输入符合规范的昵称(如:张三)', '点击保存按钮'], 'expected': ['系统校验昵称长度符合要求(3-20字符)', '系统提示修改成功', '个人中心页面刷新显示新的昵称']}, {'id': 'TC-F1.3-002', 'name': '修改性别-正向测试', 'steps': ['用户登录系统', '进入个人中心页面', '点击性别编辑按钮', "选择性别为'男'", '点击保存按钮'], 'expected': ['系统校验性别选项合法(男/女/保密)', '系统提示修改成功', '个人中心页面刷新显示新的性别信息']}, {'id': 'TC-F1.3-003', 'name': '修改头像-正向测试', 'steps': ['用户登录系统', '进入个人中心页面', '点击头像编辑按钮', '选择符合规范的图片文件(如:1.5M的jpg格式图片)', '点击保存按钮'], 'expected': ['系统校验图片格式符合要求(png/jpg/jpeg)', '系统校验图片大小符合要求(2M以内)', '系统提示修改成功', '个人中心页面刷新显示新的头像']}]}
3. 使用 TypedDict 来控制输出结果 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 from src.core.llms import model_clientmessage = [ {"role" : "user" , "content" : """ 请根据以下需求文档,生成3条正向的测试用例 📌 F1.3 用户信息修改 🧩 功能背景 用户可修改昵称、密码、头像、性别等基础信息。 🚶 主流程 1. 用户进入“个人中心” 2. 修改某字段并保存 3. 系统校验内容合法性(如昵称长度、头像格式) 4. 修改成功后刷新显示 ⚠ 异常流程 用户未登录:提示登录后操作 输入非法字符:提示不符合规范 📌 业务规则 昵称长度大于3 小于20,支持中英文 性别只能为“男 / 女 / 保密” 头像图片限制大小(2M以内),格式为 png/jpg/jpeg """ }] from typing import List , TypedDictclass CaseItem (TypedDict ): id : str name: str setup: str expected: List class CaseList (TypedDict ): cases: List [CaseItem] model_with_structure = model_client.with_structured_output(CaseList) result = model_with_structure.invoke(message) print (type (result))print ("************************************结果****************************" )print (result)
输出结果为
1 2 3 <class 'dict'> ************************************结果**************************** {'cases': [{'id': 'F1.3_TC001', 'name': '修改昵称-合法长度中英文混合', 'setup': '1. 用户已登录\n2. 进入个人中心\n3. 修改昵称字段为"张三Zhang123"(长度12,包含中英文和数字)\n4. 点击保存按钮', 'expected': ['系统校验通过', '修改成功提示', '页面刷新显示新昵称"张三Zhang123"']}, {'id': 'F1.3_TC002', 'name': '修改性别-选择合法选项', 'setup': '1. 用户已登录\n2. 进入个人中心\n3. 修改性别字段为"男"\n4. 点击保存按钮', 'expected': ['系统校验通过', '修改成功提示', '页面刷新显示性别为"男"']}, {'id': 'F1.3_TC003', 'name': '修改头像-合法格式和大小', 'setup': '1. 用户已登录\n2. 进入个人中心\n3. 上传头像图片(格式为jpg,大小1.5M)\n4. 点击保存按钮', 'expected': ['系统校验通过(格式和大小符合要求)', '修改成功提示', '页面刷新显示新头像']}]}
注意事项:
TypedDict 只提供类型提示,没有数据验证功能
TypedDict性能更好,但功能比 Pydantic 简单
适合不需要复杂验证的场景
补充:参数include_raw=True 加上参数include_raw=True,大模型在输出结果时,不仅会返回格式化之后的结果,也会返回大模型输出的原始结果和元数据。以上的示例增加这个参数,查看下输出的内容。
1 2 3 4 5 6 7 model_with_structure = model_client.with_structured_output(CaseList, include_raw=True ) result = model_with_structure.invoke(message) print (type (result))print ("************************************结果****************************" )print (result)
输出结果
1 2 3 <class 'dict'> ************************************结果**************************** {'raw': AIMessage(content='', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 323, 'prompt_tokens': 763, 'total_tokens': 1086, 'completion_tokens_details': None, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 704}, 'prompt_cache_hit_tokens': 704, 'prompt_cache_miss_tokens': 59}, 'model_provider': 'deepseek', 'model_name': 'deepseek-chat', 'system_fingerprint': 'fp_eaab8d114b_prod0820_fp8_kvcache', 'id': 'cfef118d-b435-424f-af7d-8257afe8d218', 'finish_reason': 'tool_calls', 'logprobs': None}, id='lc_run--1ed5c2ac-7750-48f5-9ef8-be913f542194-0', tool_calls=[{'name': 'CaseList', 'args': {'cases': [{'id': 'TC_F1.3_001', 'name': '修改昵称-正常场景', 'setup': '1. 用户已登录系统\n2. 进入个人中心页面\n3. 准备修改昵称为符合规范的名称', 'expected': ['1. 成功修改昵称为新值', '2. 页面刷新显示更新后的昵称', '3. 无错误提示信息']}, {'id': 'TC_F1.3_002', 'name': '修改性别-正常场景', 'setup': "1. 用户已登录系统\n2. 进入个人中心页面\n3. 准备修改性别为'男'、'女'或'保密'中的任一值", 'expected': ['1. 成功修改性别为新值', '2. 页面刷新显示更新后的性别', '3. 无错误提示信息']}, {'id': 'TC_F1.3_003', 'name': '修改头像-正常场景', 'setup': '1. 用户已登录系统\n2. 进入个人中心页面\n3. 准备上传符合规范的图片文件(大小2M以内,格式为png/jpg/jpeg)', 'expected': ['1. 成功上传并更新头像', '2. 页面刷新显示新的头像', '3. 无错误提示信息']}]}, 'id': 'call_00_2907Uso2ye8qxnYrWaRQkADk', 'type': 'tool_call'}], usage_metadata={'input_tokens': 763, 'output_tokens': 323, 'total_tokens': 1086, 'input_token_details': {'cache_read': 704}, 'output_token_details': {}}), 'parsed': {'cases': [{'id': 'TC_F1.3_001', 'name': '修改昵称-正常场景', 'setup': '1. 用户已登录系统\n2. 进入个人中心页面\n3. 准备修改昵称为符合规范的名称', 'expected': ['1. 成功修改昵称为新值', '2. 页面刷新显示更新后的昵称', '3. 无错误提示信息']}, {'id': 'TC_F1.3_002', 'name': '修改性别-正常场景', 'setup': "1. 用户已登录系统\n2. 进入个人中心页面\n3. 准备修改性别为'男'、'女'或'保密'中的任一值", 'expected': ['1. 成功修改性别为新值', '2. 页面刷新显示更新后的性别', '3. 无错误提示信息']}, {'id': 'TC_F1.3_003', 'name': '修改头像-正常场景', 'setup': '1. 用户已登录系统\n2. 进入个人中心页面\n3. 准备上传符合规范的图片文件(大小2M以内,格式为png/jpg/jpeg)', 'expected': ['1. 成功上传并更新头像', '2. 页面刷新显示新的头像', '3. 无错误提示信息']}]}, 'parsing_error': None}
Agent接入模型调用 静态模型 静态模型在创建智能体时配置一次,并在整个执行过程中保持不变。这是最常见和直接的方法。要从模型标识符字符串初始化静态模型:
1 2 3 4 5 6 7 8 9 10 11 from langchain.agents import create_agentfrom langchain_openai import ChatOpenAImodel = ChatOpenAI( model="gpt-5" , temperature=0.1 , max_tokens=1000 , timeout=30 ) agent = create_agent(model, tools=tools)
模型实例让您可以完全控制配置。当您需要设置特定的参数 时使用它们,例如 temperature 、max_tokens 、timeouts 、base_url 和其他特定于提供者的设置。
动态模型 动态模型在运行时根据当前状态和上下文选择。这支持复杂的路由逻辑和成本优化。要使用动态模型,请使用@wrap_model_call 装饰器创建中间件,该中间件会修改请求中的模型:
使用动态模型的优点:
轻松集成新模态(图片、音频、视频),多模态的支持更方便
简单对话使用成本较低的模型、复杂任务才启用高性能模型、降低成本
模块化扩展
这次更新后,增加了中间间的内容,使得大模型在执行过程中,可更好的控制执行中的行为,动态模型就是其中一种方式,官方网站的说明:https://docs.langchain.com/oss/python/langchain/middleware/custom#dynamic-model-selection
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 import osfrom dotenv import load_dotenvfrom langchain_openai import ChatOpenAIfrom langchain.agents import create_agentfrom langchain.agents.middleware import wrap_model_call, ModelRequest, ModelResponseload_dotenv() basic_model = ChatOpenAI( model=os.getenv("llm_model" ), base_url=os.getenv("base_url" ), api_key=os.getenv("api_key" ), ) image_model = ChatOpenAI( model=os.getenv("image_model" ), base_url=os.getenv("base_url" ), api_key=os.getenv("api_key" ), ) @wrap_model_call def dynamic_model_selection (request: ModelRequest, handler ) -> ModelResponse: """基于对话复杂度选择模型""" message_count = len (request.state["messages" ]) if message_count > 10 : selected_model = image_model else : selected_model = basic_model request.model = selected_model return handler(request) agent = create_agent( model=basic_model, tools=tools, middleware=[dynamic_model_selection] )