2026/4/23 9:52:51
网站建设
项目流程
番禺 建网站 360元,永州做网站费用,非物质文化遗产网站怎么做,成都筑巢网站建设本文详细解析了基于LangGraph构建的Open Deep Research多Agent系统中动态模型配置的实现方法。通过四步流程#xff08;创建可配置模型模板、读取配置信息、构建配置字典、应用配置#xff09;#xff0c;实现了不同Agent使用不同模型配置的需求。配置采用三级优先级机制创建可配置模型模板、读取配置信息、构建配置字典、应用配置实现了不同Agent使用不同模型配置的需求。配置采用三级优先级机制环境变量 运行时配置 默认值可通过LangGraph Studio UI或程序调用时手动传入。这一技术使多Agent系统能根据任务特点灵活选择最适合的模型配置提升系统整体性能。Open Deep Research 简介Open Deep Research 是一个基于 LangGraph 构建的多Agent深度研究系统。该系统将复杂的深度研究任务分解为多个专业化Agent包括用户澄清Agent、研究Agent、压缩Agent和报告生成Agent等。每个Agent专注于特定任务实现了职责分离、灵活配置和高效协作的多Agent架构设计。在多Agent系统中不同Agent往往需要不同的模型配置来优化其特定任务的性能。例如研究Agent可能需要更强的推理能力而压缩Agent可能更注重效率。因此动态模型配置成为了多Agent系统设计中的关键。事实上我们在前期文章中已经学习过了一种简单地通过ContextSchema来动态配置运行时参数的方法[从零开始学LangGraph10利用Runtime自定义实现Model和System Prompt的灵活切换]。而根据Open Deep Research的源代码我们可以学习到一种更专业的配置方式实现在Graph运行时通过配置字符串动态创建模型实例的效果。下面直接进入正题动态模型配置实践学习第一步创建可动态配置的模型模板init_chat_model这个接口我们已经很熟悉了它是LangChain给我提供的调用模型能力的工具。它有一个参数configurable_fields作用是指定哪些字段可以在运行时通过config参数动态修改。如果不指定 configurable_fields默认情况下 “model” 和 “model_provider” 是可配置的我们之前通过init_chat_model使用DeepSeek就是这么用的。from langchain.chat_models import init_chat_modelmodel init_chat_model(modeldeepseek-chat, model_providerdeepseek)因为Open Deep Research是一个多Agent系统不同的Agent由于负责的任务不同可能需要适配不同的模型因此我们需要通过configurable_fields来实现一个可动态配置参数的模型模板。源代码如下deep_researcher.py Lines 56-58configurable_model init_chat_model( configurable_fields(model, max_tokens, api_key),)上述代码中configurable_fields指定了三个可在运行时动态配置的字段•model模型名称如 “openai:gpt-4.1”•max_tokens最大输出 token 数•api_keyAPI 密钥后续在不同节点里具体配置模型时会使用这个模版填入读取到的具体的配置参数来“定制化”模型。下面我们逐步来学习这个过程。第二步读取模型的配置信息由于所有模型节点的配置都是大同小异的我们选择Open Deep Research中的第一个模型节点clarify_with_user来作为研究对象。先来看源代码deep_researcher.py Lines 60-74async def clarify_with_user(state: AgentState, config: RunnableConfig) - Command[Literal[write_research_brief, __end__]]: Analyze user messages and ask clarifying questions if the research scope is unclear. This function determines whether the users request needs clarification before proceeding with research. If clarification is disabled or not needed, it proceeds directly to research. Args: state: Current agent state containing user messages config: Runtime configuration with model settings and preferences Returns: Command to either end with a clarifying question or proceed to research brief configurable Configuration.from_runnable_config(config)async是异步编程的内容与本期无关大家可以忽略于是这就是个简单的节点函数。可以看到在节点函数签名中除了我们熟悉的state参数外还有个config参数类型为RunnableConfig它就是我们动态调整模型配置的关键所在。当 LangGraph 调用节点函数时需要传入config参数然后节点函数会从中读取配置并将其转换为便于使用的Configuration对象该对象在configuration.py中被定义使节点函数能够根据运行时配置动态调整行为。其中读取配置的代码就是configurable Configuration.from_runnable_config(config)可以看到这里使用了Configuration类中定义的一个.from_runnable_config方法下面我们展开看看它的作用原理。如何从运行时配置读取Configuration.from_runnable_config()的源代码如下configuration.py Lines 236-247。classmethod def from_runnable_config( cls, config: Optional[RunnableConfig] None ) - Configuration: Create a Configuration instance from a RunnableConfig. configurable config.get(configurable, {}) if config else {} field_names list(cls.model_fields.keys()) values: dict[str, Any] { field_name: os.environ.get(field_name.upper(), configurable.get(field_name)) for field_name in field_names } return cls(**{k: v for k, v in values.items() if v is not None})这是一个类方法classmethod所以from_runnable_config的第一个参数是类本身cls。从总体来说.from_runnable_config()的思路就是从用户配置的config中获得一个数据字典然后确定需要的字段来从这个字典中得到需要的值。接下来我们逐步分析这个方法是如何工作的。步骤 1从 RunnableConfig 中提取 configurable 字典configurable config.get(configurable, {}) if config else {}因为config是一个RunnableConfig对象所以我们首先需要理解RunnableConfig的结构。RunnableConfig是LangChain定义的一个配置字典它可能包含多个字段比如tags用于标记、metadata元数据等但对我们来说最重要的就是configurable字段。而同时configurable字段本身也是一个字典里面存放着所有可以在运行时动态调整的配置项。一个典型的RunnableConfig结构如下{ configurable: { research_model: openai:gpt-4.1, research_model_max_tokens: 10000, allow_clarification: True, # ... 其他配置项 }, tags: [production, v1], metadata: {user_id: 12345}, # ... 其他字段}所以前述源代码的逻辑就是• 如果config存在就尝试从中获取configurable字段• 如果config为None或者configurable字段不存在就返回一个空字典{}需要多说一句的是这个config在Open Deep Research项目中主要是通过使用LangGraph Studio UI来输入配置的步骤 2获取 Configuration 类中定义的所有字段名field_names list(cls.model_fields.keys())这一步的目的是获取Configuration类中定义的所有配置字段的名称。为后面提取Configuration类中定义的特定字段然后根据前一步获得的configurable 字典分配对应的配置值做准备。那么如何获取这些字段名呢这里用到了Pydantic的一个特性。因为Configuration类继承自BaseModelPydantic会自动扫描类中所有用Field()定义的字段并创建一个名为model_fields的字典属性。这个字典的键是字段名值是字段定义对象。还是以源代码为例Configuration类的定义大概如下class Configuration(BaseModel): Main configuration class for the Deep Research agent. # General Configuration max_structured_output_retries: int Field(...) allow_clarification: bool Field(...) max_concurrent_research_units: int Field(...) # Research Configuration search_api: SearchAPI Field(...) max_researcher_iterations: int Field(...) max_react_tool_calls: int Field(...) # Model Configuration summarization_model: str Field(...) summarization_model_max_tokens: int Field(...) max_content_length: int Field(...) research_model: str Field(...) research_model_max_tokens: int Field(...) compression_model: str Field(...) compression_model_max_tokens: int Field(...) final_report_model: str Field(...) final_report_model_max_tokens: int Field(...) # MCP server configuration mcp_config: Optional[MCPConfig] Field(...) mcp_prompt: Optional[str] Field(...)Pydantic 会将这些字段收集到model_fields字典中通过cls.model_fields)其结构如下cls.model_fields { # 键是字段名字符串值是 FieldInfo 对象 max_structured_output_retries: FieldInfo( default3, metadata{...}, # ... 其他字段信息 ), allow_clarification: FieldInfo( defaultTrue, metadata{...}, ), max_concurrent_research_units: FieldInfo( default5, metadata{...}, ), search_api: FieldInfo( defaultSearchAPI.TAVILY, metadata{...}, ), ......}然后再使用.keys()返回一个视图对象包含所有字段名dict_keys([ max_structured_output_retries, allow_clarification, max_concurrent_research_units, search_api, ......])最后用list()将其转换为列表便于后续遍历处理。field_names [ max_structured_output_retries, allow_clarification, max_concurrent_research_units, search_api, ......]值得一提的是这种方式是动态的当你在Configuration类中添加新字段时model_fields.keys()会自动包含新字段无需修改from_runnable_config方法。这避免了手动维护字段列表的麻烦也减少了出错的可能性。步骤 3按优先级顺序读取每个字段的配置值values: dict[str, Any] { field_name: os.environ.get(field_name.upper(), configurable.get(field_name)) for field_name in field_names}这是整个方法的核心逻辑。使用字典推导式为每个配置字段field_name确定最终使用的值。这里的关键在于优先级机制的设计。os.environ.get(field_name.upper(), configurable.get(field_name))这行代码体现了两个优先级的处理优先级 1环境变量最高优先级os.environ.get(field_name.upper(), ...)首先尝试从系统环境变量中读取配置。注意这里有一个细节字段名会被转换为大写。比如如果字段名是research_model那么会去查找环境变量RESEARCH_MODEL。优先级 2运行时配置次优先级如果环境变量中没有找到对应的值os.environ.get()返回None那么os.environ.get()的第二个参数就会生效这个参数是configurable.get(field_name)即从我们步骤一中获取的运行时配置的configurable字典中读取值。优先级 3默认值最低优先级如果前两者都没有提供值则在这一步field_name的值将为none。而后面我们会看到通过过滤none相关的值最终会使用Configuration类中定义的默认值。这个默认值是在定义Configuration类时通过Field(default...)设置的。步骤 4过滤 None 值并创建 Configuration 实例return cls(**{k: v for k, v in values.items() if v is not None})最后一步我们需要将收集到的配置值传递给Configuration类的构造函数创建Configuration实例。这里有一个重要的细节我们使用字典推导式{k: v for k, v in values.items() if v is not None}过滤掉了所有值为None的项。为什么要这样做呢这是因为如果某个字段在前面的步骤中既没有从环境变量读取到也没有从运行时配置读取到那么它的值就是None。如果我们把这些None值也传给Configuration的构造函数可能会覆盖掉类中定义的默认值。通过过滤掉None值我们确保了只有明确提供的配置值才会被使用而那些没有提供的字段会使用Configuration类中通过Field(default...)定义的默认值。最后cls(**{...})使用解包操作符**将字典展开为关键字参数调用Configuration类的构造函数创建一个配置实例并返回。第三步为不同的节点创建配置字典模板接下来的步骤就很简单了我们只需要从上一步读取运行时配置后创建的Configuration 类的configurable中读取相关信息。model_config { model: configurable.research_model, max_tokens: configurable.research_model_max_tokens, api_key: get_api_key_for_model(configurable.research_model, config), tags: [langsmith:nostream] }model、max_tokens都是直接通过点的方式从configurable中读取对应的字段信息比如我们这里是research节点所以读的是research_model、research_model_max_tokens如此实现了config的动态变化。api_key稍微特殊点使用了get_api_key_for_model()这个函数 根据模型名称前缀如 “openai:”、“anthropic:”从环境变量或配置中获取。这个函数的具体作用原理就不再赘述了感兴趣的朋友可以把代码丢给AI解读下def get_api_key_for_model(model_name: str, config: RunnableConfig): Get API key for a specific model from environment or config. should_get_from_config os.getenv(GET_API_KEYS_FROM_CONFIG, false) model_name model_name.lower() if should_get_from_config.lower() true: api_keys config.get(configurable, {}).get(apiKeys, {}) ifnot api_keys: returnNone if model_name.startswith(openai:): return api_keys.get(OPENAI_API_KEY) elif model_name.startswith(anthropic:): return api_keys.get(ANTHROPIC_API_KEY) elif model_name.startswith(google): return api_keys.get(GOOGLE_API_KEY) returnNone else: if model_name.startswith(openai:): return os.getenv(OPENAI_API_KEY) elif model_name.startswith(anthropic:): return os.getenv(ANTHROPIC_API_KEY) elif model_name.startswith(google): return os.getenv(GOOGLE_API_KEY) return None第四步将配置到应用到模型# Configure model with structured output and retry logic clarification_model ( configurable_model .with_structured_output(ClarifyWithUser) .with_retry(stop_after_attemptconfigurable.max_structured_output_retries) .with_config(model_config) )最终在我们第一步创建的configurable_model这个模板的基础上 使用.with_config()方法将前面获取的配置信息应用进去就大功告成啦。补充config 的来源前文中我们已经了解了Open Deep Research中模型动态配置的基本原理但有个尾巴还需要说明一下。我们已经知道了节点在读取模型的配置信息时有个环境变量 运行时配置 默认值的优先级顺序前后两个都好理解那么“运行时配置”到底是从哪里来的呢通过LangGraph Studio UI配置对于Open Deep Research这个项目来说它推荐的方法是使用LangGraph Studio 。由于源代码在图的定义中指定了config_schemaConfigurationdeep_researcher_builder StateGraph( AgentState, inputAgentInputState, config_schemaConfiguration # 指定配置 schema)所以LangGraph Studio 会根据Configuration类的字段定义自动生成配置 UI。用户在 UI 的 “Manage Assistants” 标签页中设置的配置会自动作为config传入所有节点。程序调用时手动传入第二种方式就是我们熟悉的手动传入了。我们可以在代码中写好config的内容然后在invoke图的时候作为参数传入。config { configurable: { research_model: openai:gpt-4.1, research_model_max_tokens: 10000, # ... 其他配置项 }}result deep_researcher.invoke(inputs, config)总结综上Open Deep Research 大致通过以上四步配置流程实现了多Agent系统的动态模型配置• 1.创建模型模板使用init_chat_model(configurable_fields...)创建可配置的模型模板• 2.读取预设配置通过Configuration.from_runnable_config()从运行时配置中提取参数支持三级优先级环境变量 运行时配置 默认值• 3.构建模型配置字典根据不同节点需求从Configuration对象提取相应配置项构建model_config字典• 4.应用配置使用.with_config(model_config)将配置应用到模型模板生成定制化的模型实例如何系统的学习大模型 AI 由于新岗位的生产效率要优于被取代岗位的生产效率所以实际上整个社会的生产效率是提升的。但是具体到个人只能说是“最先掌握AI的人将会比较晚掌握AI的人有竞争优势”。这句话放在计算机、互联网、移动互联网的开局时期都是一样的道理。我在一线互联网企业工作十余年里指导过不少同行后辈。帮助很多人得到了学习和成长。我意识到有很多经验和知识值得分享给大家也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限很多互联网行业朋友无法获得正确的资料得到学习提升故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。一直在更新更多的大模型学习和面试资料已经上传带到CSDN的官方了有需要的朋友可以扫描下方二维码免费领取【保证100%免费】01.大模型风口已至月薪30K的AI岗正在批量诞生2025年大模型应用呈现爆发式增长根据工信部最新数据国内大模型相关岗位缺口达47万初级工程师平均薪资28K数据来源BOSS直聘报告70%企业存在能用模型不会调优的痛点真实案例某二本机械专业学员通过4个月系统学习成功拿到某AI医疗公司大模型优化岗offer薪资直接翻3倍02.大模型 AI 学习和面试资料1️⃣ 提示词工程把ChatGPT从玩具变成生产工具2️⃣ RAG系统让大模型精准输出行业知识3️⃣ 智能体开发用AutoGPT打造24小时数字员工熬了三个大夜整理的《AI进化工具包》送你✔️ 大厂内部LLM落地手册含58个真实案例✔️ 提示词设计模板库覆盖12大应用场景✔️ 私藏学习路径图0基础到项目实战仅需90天第一阶段10天初阶应用该阶段让大家对大模型 AI有一个最前沿的认识对大模型 AI 的理解超过 95% 的人可以在相关讨论时发表高级、不跟风、又接地气的见解别人只会和 AI 聊天而你能调教 AI并能用代码将大模型和业务衔接。大模型 AI 能干什么大模型是怎样获得「智能」的用好 AI 的核心心法大模型应用业务架构大模型应用技术架构代码示例向 GPT-3.5 灌入新知识提示工程的意义和核心思想Prompt 典型构成指令调优方法论思维链和思维树Prompt 攻击和防范…第二阶段30天高阶应用该阶段我们正式进入大模型 AI 进阶实战学习学会构造私有知识库扩展 AI 的能力。快速开发一个完整的基于 agent 对话机器人。掌握功能最强的大模型开发框架抓住最新的技术进展适合 Python 和 JavaScript 程序员。为什么要做 RAG搭建一个简单的 ChatPDF检索的基础概念什么是向量表示Embeddings向量数据库与向量检索基于向量检索的 RAG搭建 RAG 系统的扩展知识混合检索与 RAG-Fusion 简介向量模型本地部署…第三阶段30天模型训练恭喜你如果学到这里你基本可以找到一份大模型 AI相关的工作自己也能训练 GPT 了通过微调训练自己的垂直大模型能独立训练开源多模态大模型掌握更多技术方案。到此为止大概2个月的时间。你已经成为了一名“AI小子”。那么你还想往下探索吗为什么要做 RAG什么是模型什么是模型训练求解器 损失函数简介小实验2手写一个简单的神经网络并训练它什么是训练/预训练/微调/轻量化微调Transformer结构简介轻量化微调实验数据集的构建…第四阶段20天商业闭环对全球大模型从性能、吞吐量、成本等方面有一定的认知可以在云端和本地等多种环境下部署大模型找到适合自己的项目/创业方向做一名被 AI 武装的产品经理。硬件选型带你了解全球大模型使用国产大模型服务搭建 OpenAI 代理热身基于阿里云 PAI 部署 Stable Diffusion在本地计算机运行大模型大模型的私有化部署基于 vLLM 部署大模型案例如何优雅地在阿里云私有部署开源大模型部署一套开源 LLM 项目内容安全互联网信息服务算法备案…学习是一个过程只要学习就会有挑战。天道酬勤你越努力就会成为越优秀的自己。如果你能在15天内完成所有的任务那你堪称天才。然而如果你能完成 60-70% 的内容你就已经开始具备成为一名大模型 AI 的正确特征了。这份完整版的大模型 AI 学习资料已经上传CSDN朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】