恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

LangChain Core API深度解析:从Runnable接口到生产级AI应用构建

  • 首页
  • 资讯中心
  • /
  • LangChain Core API深度解析:从Runnable接口到生产级AI应用构建

相关资讯

小鼠滑膜细胞(滑膜成纤维)分离、培养与鉴定方案protocol 2026/8/13 3:52:10
Kimi K3:开源API代理工具,无缝切换AI模型后端实战指南 2026/8/13 3:47:10
APP内嵌H5开发实战:从性能优化到JSBridge通信的避坑指南 2026/8/13 3:47:10

最新资讯

从Token到智能体:大模型工作原理与提示工程实战指南
Harness Engineering:模型驱动的线束系统工程实践与工具链解析
软件工程核心三图:类图、时序图、活动图实战指南
IEEE 754浮点数标准详解:从二进制表示到编程实战避坑指南
RHEL 9 图形化安装全攻略:从虚拟机配置到系统部署
Loop Engineering:构建自进化软件系统的闭环工程实践

今日推荐

VSCode插件精选:从AI补全到代码规范,打造高效开发环境
如何快速完成文件批量重命名:FreeReNamer终极指南
2026年横评:宁波3大学科小升初机构全面对比

本周热门

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁
如何快速生成中国车牌图片:Python开源工具完整指南
当 LLM 遇见大文档:主流开源项目如何处理上下文超限

本月精选

如何用DamaiHelper实现演唱会门票的智能自动化抢购:完整技术解决方案指南
第4篇:59 倍性能差距的索引瓶颈定位——一次教科书级的全表扫描调优
终极歌词批量下载神器:5分钟解决离线音乐库歌词同步难题

LangChain Core API深度解析:从Runnable接口到生产级AI应用构建

发布时间:2026/8/13 3:52:10
LangChain Core API深度解析:从Runnable接口到生产级AI应用构建 1. 从“玩具”到“工具”为什么必须掌握LangChain Core API如果你最近在折腾大语言模型应用开发大概率听说过LangChain。很多人对它的第一印象是“一个快速搭建AI应用的原型框架”网上随手一搜满屏都是“三行代码调用ChatGPT”、“五分钟搭建一个知识库问答机器人”的教程。这些教程确实能让你快速跑通一个Demo获得即时的成就感。但当你真正想把Demo变成一个稳定、可靠、可维护的生产级应用时往往会发现仅仅停留在“三行代码”的层面你会遇到一堆麻烦Prompt稍微复杂点就难以管理、不同模型供应商的API调用方式各异、应用逻辑和状态管理混乱、错误处理和日志追踪无从下手。这时你就会意识到之前玩的只是LangChain这座冰山露出水面的部分——那些高级的、封装好的组件LCEL, Chains, Agents。而水面之下支撑整个框架稳定运行的基石正是LangChain Core API。掌握Core API意味着你不再是被动使用框架的“调包侠”而是能理解其内部运作机制并能根据自身业务需求进行定制和扩展的“架构师”。你能清晰地定义数据如何流动Runnable接口精确地控制每一步的执行RunnableLambda, RunnableBranch高效地管理对话历史与状态RunnableWithMessageHistory并构建出健壮、可观测的生产级应用。这才是LangChain从“玩具”进阶为“利器”的关键。2. 理解LangChain Core的基石Runnable接口与LCEL要掌握Core API第一个必须啃下的硬骨头就是Runnable接口和以其为核心的LangChain Expression Language (LCEL)。这是整个LangChain Core的设计灵魂理解了它们你就理解了LangChain是如何将复杂的AI应用流程抽象成可组合、可观测的“管道”的。2.1 Runnable接口一切皆可“运行”在LangChain Core的世界里几乎所有组件——一个简单的Prompt模板、一次LLM调用、一个输出解析器甚至是你自定义的一个数据处理函数——都可以被包装成一个Runnable对象。Runnable定义了一个最基础的契约它必须有一个invoke或batch方法接收输入产生输出。这种抽象带来的最大好处是一致性。无论底层是调用OpenAI的GPT-4还是处理一段文本抑或是访问一个数据库在应用流程的视角看来它们都是一个个可以连接起来的“黑盒”。你不需要关心每个黑盒内部的具体实现只需要知道它们接收什么、输出什么然后用管道操作符|把它们串起来。from langchain_core.runnables import RunnableLambda from langchain_openai import ChatOpenAI from langchain_core.prompts import ChatPromptTemplate # 1. 一个自定义函数可以被包装成Runnable def extract_keyword(text: str) - str: # 假设这里有一些简单的关键词提取逻辑 return text.split()[0] if text else custom_runnable RunnableLambda(extract_keyword) # 2. 一个标准的Prompt模板也是Runnable prompt_template ChatPromptTemplate.from_template(请总结这段话的核心思想{input}) # 3. 大语言模型同样是Runnable llm ChatOpenAI(modelgpt-4) # 4. 用LCEL的管道操作符将它们组合起来 chain custom_runnable | prompt_template | llm # 现在chain本身也是一个Runnable result chain.invoke(今天天气晴朗非常适合户外运动。) print(result.content) # 输出模型总结的核心思想在上面的例子中custom_runnable、prompt_template、llm都是Runnable。通过|操作符我们定义了一个数据流输入文本先经过自定义函数提取关键词然后将关键词填入Prompt模板最后送给LLM生成总结。整个链条清晰、声明式并且每个环节都可以独立测试和替换。注意RunnableLambda是将任意Python函数转换为Runnable的桥梁。但这里有一个关键细节函数最好有明确的输入输出类型注解如str - str这不仅能提高代码可读性在一些高级特性如流式输出、异步支持中也能获得更好的兼容性。2.2 LCEL声明式的编排语言LCEL不是一门新的编程语言而是一套基于Python操作符重载的DSL领域特定语言。它的核心就是管道操作符|。LCEL让你能用近乎自然语言的方式描述应用的工作流代码的可读性和可维护性极高。更重要的是LCEL不仅仅是语法糖。任何由LCEL组合而成的链条都自动获得了以下生产级特性流式输出 (Streaming) 只需调用chain.stream()即可逐词获取LLM的输出无需额外配置。异步支持 (Async) 天然支持ainvoke()和astream()便于构建高性能的并发应用。批量处理 (Batch) 调用chain.batch()可以并行处理多个输入提升吞吐量。日志与追踪 (Logging Tracing) 每个Runnable的执行过程都可以被LangSmith等工具追踪方便调试和监控。并行执行 (Parallel) 通过RunnableParallel可以轻松实现分支与合并。如果你只用高级的LLMChain要实现流式输出可能需要额外配置回调函数而用LCEL这是内置的、开箱即用的能力。这就是掌握Core API带来的降维打击——你用的不是封装好的“功能”而是构建功能的“原语”。3. 核心Runnable原语详解构建复杂逻辑的积木掌握了Runnable和 LCEL 的思想后我们需要认识一批最常用、最核心的Runnable原语。它们就像乐高积木不同的组合能搭建出形态各异的AI应用。3.1 RunnableLambda注入自定义逻辑RunnableLambda是你的瑞士军刀用于将任何不符合Runnable接口的代码接入LCEL管道。它非常灵活但使用时需注意几个要点输入/输出格式RunnableLambda包装的函数其输入和输出应该与管道中相邻环节匹配。如果前一个环节输出一个字典那么你的函数就应该接收一个字典作为参数。错误处理在管道中一个环节出错会导致整个链条中断。建议在自定义函数内部做好健壮性处理如try-catch或者考虑使用RunnableLambda的config参数来配置重试策略。from langchain_core.runnables import RunnableLambda def complex_processor(data: dict) - dict: 假设前一个环节输出 {query: 用户问题, history: [...]} 这个函数负责一些复杂的业务逻辑比如查询数据库、调用外部API等。 try: user_query data.get(query, ) # ... 这里是一些复杂的业务逻辑 ... enriched_data { original_query: user_query, processed_query: user_query.upper(), # 示例处理 external_context: 从数据库查到的相关信息 } # 将处理后的数据与原始数据合并传递给下一环节 return {**data, **enriched_data} except Exception as e: # 良好的错误处理可以返回一个兜底数据而不是让整个链条崩溃 print(f处理器出错: {e}) return {**data, processed_query: data.get(query, ), external_context: } # 将业务逻辑函数包装成管道的一环 business_logic_step RunnableLambda(complex_processor) # 在链中使用 chain some_previous_step | business_logic_step | llm3.2 RunnableBranch实现条件路由很多复杂的AI应用需要根据输入内容走不同的处理分支。RunnableBranch就是实现这一功能的“路由器”。它接收一个由(条件, Runnable)对组成的列表以及一个默认的Runnable。from langchain_core.runnables import RunnableBranch # 定义条件判断函数 def is_greeting(input: str) - bool: return input.lower().strip() in [你好, hi, hello] def needs_translation(input: str) - bool: # 简单判断是否包含中文非严谨 return any(\u4e00 char \u9fff for char in input) # 定义不同分支的处理逻辑 greeting_chain ChatPromptTemplate.from_template(友好地回应问候{input}) | llm translation_chain ChatPromptTemplate.from_template(将以下英文翻译成中文{input}) | llm general_chain ChatPromptTemplate.from_template(请回答以下问题{input}) | llm # 构建分支路由 branch RunnableBranch( (is_greeting, greeting_chain), (needs_translation, translation_chain), general_chain # 默认分支 ) # 使用 print(branch.invoke(你好)) # 走问候分支 print(branch.invoke(What is AI?)) # 走翻译分支假设判断逻辑生效 print(branch.invoke(讲一个故事)) # 走默认的问答分支关键点条件函数如is_greeting的输入是流入RunnableBranch的原始输入而不是上一个环节处理后的输出。你需要根据业务逻辑仔细设计条件判断。3.3 RunnableParallel并行处理与结果合并当你的应用需要同时做多件事情时比如既需要查询知识库又需要分析用户情绪RunnableParallel就派上用场了。它允许你并行执行多个Runnable并将它们的结果合并成一个字典。from langchain_core.runnables import RunnableParallel # 假设我们有几个并行的处理任务 fetch_facts RunnableLambda(lambda x: {facts: f关于{x}的百科知识}) analyze_sentiment RunnableLambda(lambda x: {sentiment: 积极 if 好 in x else 中性}) check_grammar RunnableLambda(lambda x: {grammar_errors: []}) # 构建并行处理步骤 parallel_step RunnableParallel({ retrieved_facts: fetch_facts, mood: analyze_sentiment, language_check: check_grammar }) # 在链中使用先并行处理再将并行结果传递给LLM进行综合 prompt ChatPromptTemplate.from_template( 基于以下信息综合回答用户的问题。 用户问题{question} 检索到的事实{retrieved_facts} 用户情绪{mood} 语言检查结果{language_check} 请生成回答 ) chain parallel_step | prompt | llm result chain.invoke({question: 今天的天气好吗})这种模式在RAG检索增强生成应用中非常常见并行执行检索和查询理解然后将结果一并送入生成环节。3.4 RunnableWithMessageHistory管理对话状态对于聊天机器人管理对话历史是核心需求。RunnableWithMessageHistory专门用于此。它包装一个普通的Runnable通常是一个LCEL链并自动为其注入历史消息列表。from langchain_core.chat_history import BaseChatMessageHistory from langchain_core.runnables import RunnableWithMessageHistory from langchain_community.chat_message_histories import ChatMessageHistory from langchain_core.prompts import MessagesPlaceholder # 1. 定义一个存储历史的后端这里用内存存储示例 store {} def get_session_history(session_id: str) - BaseChatMessageHistory: if session_id not in store: store[session_id] ChatMessageHistory() return store[session_id] # 2. 构建一个需要历史记录的链 prompt ChatPromptTemplate.from_messages([ (system, 你是一个乐于助人的助手。), MessagesPlaceholder(variable_namehistory), # 关键预留历史消息的位置 (human, {input}) ]) chain prompt | llm # 3. 用 RunnableWithMessageHistory 包装这个链 conversational_chain RunnableWithMessageHistory( chain, get_session_history, # 获取历史存储的函数 input_messages_keyinput, # 输入中用户消息的键 history_messages_keyhistory, # Prompt中历史消息的键 ) # 4. 使用需要指定session_id来区分不同对话 config {configurable: {session_id: user123}} response1 conversational_chain.invoke({input: 你好我叫小明}, configconfig) print(response1.content) # 输出: 你好小明很高兴认识你 response2 conversational_chain.invoke({input: 你还记得我叫什么吗}, configconfig) # 由于历史被注入模型能回答“你叫小明”踩坑点MessagesPlaceholder必不可少 你的Prompt模板中必须使用MessagesPlaceholder来指定历史消息插入的位置并且其variable_name必须与RunnableWithMessageHistory的history_messages_key参数一致。config参数是必须的 调用被包装后的链时必须传入config参数来指明session_id否则框架不知道从哪里获取历史。这是新手最容易忘记的一点会导致运行时错误。历史存储的选择 示例中使用的是内存字典生产环境中必须替换为持久化存储如Redis、PostgreSQL或专为LangChain设计的LangChainHub。4. 深入配置系统从静态链到动态应用一个基础的链是静态的但真实的应用需要动态行为根据用户身份切换模型、在运行时调整Prompt参数、为不同环节设置不同的超时和重试策略。这就需要用到LangChain Core的配置系统Configurable。4.1 可配置字段ConfigurableFields你可以将链中的任何Runnable标记为“可配置的”从而在运行时动态改变其行为。最常见的应用是动态切换LLM模型或Prompt。from langchain_core.runnables import ConfigurableField from langchain_openai import ChatOpenAI from langchain_anthropic import ChatAnthropic # 创建一个可配置的LLM llm ChatOpenAI(modelgpt-3.5-turbo).configurable_fields( model_nameConfigurableField( idmodel, nameLLM Model, description选择要使用的LLM模型, ) ) # 现在我们可以通过配置来动态切换这个llm的实际实现 # 定义备选模型 llm_with_alternatives llm.configurable_alternatives( ConfigurableField(idmodel), default_keyopenai_gpt35, anthropic_claudeChatAnthropic(modelclaude-3-haiku), openai_gpt4ChatOpenAI(modelgpt-4), ) # 构建一个简单的链 prompt ChatPromptTemplate.from_template(用{style}风格回答{question}) chain prompt | llm_with_alternatives # 运行时配置选择不同的模型 response1 chain.invoke( {style: 幽默, question: 什么是人工智能}, config{configurable: {model: openai_gpt4}} # 使用GPT-4 ) response2 chain.invoke( {style: 严谨, question: 什么是人工智能}, config{configurable: {model: anthropic_claude}} # 使用Claude )这个功能在A/B测试不同模型效果、为付费用户提供更强大的模型、或者根据查询复杂度自动选择性价比最高的模型时非常有用。4.2 可配置方法ConfigurableMethods与运行时参数除了替换整个Runnable你还可以动态调整Runnable的内部参数。例如根据输入内容动态调整LLM的temperature创造性参数。from langchain_core.runnables import ConfigurableField, RunnableConfig from langchain_core.prompts import ChatPromptTemplate def dynamic_temperature(input_dict: dict, config: RunnableConfig) - float: 根据用户问题的长度动态决定temperature question input_dict.get(question, ) question_length len(question) if question_length 100: return 0.2 # 长问题需要更确定性的回答 else: return 0.7 # 短问题可以更有创造性 # 创建一个可配置temperature的LLM llm ChatOpenAI(modelgpt-3.5-turbo, temperature0.5).configurable_fields( temperatureConfigurableField( idtemperature, nameTemperature, description控制输出的随机性, ) ) # 构建链并在Prompt后插入一个动态设置配置的步骤 from langchain_core.runnables import RunnablePassthrough def configure_params(input_dict: dict): # 这里可以基于输入计算复杂的配置逻辑 temp dynamic_temperature(input_dict, None) # 返回一个更新后的config字典 return {configurable: {temperature: temp}} chain ( RunnablePassthrough.assign() # 保留原始输入 | RunnableLambda(configure_params) # 动态生成配置 | llm ) # 注意这种模式需要链能正确处理传递下来的config。更常见的做法是使用“绑定”模式。 # 更优雅的方式使用 bind 方法在运行时绑定参数 simple_prompt ChatPromptTemplate.from_template(回答{question}) simple_chain simple_prompt | llm # 对于简单链可以直接在invoke时通过config传递 response simple_chain.invoke( {question: 讲一个长故事}, config{configurable: {temperature: 0.2}} )经验之谈配置系统功能强大但也增加了复杂性。对于大多数应用我建议先从简单的、静态的链开始。只有当你有明确的动态需求如多租户模型切换、复杂的运行时参数计算时再引入可配置字段。过度设计会让代码难以理解和调试。5. 生产化实践错误处理、日志与监控一个能在实验室跑通的链距离在生产环境稳定运行还差着“错误处理”、“日志”和“监控”这三道关卡。LangChain Core提供了相应的工具来帮助你闯关。5.1 健壮的错误处理with_fallbacks网络会波动API会限流模型会返回莫名其妙的内容。你的应用必须能优雅地应对这些故障。with_fallbacks方法可以为任何Runnable添加后备方案。from langchain_core.runnables import RunnableWithFallbacks primary_llm ChatOpenAI(modelgpt-4, temperature0) fallback_llm ChatOpenAI(modelgpt-3.5-turbo, temperature0) # 备用模型 # 为主模型添加后备链 robust_llm primary_llm.with_fallbacks([fallback_llm]) prompt ChatPromptTemplate.from_template(回答{query}) chain prompt | robust_llm try: # 当primary_llm因任何原因超时、API错误等调用失败时 # 会自动尝试使用fallback_llm result chain.invoke({query: 复杂问题...}) except Exception as e: # 如果所有后备也都失败了才会抛出异常 print(f所有LLM调用均失败: {e}) # 这里可以执行更进一步的兜底逻辑比如返回一个预设的答案 result 抱歉服务暂时不可用。高级技巧后备链不一定非得是另一个LLM。它可以是一个返回静态回复的RunnableLambda也可以是一个更简单、更稳定的检索流程。你可以设计多层级的后备策略确保核心服务的高可用。5.2 全面的日志与追踪LangSmith集成“为什么这次生成的回答这么差” 没有日志和追踪排查这种问题就像大海捞针。LangChain官方推出的LangSmith平台与Core API无缝集成提供了强大的可观测性。import os from langsmith import Client from langchain_core.tracers import LangChainTracer # 设置环境变量通常在应用启动时设置 os.environ[LANGCHAIN_TRACING_V2] true os.environ[LANGCHAIN_ENDPOINT] https://api.smith.langchain.com os.environ[LANGCHAIN_API_KEY] your-api-key os.environ[LANGCHAIN_PROJECT] my-production-project # 指定项目名 # 当你使用LCEL构建的链执行时追踪信息会自动发送到LangSmith chain prompt | llm result chain.invoke({query: test query}) # 在LangSmith控制台你可以看到这次调用的完整链路 # 1. PromptTemplate的输入输出 # 2. LLM调用的请求参数和返回结果 # 3. 每个步骤的耗时 # 4. Token使用量如果供应商支持生产环境必备即使你不使用LangSmith的商业服务也强烈建议在开发阶段启用它。它能帮你可视化整个调用链精确找出性能瓶颈是Prompt太长还是某个检索步骤太慢和错误根源。对于团队协作和后期迭代优化这是不可或缺的工具。5.3 超时与重试配置远程服务调用必须设置超时并对可重试的错误如网络抖动、速率限制进行重试。LangChain Core的很多组件都支持通过config参数进行精细控制。from langchain_core.runnables import RunnableConfig # 方法1在构建时指定适用于该Runnable的所有调用 llm_with_timeout ChatOpenAI( modelgpt-3.5-turbo, request_timeout30.0, # 单次请求超时30秒 max_retries2, # 自动重试2次 ) # 方法2在调用时通过config指定更灵活 config RunnableConfig( max_concurrency5, # 最大并发数 timeout60, # 整个链的超时时间 # 一些Runnable有自己特定的配置项可以通过configurable传递 configurable{llm_timeout: 15} ) try: result chain.invoke({query: ...}, configconfig) except TimeoutError: print(处理超时)重要提示超时设置需要权衡。设置太短会导致不必要的失败设置太长会拖慢整个系统的响应并在上游服务故障时耗尽你的资源。通常建议为LLM调用设置15-30秒的超时并为整个端到端链条设置一个更长的总超时如60秒。6. 从Core API出发构建你自己的高级抽象当你熟练运用上述Core API的原语后你会发现LangChain官方提供的那些高级Chain和Agent本质上也是用这些原语搭建起来的。此时你就可以不再满足于使用现成的组件而是开始构建符合自己业务需求的、独一无二的抽象。例如你可以构建一个专门用于处理客户工单的“工单分析链”from typing import List, Dict, Any from langchain_core.runnables import RunnableParallel, RunnableLambda, RunnableSequence from langchain_core.prompts import ChatPromptTemplate from langchain_openai import ChatOpenAI from pydantic import BaseModel, Field # 1. 定义你的输出数据结构使用Pydantic class TicketAnalysis(BaseModel): urgency: str Field(description紧急程度高、中、低) category: str Field(description问题分类技术、账单、账户、其他) summary: str Field(description问题摘要) suggested_response: str Field(description建议的回复模板) # 2. 用Core API原语搭建专属链条 class TicketAnalysisChain: def __init__(self, llm): self.llm llm self._chain self._build_chain() def _build_chain(self): # 步骤1并行提取关键信息 extractors RunnableParallel({ entities: RunnableLambda(self._extract_entities), # 提取实体 sentiment: RunnableLambda(self._analyze_sentiment), # 情感分析 }) # 步骤2构建分析Prompt analysis_prompt ChatPromptTemplate.from_template( 你是一个资深的客户支持分析师。请分析以下工单内容。 客户原始描述 {ticket_description} 提取到的关键实体{entities} 情感倾向{sentiment} 请严格按照以下JSON格式输出分析结果 {{ urgency: 高/中/低, category: 技术/账单/账户/其他, summary: 不超过50字的摘要, suggested_response: 一个初步的回复建议 }} ) # 步骤3使用Pydantic格式输出解析器这是LangChain的高级组件但其底层也是Runnable from langchain_core.output_parsers import PydanticOutputParser parser PydanticOutputParser(pydantic_objectTicketAnalysis) # 步骤4组装完整链条 chain ( extractors | analysis_prompt | self.llm | parser ) return chain def _extract_entities(self, input_dict: Dict) - Dict: # 这里可以集成NER模型或规则 ticket input_dict[ticket_description] # 简化示例 entities [] if 登录 in ticket or 密码 in ticket: entities.append(账户问题) if 扣费 in ticket or 退款 in ticket: entities.append(财务问题) return {entities: , .join(entities) if entities else 无} def _analyze_sentiment(self, input_dict: Dict) - Dict: ticket input_dict[ticket_description] # 简化示例 if any(word in ticket for word in [急, 尽快, 无法使用, 糟糕]): sentiment 负面且急切 elif 谢谢 in ticket or 请 in ticket: sentiment 正面且礼貌 else: sentiment 中性 return {sentiment: sentiment} def analyze(self, ticket_description: str) - TicketAnalysis: 对外暴露的简洁接口 return self._chain.invoke({ticket_description: ticket_description}) # 使用你自定义的高级链 llm ChatOpenAI(modelgpt-4, temperature0) analyzer TicketAnalysisChain(llm) ticket 我的账号从昨晚开始就一直登录不上提示密码错误但我确定密码没错。这严重影响我工作了请尽快解决 result analyzer.analyze(ticket) print(f紧急程度: {result.urgency}) print(f问题分类: {result.category}) print(f摘要: {result.summary}) print(f建议回复: {result.suggested_response})通过这种方式你将业务逻辑工单分析封装成了一个内聚的、可测试的、易于使用的类。内部利用Core API的原语实现复杂流程对外则提供干净的接口。这才是掌握LangChain Core API的终极目标让你拥有将任意AI想法快速、稳健地转化为现实应用的能力。你不再受限于框架预设的范式而是能够自由地设计和实现最适合自己业务的技术架构。

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号