资讯详情

Haystack Extractors 组件深度指南:LLM 文档内容抽取、元数据生成、NER 命名实体识别与正则文本提取

📅 2026/9/15 1:52:06 | 华诺云谱 👁 阅读
Haystack Extractors 组件深度指南:LLM 文档内容抽取、元数据生成、NER 命名实体识别与正则文本提取
Haystack Extractors 组件深度指南LLM 文档内容抽取、元数据生成、NER 命名实体识别与正则文本提取【免费下载链接】haystackOpen-source AI orchestration framework for building context-engineered, production-ready LLM applications. Design modular pipelines and agent workflows with explicit control over retrieval, routing, memory, and generation. Built for scalable agents, RAG, multimodal applications, semantic search, and conversational systems.项目地址: https://gitcode.com/GitHub_Trending/ha/haystack本篇技术指南以 Haystack 2.22 参考文档 extractors_api.md 为骨架系统讲解 Haystack 的 Extractors提取器组件族LLMDocumentContentExtractor视觉大模型抽取图片/扫描件文本、LLMMetadataExtractorLLM 生成文档元数据、NamedEntityExtractor基于 Hugging Face / spaCy 的命名实体识别与RegexTextExtractor正则表达式提取片段。读完本文你将掌握每个组件的初始化参数、运行契约、失败处理机制、序列化方式以及如何把它们编排进索引/问答 Pipeline并理解其底层源码实现与测试验证。一、Extractors 组件族概览Haystack 的 Extractors 是一组负责从文本或文档中提取特定元素的组件典型用途包括把图片型文档变成可检索文本、为文档补充可用于过滤与检索的元数据、识别命名实体、从 LLM 输出中解析结构化片段。它们在 Pipeline 中通常位于预处理索引侧之后或在查询侧跟随 Retriever / Generator。组件核心能力源码位置LLMDocumentContentExtractor用视觉大模型从图片型文档中抽取文本内容haystack/components/extractors/image/llm_document_content_extractor.pyLLMMetadataExtractor用 LLM 按提示词为文档生成元数据haystack/components/extractors/llm_metadata_extractor.pyNamedEntityExtractor用 Hugging Face / spaCy 模型做命名实体识别并写入 meta2.22 时代位于 haystack/components/extractors/named_entity_extractor.py后续版本已迁往独立集成包RegexTextExtractor用正则表达式从字符串或ChatMessage中提取文本haystack/components/extractors/regex_text_extractor.py二、LLMDocumentContentExtractor视觉大模型驱动的文档内容抽取LLMDocumentContentExtractor面向以图片为载体的文档扫描件、含文字的图片、PDF 页面利用具备视觉能力的 Chat Generator 把图像内容转化为结构化文本。它的典型应用场景是把不可检索的图片型文档转成可搜索文本再交给后续切分与写入组件。2.1 工作原理组件按如下三步工作与参考文档描述一致通过DocumentToImageContent组件把每个输入文档转换为图像源码导入使用一段预先定义好的提示词prompt指导 LLM 如何抽取内容把图像 提示词一起作为一条 Chat Message 交给支持视觉输入的ChatGenerator抽取结构化文本。提示词中不允许包含任何变量提示词只能包含抽取指令不能有 Jinja 变量。源码在初始化时通过_validate_prompt_no_variables用沙箱化 Jinja 环境解析并检测未声明变量一旦发现就抛出ValueError见 llm_document_content_extractor.py#L245-L254。这意味着提示词不能像PromptBuilder那样被动态填充——文档的图像数据本身即是变量。2.2 初始化参数def __init__(*, chat_generator: ChatGenerator, prompt: str DEFAULT_PROMPT_TEMPLATE, file_path_meta_field: str file_path, root_path: str | None None, detail: Literal[auto, high, low] | None None, size: tuple[int, int] | None None, raise_on_failure: bool False, max_workers: int 3)参数类型说明chat_generatorChatGenerator必填负责生成文本的 LLM必须支持视觉输入并返回纯文本回复promptstr提供给 LLM 的抽取指令不得包含 Jinja 变量默认使用DEFAULT_PROMPT_TEMPLATEfile_path_meta_fieldstr file_pathDocument 元数据中存放图片/PDF 文件路径的字段名root_pathstr \| None文档文件所在根目录。提供后元数据中的文件路径将相对该目录解析并保证不会越出该目录为None时按绝对路径处理且不做包含性校验detailauto \| high \| low \| None图像细节级别仅 OpenAI 支持会透传给chat_generatorsizetuple[int, int] \| None若提供则把图像等比缩放到 (width, height) 范围内降低文件体积、内存占用与处理耗时适合有分辨率约束的模型或需远程传输图像的场景raise_on_failurebool False为True时 LLM 抛出的异常直接上抛为False时记录日志并把失败文档返回max_workersint 3用ThreadPoolExecutor并行调用 LLM 的最大线程数其中root_path带有安全语义组件会读取file_path_meta_field指向的主机文件。若文档元数据可能受不可信输入影响应设置root_path为专用数据目录以拒绝路径穿越载荷绝对路径或../。组件内部正是把file_path_meta_field、root_path、detail、size透传构造了DocumentToImageContent见 llm_document_content_extractor.py#L175-L177。2.3 使用示例参考文档给出的最小用法如下from haystack import Document from haystack.components.generators.chat import OpenAIChatGenerator from haystack.components.extractors.image import LLMDocumentContentExtractor chat_generator OpenAIChatGenerator() extractor LLMDocumentContentExtractor(chat_generatorchat_generator) documents [ Document(content, meta{file_path: image.jpg}), Document(content, meta{file_path: document.pdf, page_number: 1}), ] updated_documents extractor.run(documentsdocuments)[documents] print(updated_documents) # [Document(contentExtracted text from image.jpg, # meta{file_path: image.jpg}), # ...]注意输入文档的content可以为空但必须在元数据中携带有效文件路径字段名由file_path_meta_field指定默认为file_path对于 PDF 场景可以像第二个文档那样通过page_number指定要渲染的页面。2.4 响应处理与失败机制run的签名与返回契约如下component.output_types(documentslist[Document], failed_documentslist[Document]) def run(documents: list[Document]) - dict[str, list[Document]]documents抽取成功的文档content已被更新failed_documents抽取失败的文档元数据中带有失败说明。参考文档version-2.22中失败文档的元数据键名为content_extraction_error。需要留意的是当前主线源码中的_process_llm_results实际写入的键名是extraction_error见 llm_document_content_extractor.py#L346-L371且成功重跑时会自动清除旧的错误字段——以你实际安装版本为准。源码对 LLM 回复做了统一解析_process_responsellm_document_content_extractor.py#L256-L274存在三种结果形态纯字符串回复非 JSON整段回复直接写入文档contentJSON 对象且仅含document_content键该键的值写入contentJSON 对象且含多个键document_content的值写入content其余键值合并进文档元数据。因此如果你想让 LLM 同时返回正文与结构化元数据如作者、日期、文档类型可以用generation_kwargs配置结构化输出chat_generator OpenAIChatGenerator( generation_kwargs{ response_format: { type: json_schema, json_schema: { name: entity_extraction, schema: { type: object, properties: { document_content: {type: string}, author: {type: string}, date: {type: string}, document_type: {type: string}, title: {type: string}, }, additionalProperties: False, }, }, } } )2.5 并行与异步执行组件用ThreadPoolExecutor(max_workersself.max_workers)对每个文档的 LLM 调用做线程级并行llm_document_content_extractor.py#L392-L393同时提供run_async使用asyncio.Semaphore(max(1, self.max_workers))限制并发兼容不支持异步的 Chat Generator自动回退到线程执行见 llm_document_content_extractor.py#L406-L451。warm_up/warm_up_async会在有对应方法时预热底层 Chat Generatorclose/close_async负责释放资源。此外组件还支持to_dict/from_dict序列化from_dict会通过deserialize_chatgenerator_inplace就地反序列化嵌套的chat_generatorllm_document_content_extractor.py#L230-L243。对应的行为均有测试覆盖例如混合成功/失败场景、纯字符串回复写入 content、非对象 JSON 报错、多键 JSON 元数据合并、重跑清除旧错误字段等见 test/components/extractors/image/test_llm_document_content_extractor.py。2.6 在 Pipeline 中使用from haystack import Pipeline from haystack.components.extractors.image import LLMDocumentContentExtractor from haystack.components.generators.chat import OpenAIChatGenerator from haystack.components.preprocessors import DocumentSplitter from haystack.components.writers import DocumentWriter from haystack.document_stores.in_memory import InMemoryDocumentStore from haystack import Document document_store InMemoryDocumentStore() p Pipeline() p.add_component( instanceLLMDocumentContentExtractor( chat_generatorOpenAIChatGenerator(modelgpt-4o-mini), file_path_meta_fieldfile_path, ), namecontent_extractor, ) p.add_component(instanceDocumentSplitter(), namesplitter) p.add_component(instanceDocumentWriter(document_storedocument_store), namewriter) p.connect(content_extractor.documents, splitter.documents) p.connect(splitter.documents, writer.documents) docs [ Document(content, meta{file_path: scanned_document.pdf}), Document(content, meta{file_path: image_with_text.jpg}), ] result p.run({content_extractor: {documents: docs}}) print(len(result[content_extractor][documents])) print(len(result[content_extractor][failed_documents]))三、LLMMetadataExtractor用 LLM 为文档生成元数据LLMMetadataExtractor通过提示词让 LLM 从文档中抽取结构化元数据如命名实体、主题标签、摘要字段并把结果合并进文档的meta字段供后续过滤、路由或检索使用。3.1 工作原理与提示词约束组件在初始化时接收一个prompt和一个ChatGenerator。提示词中必须且只能包含一个名为document的变量它指向文档列表中的单个文档因此访问正文用{{ document.content }}。源码在__init__中用沙箱化 Jinja 环境解析提示词并校验变量列表若变量数不为 1 或名称不是document直接抛出ValueError见 llm_metadata_extractor.py#L186-L194。校验通过后组件内部组合了PromptBuilder负责把每个文档渲染进提示词与DocumentSplitter(split_bypage, split_length1)负责按页切分以支持page_range见 llm_metadata_extractor.py#L195-L198。3.2 完整使用示例命名实体抽取参考文档给出了一个完整的 NER 元数据抽取示例提示词采用目标-步骤-示例-真实数据的结构化模板from haystack import Document from haystack.components.extractors.llm_metadata_extractor import LLMMetadataExtractor from haystack.components.generators.chat import OpenAIChatGenerator NER_PROMPT -Goal- Given text and a list of entity types, identify all entities of those types from the text. -Steps- 1. Identify all entities. For each identified entity, extract the following information: - entity: Name of the entity - entity_type: One of the following types: [organization, product, service, industry] Format each entity as a JSON like: {entity: entity_name, entity_type: entity_type} 2. Return output in a single list with all the entities identified in steps 1. -Examples- ###################### Example 1: entity_types: [organization, person, partnership, financial metric, product, service, industry, investment strategy, market trend] text: Another area of strength is our co-brand issuance. Visa is the primary network partner for eight of the top 10 co-brand partnerships in the US today and we are pleased that Visa has finalized a multi-year extension of our successful credit co-branded partnership with Alaska Airlines, a portfolio that benefits from a loyal customer base and high cross-border usage. ... output: {entities: [{entity: Visa, entity_type: company}, {entity: Alaska Airlines, entity_type: company}, ...]} ############################# -Real Data- ###################### entity_types: [company, organization, person, country, product, service] text: {{ document.content }} ###################### output: docs [ Document(contentdeepset was founded in 2018 in Berlin, and is known for its Haystack framework), Document(contentHugging Face is a company that was founded in New York, USA and is known for its Transformers library) ] chat_generator OpenAIChatGenerator( generation_kwargs{ max_completion_tokens: 500, temperature: 0.0, seed: 0, response_format: {type: json_object}, }, max_retries1, timeout60.0, ) extractor LLMMetadataExtractor( promptNER_PROMPT, chat_generatorchat_generator, expected_keys[entities], raise_on_failureFalse, ) extractor.warm_up() extractor.run(documentsdocs) # {documents: [ # Document(id.., content: deepset was founded in 2018 in Berlin, ..., # meta: {entities: [{entity: deepset, entity_type: company}, # {entity: Berlin, entity_type: city}, # {entity: Haystack, entity_type: product}]}), # ... # ], failed_documents: []}关键配置点为了让组件正常工作Chat Generator 必须配置为返回 JSON 对象。使用OpenAIChatGenerator时在generation_kwargs中传入{response_format: {type: json_object}}也可以使用json_schema方式强制输出结构如上文LLMDocumentContentExtractor一节所示。当前实现支持OpenAIChatGenerator、AzureOpenAIChatGenerator、AmazonBedrockChatGenerator、VertexAIGeminiChatGenerator等 Haystack Chat Generator。3.3 初始化参数def __init__(prompt: str, chat_generator: ChatGenerator, expected_keys: list[str] | None None, page_range: list[str | int] | None None, raise_on_failure: bool False, max_workers: int 3)参数类型说明promptstr必填提供给 LLM 的抽取提示词必须恰好包含一个名为document的变量chat_generatorChatGenerator必填代表 LLM需配置为返回 JSON 对象expected_keyslist[str] \| None期望 LLM JSON 输出中出现的键解析时用于校验见下方失败处理page_rangelist[str \| int] \| None仅对指定页码范围抽取元数据可在run中覆盖raise_on_failurebool False生成器执行或 JSON 校验失败时是否抛错max_workersint 3线程池最大工作线程数同时限制run_async的最大并发请求数3.4 page_range按页抽取page_range支持单页与可打印区间字符串两种形式page_range[1, 3]抽取每个文档的第 1 页与第 3 页page_range[1-3, 5, 8, 10-12]抽取第 1、2、3、5、8、10、11、12 页。为None时对每个文档的全文抽取。run方法同样接受可选的page_range参数以覆盖初始化时的设置。实现上区间字符串通过expand_page_range来自haystack.utils展开为具体页码列表组件先用内置DocumentSplitter按页切分文档再只把目标页内容拼接进提示词见 llm_metadata_extractor.py#L271-L298。3.5 失败处理与重跑机制component.output_types(documentslist[Document], failed_documentslist[Document]) def run(documents: list[Document], page_range: list[str | int] | None None)documents成功抽取并合并元数据的文档failed_documents抽取失败的文档其元数据中带有metadata_extraction_error与metadata_extraction_response两个键。metadata_extraction_error描述失败原因LLM 调用异常、回复不是合法 JSON、或缺少expected_keys中的键metadata_extraction_response保存原始回复。这两者的组合让失败重跑成为可能你可以把失败文档连同错误信息喂给另一个抽取器或同一抽取器的修正提示词再次尝试。成功重跑后旧的metadata_extraction_error/metadata_extraction_response会被自动清除见 llm_metadata_extractor.py#L344-L379。另外两个值得注意的细节空content的文档会被跳过并放入failed_documents错误信息为 Document has no content, skipping LLM call.即使expected_keys中恰好包含error这样的键只要 LLM 返回了合法 JSON该键也会被当作正常抽取结果而非失败——这两点都有对应测试覆盖见 test/components/extractors/test_llm_metadata_extractor.py。与内容抽取器一致该组件同样具备warm_up/warm_up_async预热生成器与切分器、close/close_async、to_dict/from_dict序列化from_dict同样就地反序列化嵌套的chat_generator以及线程池并行run与信号量限流的异步执行run_async。四、NamedEntityExtractor基于 Hugging Face / spaCy 的命名实体识别NamedEntityExtractor从一段文本中识别预定义实体人名、组织、地点等并把识别结果写入文档的meta字段。它适用于索引流水线中预处理之后或在查询流水线中跟随 Retriever为下游提供实体级别的结构信息。4.1 后端与注解数据结构组件支持两种 NLP 后端NamedEntityExtractorBackend.HUGGING_FACE使用 Hugging Face 模型与 pipelineNamedEntityExtractorBackend.SPACY使用 spaCy 模型与 pipeline。两者都可与各自生态中支持 token 分类 / NER 的模型配合使用如dslim/bert-base-NER、en_core_web_sm。后端枚举还提供from_str静态方法把字符串转换为枚举值。每个识别结果是一个NamedEntityAnnotation包含四个字段字段说明entity实体标签如PER、LOCstart实体在文档中的起始下标end实体在文档中的结束下标score模型给出的置信度分数例如NamedEntityAnnotation(entityPER, start11, end16, score0.9)。4.2 初始化与运行def __init__( *, backend: str | NamedEntityExtractorBackend, model: str, pipeline_kwargs: dict[str, Any] | None None, device: ComponentDevice | None None, token: Secret | None Secret.from_env_var([HF_API_TOKEN, HF_TOKEN], strictFalse) ) - None参数说明backend使用的 NER 后端取hugging_face或spacymodel模型名称或本地磁盘模型路径取决于后端pipeline_kwargs透传给 HF / spaCy pipeline 的关键字参数device模型加载设备为None时自动选择默认设备。若在pipeline_kwargs中指定了 device / device map则优先生效仅 HF 后端token用于从 Hugging Face 下载私有模型的 API Token默认从HF_API_TOKEN/HF_TOKEN环境变量读取非强制使用示例from haystack import Document from haystack.components.extractors.named_entity_extractor import NamedEntityExtractor documents [ Document(contentIm Merlin, the happy pig!), Document(contentMy name is Clara and I live in Berkeley, California.), ] extractor NamedEntityExtractor(backendhugging_face, modeldslim/bert-base-NER) extractor.warm_up() results extractor.run(documentsdocuments)[documents] annotations [NamedEntityExtractor.get_stored_annotations(doc) for doc in results] print(annotations)warm_up()负责初始化组件加载模型后端初始化失败时抛出ComponentErrorrun(documents, batch_size1)对每个文档标注实体batch_size控制处理批大小注解存入文档meta的named_entities键下initialized属性返回抽取器是否已就绪get_stored_annotations(document)类方法透明地读取文档中存储的注解列表若文档没有注解则返回None。参考文档还展示了更完整的输入输出形态输入三个文档输出meta中带有named_entities列表例如Document(..., meta: {named_entities: [NamedEntityAnnotation(entityPER, start11, end16, score0.99641764), NamedEntityAnnotation(entityLOC, start31, end39, score0.996198), ...]})。2.22 用户指南的完整说明见 docs-website/versioned_docs/version-2.22/pipeline-components/extractors/namedentityextractor.mdx。4.3 版本迁移提示组件已迁出主仓库需要特别说明的是当前主仓库的haystack/components/extractors/目录下已不再包含named_entity_extractor.py。根据发布说明 releasenotes/notes/remove-named-entity-extractor-a8d65992a201a775.yamlNamedEntityExtractor连同NamedEntityAnnotation、NamedEntityExtractorBackend已从 Haystack 主仓库移除拆分进按后端划分的独立集成包Hugging Face 后端安装transformers-haystack改用from haystack_integrations.components.extractors.transformers import TransformersNamedEntityExtractor并以TransformersNamedEntityExtractor(modeldslim/bert-base-NER)初始化spaCy 后端安装spacy-haystack改用from haystack_integrations.components.extractors.spacy import SpacyNamedEntityExtractor并以SpacyNamedEntityExtractor(modelen_core_web_trf)初始化。因此本文所述 API 以 2.22 参考文档为准若你使用更高版本请安装对应集成包并调整导入路径。五、RegexTextExtractor用正则从文本与 ChatMessage 中提取片段RegexTextExtractor是一个零依赖、确定性的轻量提取器用正则表达式解析输入文本或ChatMessage列表返回第一个捕获组命中的文本。它非常适合放在 Chat Generator 之后用于从 LLM 输出中解析带标签如 XML 风格标签、JSON 代码块的结构化片段。5.1 初始化与运行契约def __init__(regex_pattern: str)regex_pattern应包含捕获组圆括号以指定提取目标。例如issue url(.)从issue urlgithub.com/hahahaha中捕获github.com/hahahaha。若模式不含任何捕获组源码在初始化时会打印警告运行时不返回捕获组而是返回整个匹配串见 regex_text_extractor.py#L52-L59 与 regex_text_extractor.py#L129-L146。component.output_types(captured_textstr) def run(text_or_messages: str | list[ChatMessage]) - dict[str, str]输入为字符串时直接在其中搜索输入为ChatMessage列表时只处理最后一条消息如果最后一条不是ChatMessage实例则抛出TypeError列表为空或最后一条消息无文本时返回{captured_text: }并记录警告见 regex_text_extractor.py#L114-L127返回值为{captured_text: matched text}命中或{captured_text: }未命中。5.2 使用示例参考文档给出的两种输入形态from haystack.components.extractors import RegexTextExtractor from haystack.dataclasses import ChatMessage # Using with a string parser RegexTextExtractor(regex_patternissue url(.)) result parser.run(text_or_messagesissue urlgithub.com/hahahahahahahah/issue) # result: {captured_text: github.com/hahahaha} # Using with ChatMessages messages [ChatMessage.from_user(issue urlgithub.com/hahahahahahahah/issue)] result parser.run(text_or_messagesmessages) # result: {captured_text: github.com/hahahaha}与 LLM 输出配合时可以提取json代码块中的 JSONextractor RegexTextExtractor(regex_patternrjson\s*(.*?)\s*) messages [ ChatMessage.from_user(Extract the data), ChatMessage.from_assistant(Here is the data:\njson\n{name: Alice, age: 30}\n), ] result extractor.run(text_or_messagesmessages) # result: {captured_text: {name: Alice, age: 30}}5.3 在 Pipeline 中解析 LLM 结构化输出一个典型场景是让 LLM 输出同时包含analysis与summary标签的回复再用RegexTextExtractor只摘出summary部分from haystack import Pipeline from haystack.components.builders import ChatPromptBuilder from haystack.components.generators.chat import OpenAIChatGenerator from haystack.components.extractors import RegexTextExtractor from haystack.dataclasses import ChatMessage pipe Pipeline() pipe.add_component(prompt_builder, ChatPromptBuilder()) pipe.add_component(llm, OpenAIChatGenerator()) pipe.add_component( extractor, RegexTextExtractor(regex_patternrsummary(.*?)/summary), ) pipe.connect(prompt_builder.prompt, llm.messages) pipe.connect(llm.replies, extractor.text_or_messages) messages [ ChatMessage.from_system( Respond using this exact format:\n analysisYour detailed analysis here/analysis\n summaryA one-sentence summary/summary, ), ChatMessage.from_user(What are the main benefits and drawbacks of remote work?), ] result pipe.run({prompt_builder: {template: messages}}) print(result[extractor][captured_text])注意pipe.connect(llm.replies, extractor.text_or_messages)把 LLM 的回复列表直接接到提取器输入提取器会自动只取最后一条消息。5.4 版本差异与序列化兼容2.22 用户指南曾描述过一个已废弃的return_empty_on_no_match参数旧行为无匹配时返回空字典{}。在参考 API 文档与当前源码中该参数已被移除无匹配时统一返回{captured_text: }。为保证旧 Pipeline 反序列化不中断from_dict会识别并忽略残留的return_empty_on_no_match参数并打印警告见 regex_text_extractor.py#L70-L85。序列化方面to_dict/from_dict只保存regex_pattern一个初始化参数。该组件的字符串、消息列表、空列表、无捕获组等分支均有测试覆盖见 test/components/extractors/test_regex_text_extractor.py。六、小结与选型建议场景推荐组件扫描件、图片、PDF 页面转可检索文本LLMDocumentContentExtractor视觉 LLM为文档生成实体/主题/摘要等结构化元数据LLMMetadataExtractor提示词驱动 LLM支持按页抽取在本地用确定性模型识别命名实体NamedEntityExtractor2.22或TransformersNamedEntityExtractor/SpacyNamedEntityExtractor新版本集成包从 LLM 输出中确定性解析带标签片段RegexTextExtractor零依赖、无网络调用四个组件都遵循 Haystack 的组件规范以component装饰、声明output_types、实现to_dict/from_dict可序列化、warm_up预热、run运行并LLM 系组件提供run_async异步入口。LLM 系组件普遍采用成功文档 失败文档双输出设计配合raise_on_failure与失败元数据键extraction_error/metadata_extraction_error、metadata_extraction_response可以在生产索引链路中做到失败不阻断、事后可重跑。更多组合用法可参考 2.22 用户指南的 extractors.mdx 及各组件独立页面llmdocumentcontentextractor.mdx、llmmetadataextractor.mdx、namedentityextractor.mdx、regextextextractor.mdx。【免费下载链接】haystackOpen-source AI orchestration framework for building context-engineered, production-ready LLM applications. Design modular pipelines and agent workflows with explicit control over retrieval, routing, memory, and generation. Built for scalable agents, RAG, multimodal applications, semantic search, and conversational systems.项目地址: https://gitcode.com/GitHub_Trending/ha/haystack创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。