当前位置: 首页 > news >正文

20250913-01: Langchain概念:Runnable可运行接口

image

20250913-01: Langchain概念:Runnable可运行接口

  1. 任务

  2. 🎯 学习目标

    1. 🔗 核心概念
  3. 可运行接口​(Runnable)​

    1. Runnable 接口概述

    2. 优化的并行执行(批量)

    3. 异步支持

    4. 流式 API

    5. 输入和输出类型

    6. 检查 Schema

      1. With_types
  4. RunnableConfig

    1. RunnableConfig 的传播
    2. 设置自定义运行名称、标签和元数据
    3. 设置运行 ID
    4. 设置递归限制
    5. 设置最大并发
    6. 设置可配置项
    7. 设置回调
  5. 从函数创建 Runnable

  6. 可配置的 Runnable

任务

  • 阅读 LCEL 官方文档
  • 理解 | 操作符的底层是 RunnableSequence

🎯 学习目标

理解 LangChain 的“运行时引擎”——所有组件如何被统一调度和编排。

🔗 核心概念

  • 可运行接口(Runnable)
  • LangChain 表达式语言(LCEL)
  • 回调(Callbacks)
  • 追踪(Tracing)
  • 流式传输(Streaming)
  • 异步编程(Async)

可运行接口(Runnable)

Runnable 接口 | 🦜️🔗 LangChain 框架

Runnable 接口是使用 LangChain 组件的 基础 ,它在许多组件中都有实现,例如语言模型、输出解析器、检索器、编译后的 LangGraph 图等等。

Runnable 接口的主要概念和方法,它允许开发者以 一致可预测 的方式与各种 LangChain 组件进行交互。

Runnable 接口概述

Runnable 方式定义了一个标准接口,允许 Runnable 组件

  • 调用 invoked:将单个输入转换为输出。
  • 批量处理 Batched:将多个输入高效地转换为输出。
  • 流式传输 Streamed:输出在其生成时进行流式传输。
  • 检查 Inspected:可以访问有关 Runnable 输入、输出和配置的示意信息。
  • 组合 Composed:可以使用LangChain 表达式语言 (LCEL) 将多个 Runnable 组合在一起以创建复杂的管道。

请查看LCEL 速查表以了解涉及 Runnable 接口和 LCEL 表达式的一些常见模式。

优化的并行执行(批量)

LangChain Runnable 提供内置的 batch(和 batch_as_completed)API,允许您并行处理多个输入。

两种批量处理选项是

  • batch:并行处理多个输入,并按与输入相同的顺序返回结果。
  • batch_as_completed:并行处理多个输入,并在完成时返回结果。结果可能无序到达,但每个结果都包含输入索引以进行匹配。

batchbatch_as_completed默认实现 使用 线程池执行器 来并行运行 invoke 方法。这 允许高效 的并行执行,而无需用户管理线程,并加速 I/O 密集型 代码(例如,发出 API 请求、读取文件等)。对于 CPU 密集型 操作,它不会那么有效,因为 Python 中的 GIL(全局解释器锁)会阻止真正的并行执行。

abatchabatch_as_completed 的异步版本依赖于 asyncio 的gather 和 as_completed 函数来并行运行 ainvoke 方法。

注意

当使用 batchbatch_as_completed 处理大量输入时,用户可能希望控制最大并行调用数量。这可以通过在 RunnableConfig 字典中设置 max_concurrency 属性来完成。有关更多信息,请参阅RunnableConfig。

聊天模型 (Chat Models) 还具有内置的速率限制器,可用于控制请求的速率。

异步支持

Runnable 暴露了一个异步 API,允许它们在 Python 中使用 await 语法进行调用。异步方法可以通过“a”前缀来识别(例如,ainvokeabatchastreamabatch_as_completed)。

请参阅LangChain 异步编程指南以获取更多详细信息。

流式 API

流式传输对于使基于 LLM 的应用程序对最终用户响应迅速至关重要。

Runnable 暴露了以下三个流式 API

  1. 同步 stream 和异步 astream:在生成时产生 Runnable 的输出。
  2. 异步 astream_events:一个更高级的流式 API,允许流式传输中间步骤和最终输出
  3. 遗留异步 astream_log:一个遗留流式 API,用于流式传输中间步骤和最终输出

请参阅流式传输概念指南以获取有关如何在 LangChain 中进行流式传输的更多详细信息。

输入和输出类型

每个 Runnable 都由一个 输入类型 和一个 输出类型 来表征。这些输入和输出类型可以是任何 Python 对象,并由 Runnable 本身定义。

导致 Runnable 执行的 Runnable 方法(例如, invokebatchstreamastream_events )都使用这些输入和输出类型。

  • invoke :接受一个输入并返回一个输出。
  • batch :接受一个输入列表并返回一个输出列表。
  • stream :接受一个输入并返回一个产生输出的生成器。

输入类型输出类型因组件而异

组件输入类型输出类型
提示词字典PromptValue
聊天模型字符串、聊天消息列表或 PromptValueChatMessage
LLM字符串、聊天消息列表或 PromptValue字符串
输出解析器LLM 或聊天模型的输出取决于解析器
检索器字符串文档列表
工具字符串或字典,取决于工具取决于工具

检查 Schema

注意

这是一个高级功能,对于大多数用户来说没有必要。除非您有特定的需求来检查 Runnable 的 schema,否则您应该跳过此部分。

Runnable 接口提供了获取 JSON Schema(Runnable 输入和输出类型的模式)以及输入和输出类型的 Pydantic schema 的方法。

方法描述
get_input_schema提供 Runnable 输入 schema 的 Pydantic Schema。
get_output_schema提供 Runnable 输出 schema 的 Pydantic Schema。
config_schema提供 Runnable 配置 schema 的 Pydantic Schema。
get_input_jsonschema提供 Runnable 输入 schema 的 JSONSchema。
get_output_jsonschema提供 Runnable 输出 schema 的 JSONSchema。
get_config_jsonschema提供 Runnable 配置 schema 的 JSONSchema。
With_types

LangChain 将根据可用信息自动尝试推断 Runnable 的输入和输出类型。

目前,这种推断对于使用LCEL组合构建的更复杂的 Runnable 效果不佳,推断的输入和/或输出类型可能不正确。在这些情况下,我们建议用户使用 with_types 方法(API 参考)覆盖推断的输入和输出类型。

RunnableConfig

任何用于执行 Runnable 的方法(例如,invokebatchstreamastream_events)都接受一个名为 RunnableConfig(API 参考)的第二个参数。

此参数是一个​** 字典 ,包含将在 Runnable 执行期间在 运行时 使用的 Runnable 配置。**

RunnableConfig 可以定义以下任何属性

属性描述
run_name用于给定 Runnable 的名称(不可继承)。
run_id此调用的唯一标识符。子调用将获得自己的唯一运行 ID。
tags此调用和任何子调用的标签。
metadata此调用和任何子调用的元数据。
callbacks此调用和任何子调用的回调。
max_concurrency最大并行调用数量(例如,由批量处理使用)。
recursion_limit调用可以递归的最大次数(例如,由返回 Runnable 的 Runnable 使用)
configurableRunnable 可配置属性的运行时值。

将 config 传递给 invoke 方法的方式如下

some_runnable.invoke(some_input, config={'run_name': 'my_run', 'tags': ['tag1', 'tag2'], 'metadata': {'key': 'value'}}
)

RunnableConfig 的传播

许多 Runnable 由其他 Runnable 组成,重要的是 RunnableConfig 要传播到 Runnable 进行的所有子调用。这允许向父 Runnable 提供运行时配置值,这些值将由所有子调用继承。

如果不是这样,将无法设置和传播回调或诸如 tagsmetadata 等其他配置值,而这些值是期望由所有子调用继承的。

创建新 Runnable 的两种主要模式是

  1. 使用LangChain 表达式语言 (LCEL) 声明式创建

    创建新 Runnable 的两种主要模式是使用LangChain 表达式语言 (LCEL) 声明式创建
    
  2. 使用自定义 Runnable(例如,RunnableLambda)或使用 @tool 装饰器

  3.  def foo(input):# Note that .invoke() is used directly herereturn bar_runnable.invoke(input)foo_runnable = RunnableLambda(foo)
    

LangChain 将尝试自动为这两种模式传播 RunnableConfig。

为了处理第二种模式,LangChain 依赖于 Python 的 contextvars。

提醒

Python 3.11 及更高版本中,这开箱即用,您无需进行任何特殊操作即可将 RunnableConfig 传播到子调用。

Python 3.93.10 中,如果您正在使用异步代码,您需要在调用 Runnable 时手动将 RunnableConfig 传递给它。

这是由于 Python 3.9 和 3.10 中 asyncio 任务的一个限制,它们不接受 context参数。

手动传播 RunnableConfig 的方式如下

async def foo(input, config): # <-- Note the config argumentreturn await bar_runnable.ainvoke(input, config=config)foo_runnable = RunnableLambda(foo)

警告

当使用 Python 3.10 或更低版本并编写异步代码时,RunnableConfig 无法自动传播,您需要手动进行!这是尝试使用 astream_eventsastream_log 流式传输数据时的一个常见陷阱,因为这些方法依赖于 RunnableConfig 中定义回调的正确传播。

设置自定义运行名称、标签和元数据

RunnableConfig 字典的 run_nametagsmetadata 属性可用于为给定 Runnable 设置运行名称、标签和元数据的自定义值。

run_name 是一个字符串,可用于为运行设置自定义名称。此名称将用于日志和其他位置以识别运行。它 不会被子调用继承

tagsmetadata 属性分别是 列表字典 ,可用于为运行设置自定义标签和元数据。这些值将被 子调用 继承。

使用这些属性对于 跟踪和调试 运行非常有用,因为它们将作为可过滤和搜索的跟踪属性呈现在 LangSmith 中。

这些属性也将传播到回调,并将作为流中每个事件的一部分出现在诸如astream_events之类的流式 API 中。

  • 如何使用 LangChain 进行追踪

设置运行 ID

这是一个高级功能,对于大多数用户来说没有必要。

您可能需要为给定运行设置自定义 run_id,以备将来引用或与其他系统关联。

run_id 必须是有效的 UUID 字符串,并且每个运行都​唯一。它用于识别父运行,子类将自动获得自己的唯一运行 ID。

要设置自定义 run_id,您可以在调用 Runnable 时将其作为键值对传递到 config 字典中

import uuidrun_id = uuid.uuid4()some_runnable.invoke(some_input, config={'run_id': run_id}
)# Do something with the run_id

设置递归限制

某些 Runnable 可能会返回其他 Runnable,如果处理不当,可能导致** 无限递归 **。为了防止这种情况,您可以在 RunnableConfig 字典中设置 recursion_limit。这将限制 Runnable 可以递归的次数。

设置最大并发

如果使用 batchbatch_as_completed 方法,您可以在 RunnableConfig 字典中设置 max_concurrency 属性来控制 最大并行 调用数量。当您想 限制并行调用数量 以防止 服务器或 API 过载 时,这会很有用。

如果您正在尝试限制聊天模型发出的请求数量,您可以使用内置的速率限制器,而不是设置 max_concurrency,这会更有效。

设置可配置项

configurable 字段用于为 Runnable 的可配置属性传递运行时值。

它经常在LangGraph与LangGraph 持久化和内存一起使用。

它在RunnableWithMessageHistory中用于类似目的,以指定 session_id / conversation_id 来跟踪对话历史记录。

此外,您可以使用它来指定任何自定义配置选项,以便传递给他们创建的任何可配置的 Runnable。

设置回调

使用此选项可在运行时为 Runnable 配置回调。回调将传递给 Runnable 进行的所有子调用。

some_runnable.invoke(some_input,{"callbacks": [SomeCallbackHandler(),AnotherCallbackHandler(),]}
)

请阅读回调概念指南,了解更多关于如何在 LangChain 中使用回调的信息。

如果您在异步环境中使用 Python 3.9 或 3.10,在某些情况下,您必须手动将 RunnableConfig 传播到子调用。请参阅RunnableConfig 的传播部分以获取更多信息。

从函数创建 Runnable

您可能需要创建一个运行任意逻辑的自定义 Runnable。

如果使用LangChain 表达式语言 (LCEL) 来组合多个 Runnable,并且您需要在其中一个步骤中添加自定义处理逻辑,这将特别有用。

有两种方法可以从函数创建自定义 Runnable

  • RunnableLambda:适用于 不需要流式传输 的简单转换。
  • RunnableGenerator:当需要 流式传输 时,适用于更复杂的转换。

有关如何使用 RunnableLambdaRunnableGenerator 的更多信息,请参阅如何运行自定义函数指南。

重要

用户不应尝试通过继承 Runnable 来创建新的自定义 Runnable。这比简单地使用 RunnableLambda RunnableGenerator 要复杂得多且更容易出错·。

可配置的 Runnable

它有助于配置使用LangChain 表达式语言 (LCEL) 创建的大型“链”,并被 LangServe 用于已部署的 Runnable。

有时您可能希望尝试,甚至向最终用户公开使用您的 Runnable 完成任务的多种不同方式。这可能涉及调整聊天模型中的温度等参数,甚至在不同的聊天模型之间切换。

为了简化此过程,Runnable 接口提供了两种在运行时创建可配置 Runnable 的方法

  • configurable_fields:此方法允许您配置 Runnable 中的特定​属性。例如,聊天模型的 temperature 属性。
  • configurable_alternatives:此方法使您能够指定可在运行时运行的替代 Runnable。例如,您可以指定一个可以使用的不同聊天模型的列表。

理解

问题:为什么需要“可配置的” Runnable?

现在问题来了。当你用 LCEL 创建好一个复杂的大链(比如一个客服机器人)后,你可能想:

  • 进行实验(Try) :在开发阶段,我想快速尝试用不同的模型(比如从 GPT-3.5 切换到 Claude)或者调整参数(比如把 temperature 从 0 调到 1,让回答更有创意),看看哪个效果更好。
  • 面向用户(Expose) :在产品阶段,我想让用户自己选择他们喜欢的模型或 creativity 级别,甚至为高级用户提供更强大的模型选项。

如果每次修改都要重新定义和创建整个链,会非常麻烦和低效。 “可配置的 Runnable” 就是为了解决这个问题而设计的。

“可配置的 Runnable” 是什么?

它是一种特殊的 Runnable,允许你在不重新构建整个链的情况下,动态地修改链中特定组件的配置。

它通过 RunnableConfig 参数来实现这一点。当你调用链时(如 chain.invoke(input, config=my_config)),你可以传入一个配置对象,这个配置对象可以告诉链:“嘿,这次运行,请把链里那个叫 ‘model’ 的组件换成我指定的这个,或者把它的温度参数调高。”

这就实现了链的“动态配置”

这段话可以这样理解:

“可配置的 Runnable” 是 LangChain 中的一个高级功能,它让你能轻松地动态调整那些由 LCEL 创建的复杂AI应用链(如客服机器人、摘要工具等)的内部设置(如切换模型、调整参数),而无需重写代码。这个功能极大地便利了开发阶段的实验和​产品阶段的用户自定义。同时,它是 LangServe 部署工具能够提供灵活 API 的基础,使得同一个部署好的AI链可以根据不同请求的配置,表现出不同的行为。

简单来说,它就是让你已经搭好的“AI乐高”(链),不用拆开就能随时换掉里面的某个“积木”(组件)。

这两个功能都来自于 LangChain 的 Runnable 接口,它们允许你在运行时(Runtime) 动态地改变链(Chain)的行为,而无需重新定义或重新部署整个链。这在需要 A/B 测试、根据不同用户调整参数或快速故障转移等场景下非常强大。


1. 动态配置 (configurable_fields)

这个功能允许你为一个 Runnable 的特定字段(如 LLM 的 temperature)设置可在运行时覆盖的配置。

核心方法: .configurable_fields(<field_name>=ConfigurableField(...))

示例场景: 创建一个翻译链,但其严谨性(由 temperature 控制)可以在调用时动态决定。

from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import ConfigurableField
# 外部配置好的模型
from src.langchain_base import model_glm45,model_qwen3_8b# # 1. 定义一个基础的 LLM,并为其 temperature 字段设置为可配置
# 这里的 temperature=0.7 是一个默认值,将在运行时被覆盖
configurable_llm = model_glm45.configurable_fields(temperature=ConfigurableField(id="llm_temperature",# 这个配置的唯一 IDname="llm's temperature", # 可读的名称description="控制模型输出的随机性(0.0-1.0)"))# 描述信息# 2. 创建一个简单的提示模板
prompt = ChatPromptTemplate.from_messages([("system", "你是一个专业的翻译家。将用户输入的内容翻译成英文。"),("human", "{text}")
])# 3. 将提示模板和可配置的 LLM 组合成链
chain = prompt | configurable_llm# 4. 调用链时,通过 `with_config` 动态传入配置
# 示例 1: 使用高创造性翻译
creative_translation = chain.with_config(config={"llm_temperature": 0.9})for chunk in creative_translation.stream(({"text": "今天天气真好,阳光明媚。"})):print(chunk.content, end="", flush=True)# 示例 2: 使用高确定性翻译(更字面、更准确)
precise_translation = chain.with_config(configurable={"llm_temperature": 0.1}
).invoke({"text": "今天天气真好,阳光明媚。"})
print("高确定性翻译:", precise_translation.content)# 示例 3: 不提供配置,则使用默认的 temperature=0.7
default_translation = chain.invoke({"text": "今天天气真好,阳光明媚。"})
print("默认翻译:", default_translation.content)

关键点:

  • ConfigurableField 定义了哪个字段可以被配置以及如何描述它。
  • with_config(configurable={"field_id": value}) 是在调用时覆盖配置的方法。
  • 你可以在同一个 Runnable 上为多个字段调用 .configurable_fields()

image


2. 动态切换 (configurable_alternatives)

这个功能允许你在一组不同的 Runnable 之间进行运行时切换。这是实现模型故障转移、A/B 测试或根据输入路由到不同专家的完美工具。

核心方法: .configurable_alternatives(ConfigurableField(...), <key>=<runnable>)

示例场景: 创建一个链,可以根据需要在 OpenAI、Anthropic 和一个快速的本地模型之间切换。

# 1. 定义多个可选的 LLM
from src.langchain_base import model_glm45,model_qwen3_8b
# 2. 创建一个基础 LLM(通常是默认选择)
base_llm = model_glm45# 3. 使用 configurable_alternatives 将其变为一个“开关”
switchable_llm = base_llm.configurable_alternatives(# 定义配置字段ConfigurableField(id="llm_choice", name="llm_choice", description="llm_choice"),# 定义备选项键值对# 键:在运行时传入的字符串# 值:对应的 Runnableqwen3_8b=model_qwen3_8b,glm45=model_glm45# 如果传入了未定义的键,或者不传,则使用默认的 base_llm (即 openai_llm)
)# 4. 创建提示模板和链
prompt = ChatPromptTemplate.from_messages([("system", "你是一个乐于助人的助手。"),("human", "{question}")
])chain = prompt | switchable_llm
# 5. 在运行时动态切换模型!
# 使用 qwen3_8b
# response_openai = chain.with_config(
#     config={"llm_choice": "qwen3_8b"}
# ).invoke({"question": "量子计算的主要挑战是什么?"})
# print(f"qwen3_8b 回答: {response_openai.content}\n")# 使用 glm45
response_anthropic = chain.with_config(configurable={"llm_choice": "glm45"}
).invoke({"question": "量子计算的主要挑战是什么?"})
print(f"glm45 回答: {response_anthropic.content}\n")# 使用 glm45
response_anthropic = chain.invoke({"question": "量子计算的主要挑战是什么?"})
print(f"default 回答: {response_anthropic.content}\n")

image

image

更复杂的示例:切换整个子链

你不仅可以切换 LLM,还可以切换任何 Runnable,例如整个检索QA链。

from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain# 假设我们有两个不同的检索器:一个用于科学文档,一个用于法律文档
science_retriever = ...
law_retriever = ...# 为每个检索器创建各自的 QA 子链
prompt = ChatPromptTemplate.from_template(...)
llm = ChatOpenAI()science_qa_chain = create_stuff_documents_chain(llm, prompt)
law_qa_chain = create_stuff_documents_chain(llm, prompt)science_chain = create_retrieval_chain(science_retriever, science_qa_chain)
law_chain = create_retrieval_chain(law_retriever, law_qa_chain)# 创建一个基础链(例如默认科学链)
base_chain = science_chain# 使其可切换
router_chain = base_chain.configurable_alternatives(ConfigurableField(id="retriever_domain",name="Retriever Domain",description="根据问题领域选择检索器",),science=science_chain,law=law_chain,
)# 现在,你可以根据用户问题的领域动态选择最合适的检索链!
science_answer = router_chain.with_config(configurable={"retriever_domain": "science"}
).invoke({"input": "解释一下光合作用。"})law_answer = router_chain.with_config(configurable={"retriever_domain": "law"}
).invoke({"input": "什么是著作权?"})

总结

功能用途核心方法
configurable_fields微调一个 Runnable 的内部参数.configurable_fields(field=ConfigurableField(...))
configurable_alternatives在多个完整的 Runnable 之间切换.configurable_alternatives(ConfigurableField(...), key=runnable)

复习知识点

Runnable 接口 - 核心概念

  1. 基础定义: Runnable 接口是 LangChain 组件的统一基础,被语言模型、输出解析器、检索器等广泛实现。
  2. 核心价值: 它提供了一种一致且可预测的方式与所有 LangChain 组件进行交互。

Runnable 接口概述 (核心能力)

  1. 核心方法: 定义了 invoke(单输入转输出)、batch(批量处理)、stream(流式传输)等标准方法。

  2. 关键能力: 允许组件被检查(获取输入/输出规范)和组合(通过 LCEL 创建复杂管道)。

  3. 优化的批量处理: batchbatch_as_completed API 提供内置的并行处理能力,显著提升多输入处理性能。

    • 关键说明: 默认使用线程池,优化 I/O 密集型操作,但对 CPU 密集型任务因 GIL 限制效果不佳。
  4. 异步支持: 所有执行方法都有对应的异步版本(如 ainvoke, abatch),通过 a前缀标识。

  5. 流式传输 API: 提供 stream/astream(流式输出)和更高级的 astream_events(流式中间步骤和输出)。

输入和输出类型

  1. 类型化接口: 每个 Runnable 都由输入和输出类型表征,这些类型因组件而异(如提示词输入字典,聊天模型输出 ChatMessage)。
  2. 执行方法约束: invoke, batch, stream 等方法都严格使用这些预定义的输入和输出类型。

RunnableConfig (高级但关键)

  1. 配置载体: 一个字典,作为第二个参数传递给所有执行方法(如 invoke(input, config={})),用于传递运行时配置。

  2. 核心配置属性:

    • callbacks: 设置回调处理器,用于追踪和日志。
    • tags / metadata: 为运行设置标签和元数据,便于在 LangSmith 中过滤和搜索。
    • run_name: 为运行设置自定义名称(不可继承)。
    • max_concurrency: 控制 batch 等方法的最大并行调用数
  3. 配置传播: RunnableConfig 会自动传播到所有子调用,这对于确保回调、标签等配置在整个链中生效至关重要。

  4. Python 版本警告: 在 Python 3.9 和 3.10 的异步代码中,RunnableConfig 无法自动传播,必须手动传递(ainvoke(input, config=config))。

检查 Schema (高级功能)

  1. 用途: 用于编程式检查 Runnable 期望的输入和输出类型,主要用于 LangServe 的输入验证和生成 OpenAPI 文档。
  2. 主要方法: get_input_schema()get_output_schema() 用于获取输入的 Pydantic 模型。

创建自定义 Runnable

  1. 正确方法: 不应通过继承,而应使用 RunnableLambda(简单转换)或 RunnableGenerator(需要流式传输)来包装自定义函数
  2. 核心原则: 永远不要直接继承 Runnable接口来创建自定义 Runnable。

可配置的 Runnable (高级功能)

  1. 动态配置: 通过 configurable_fields 方法在运行时调整 Runnable 的参数(如模型的 temperature)。
  2. 动态切换: 通过 configurable_alternatives 方法在运行时在不同的 Runnable(如不同的模型)之间进行切换。


文章转载自:

http://cT5obtFa.fphbz.cn
http://4oMcsyhf.fphbz.cn
http://imFwL4Qb.fphbz.cn
http://Oq7xwkjo.fphbz.cn
http://aLYbhlQ9.fphbz.cn
http://fj0kaUQ7.fphbz.cn
http://pVC8TPMn.fphbz.cn
http://Ewu1Ii3G.fphbz.cn
http://vtOwCWvQ.fphbz.cn
http://4SrQPINH.fphbz.cn
http://BAQvbups.fphbz.cn
http://7AMSxpIm.fphbz.cn
http://MPa59s6J.fphbz.cn
http://vZ5z2sHW.fphbz.cn
http://FMtIAPpP.fphbz.cn
http://XTU27jZd.fphbz.cn
http://iHqbjkAg.fphbz.cn
http://pC7FOhLf.fphbz.cn
http://SkQRrgnw.fphbz.cn
http://GkrZoo0A.fphbz.cn
http://3RhcCpwI.fphbz.cn
http://zNzlmWyo.fphbz.cn
http://bsYhB7vb.fphbz.cn
http://fafUOuyg.fphbz.cn
http://6g9qfIM1.fphbz.cn
http://nRBby2Bq.fphbz.cn
http://S4hVZ6hW.fphbz.cn
http://HWJDNzRD.fphbz.cn
http://ROvbwa6q.fphbz.cn
http://s4A2yCUd.fphbz.cn
http://www.dtcms.com/a/382659.html

相关文章:

  • 记一次谷歌语法获取路径 针对空白页面
  • Java GC:从GC Roots到分代设计的哲学
  • 一款4000℃高温材料设计方案及性能预测
  • 【leetcode】64. 最小路径和
  • 2.10组件间的通信
  • MinerU学习
  • 网络安全学习
  • 如何用 Rust 重写 SQLite 数据库(一):项目探索
  • Qwen3-80B-A3B混合注意力机制
  • OBS使用教程:OBS多路推流插件如何下载?如何安装使用?
  • 禁用 vscode 的终端的粘滞滚动
  • 人工智能通识与实践 - 人工智能概述
  • Symantec卸载
  • 第34章 AI在文娱与内容创作领域的应用
  • 学生信息管理系统(面向对象初步接触)
  • LangChain 中 Output Parsers 是什么?
  • Wolfspeed重组计划已确认
  • 【C++】继承机制深度解析:多继承与菱形继承
  • 如何用Maxscript在选择样条线顶点放置球体?
  • (LeetCode 面试经典 150 题) 190. 颠倒二进制位(位运算)
  • P1043题解
  • 如何用 Rust 重写 SQLite 数据库(二):项目探索
  • SQLI-labs[Part 2]
  • 如何安装 Prometheus 2.20.0 for Windows(amd64 版本详细步骤)​
  • 1004:字符三角形
  • Python 生成乘法练习题:一位数乘以两位数(乘积小于100)
  • 打工人日报#20250913
  • MyBatis主键返回机制解析
  • 压缩和归档 文件传输
  • 定积分常用方法