← 返回文章列表

Dify 中级实验(01):参数提取器实战——如何从自然语言中提取结构化数据?

1. 业务场景

先讲一个我们实际遇到的场景。

一家做招聘服务的公司,每天要处理几十份简历。HR 收到的简历格式五花八门——有人写「5 年经验,精通 Python」,有人写「Python 五年,Java 熟练」,还有人的简历是纯叙述段落,技能、年限、薪资期望全混在一段话里。他们的流程是:人工把简历里的关键信息(姓名、年龄、技能、经验年限、期望薪资、学历)逐项录入到筛选系统,再由系统按岗位要求做初筛。

我们第一次接这类需求时,第一反应也是「是不是得上个 NLP 解析库」。后来翻 Dify 的节点列表才发现:平台原生的 Parameter Extractor(参数提取器) 就是干这个的——LLM 从自然语言里提取结构化字段,直接输出 JSON,连解析代码都不用写。

这不是个例。任何「用户说人话、系统要结构化数据」的业务场景都是这个模式:工单系统里用户用一句话描述故障,客服要手动拆出设备型号和故障现象;CRM 里销售把客户需求复制进来,运营要手动提取预算和期限;搜索系统里用户随口问「有没有便宜点的 4K 显示器」,后端需要的是结构化的「屏幕尺寸、分辨率、预算上限」。

2. 场景痛点

这个流程的痛点,在招聘公司的 HR 身上体现得最直接:

本质上,最没有技术含量、却最费人力的环节,恰恰是「把自然语言变成结构化数据」这一步。模型负责理解,规则负责确定性——而这一步的确定性,不该靠人工。

3. 方案:为什么是参数提取器

选参数提取器的理由,我们实际对比过:

这篇文章我们就用它搭一个「简历筛选助手」:用户用自然语言描述候选人,系统提取出 6 个结构化字段,再根据字段做筛选判断。

4. 整体架构

graph TD start["开始:resume_text"] --> pe["参数提取(Parameter Extractor,6 字段)"] pe --> check["校验提取结果(Code:完整性校验)"] check --> branch{"校验结果判断(IF-ELSE)"} branch -- "通过" --> llm["生成筛选意见(LLM)"] --> end1["结束"] branch -- "不通过" --> end2["结束(提示补充信息)"]

链路很清晰:入口收自然语言 → 提取结构化 → 校验完整性 → 分支处理。校验和分支是这个架构的关键——参数提取偶尔漏字段是 LLM 节点的常态,不校验直接往下走,筛选意见就会基于残缺数据生成。

5. 模块设计

5.1 开始节点

resume_text 变量类型必须选「段落」(paragraph)而不是「文本框」(text-input)——简历描述是长文本,text-input 有 48 字符输入限制,粘贴一段简历直接报错:

- label: 简历描述

  max_length: 10000

  required: true

  type: paragraph

  variable: resume_text

💡 这是同批实验里踩过的真实坑:长文本/JSON 粘贴类变量用 paragraph + 显式 max_length: 10000,否则 Service API 报 must be less than 48 characters

5.2 参数提取节点(核心)

配置 6 个提取参数:

query: ['start', 'resume_text']

parameters:

  - name: name                # 候选人姓名

    type: string

    required: true

  - name: age                 # 候选人年龄

    type: number

    required: false

  - name: skills              # 技能列表

    type: array[string]

    required: true

  - name: experience_years    # 工作经验(年)

    type: number

    required: true

  - name: expected_salary     # 期望薪资(元/月)

    type: number

    required: false

  - name: education           # 最高学历

    type: string

    required: false

要点:

5.3 校验节点(Code)

参数提取偶尔会漏字段,用代码节点做完整性校验,返回 valid 标志 + 缺失项提示:

def main(name: str, age: str, skills: list, experience_years: str, expected_salary: str, education: str) -> dict:

    missing = []

    if not name: missing.append("姓名")

    if not skills: missing.append("技能")

    if not experience_years: missing.append("工作经验")

    return {

        "valid": "false" if missing else "true",

        "missing_fields": "、".join(missing) if missing else "",

        "summary": f"{name}{experience_years}年经验,技能:{', '.join(skills or [])}"

    }

💡 boolean 必须展平为 string("true"/"false")——Dify 的 object/boolean 类型在节点间不可见,IF-ELSE 判断的是字符串。

6. 运行验证

输入上面的简历描述,预期:

  1. 参数提取返回 6 个结构化字段(skills 是数组)
  2. 校验节点 valid=true
  3. LLM 生成筛选意见(结合经验年限/技能与岗位匹配度)

实测结果:完整简历 → 提取 6 字段全中 → 筛选意见输出正常;缺技能描述的简历 → valid=false → 走提示分支。

7. 实战坑

现象 修复
start 变量用 text-input 长简历粘贴报「must be less than 48 characters」 改 paragraph + max_length: 10000
校验结果 boolean 直出 IF-ELSE 判断不到(类型不可见) 展平为 string "true"/"false"
PE 提取字段描述含糊 LLM 提取错/漏字段 每个字段写清楚业务描述

8. 实验文档及源码获取

文章聚焦核心配置与采坑点;实验的完整分步操作(节点搭建/参数表/调试指引)见实验文档原文。

本系列 · Dify 实验 · 中级
  1. Dify 中级实验(01):参数提取器实战——如何从自然语言中提取结构化数据?
  2. Dify 中级实验(02):问题分类器——智能路由引擎如何四路分发?
  3. Dify 中级实验(03):模板转换实战——如何用零 Token 完成文本加工?
  4. Dify 中级实验(04):迭代进阶——如何批量处理数据并守住性能边界?
  5. Dify 中级实验(05):并行执行——如何让多路任务同时跑?
  6. Dify 中级实验(06):变量聚合——如何确定性合并多路分支结果?
  7. Dify 中级实验(07):子工作流——如何把公共逻辑做成可复用积木?
  8. Dify 中级实验(08):代码节点进阶——如何用标准库处理文件与数据?
  9. Dify 中级实验(09):HTTP 节点进阶——如何搞定认证、分页与错误重试?
  10. Dify 中级实验(10):知识库深度调优——如何科学评估检索质量?
  11. Dify 中级实验(11):高级 RAG 流水线——如何搭建多路检索与精排?
  12. Dify 中级实验(12):Agent 深度配置——如何让智能体自主调用工具?
  13. Dify 中级实验(13):多 Agent 协作——如何编排多个智能体分工干活?
  14. Dify 中级实验(14):对话变量与状态管理——如何让工作流记住多轮对话的状态?
  15. Dify 中级实验(15):条件分支高阶策略——多条件路由如何避免分支爆炸?
  16. Dify 中级实验(16):错误处理与降级——工作流如何有尊严地失败?
  17. Dify 中级实验(17):调试监控与性能优化——响应慢和 Token 超支如何定位?
  18. Dify 中级实验(18):插件开发入门——如何把工作流变成 Agent 可调用的工具?
  19. Dify 中级实验(19):综合实战——如何把 19 个实验串成一条生产级流水线?
  20. Dify 中级实验(20):综合实战——自动化报告生成流水线如何从数据到周报一步到位?

联系我

15088711270

手机端点击号码可直接拨打 · 桌面端可复制

微信二维码

扫码加微信 · 备注「门户」更快通过