ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Dify Agent Ask Human Layer:让模型以结构化方式向人类发起输入请求的完整机制

Dify Agent Ask Human Layer:让模型以结构化方式向人类发起输入请求的完整机制 Dify Agent Ask Human Layer让模型以结构化方式向人类发起输入请求的完整机制【免费下载链接】difyBuild Agentic workflows, RAG pipelines, with rich AI model and tool support on one collaborative workspace. Deploy on cloud, VPC, or self-hosted, so teams move from prototype to production without rebuilding the stack.项目地址: https://gitcode.com/GitHub_Trending/di/dify本篇围绕 Dify Agent 的 ask-human layerdify.ask_human展开它向模型暴露一个 external deferred tool使 Agent 能在当前 run 无法继续时以结构化请求形式向人类要信息并将该请求作为deferred_tool_call随run_succeeded事件返回给客户端。读完本文你将掌握如何组装包含该 layer 的CreateRunRequest、理解每个配置字段的护栏语义、处理延迟工具调用deferred call并携人类结果恢复 run 的完整闭环以及各故障症状的排查方法。层契约它做什么、不做什么ask-human layer 的定位是“模型可见的工具层”而不是消息投递系统。层契约要点如下属性值Type iddify.ask_human常用 layer 名称ask_humanConfig DTODifyAskHumanLayerConfig模型可见工具默认ask_human可用tool_name配置工具类型pydantic-aiexternaldeferred tool终止事件run_succeeded终止载荷分支run_succeeded.data.deferred_tool_call关键在于“不暂停”的语义Agent run 不会进入 paused 状态。当模型调用 ask-human 工具时当前 run 以deferred_tool_call代替普通output成功结束把延迟调用转成面向人类的流程、收集结果、再发起带deferred_tool_results的新 run全部是客户端的职责。从源码 layer.py 的模块注释也能印证这一设计layer 只贡献“一个可选 external 工具 一段 prompt 提示”工具在首次 run 中绝不执行 Python下游系统自行决定投递、接收人、超时与授权。基础用法把 layer 加入 run composition将 ask-human layer 与 prompt、history、LLM 以及可选的结构化输出 layer 放在同一个 composition 中from agenton_collections.layers.plain import PromptLayerConfig from agenton_collections.layers.pydantic_ai import PYDANTIC_AI_HISTORY_LAYER_TYPE_ID from dify_agent.layers.ask_human import DIFY_ASK_HUMAN_LAYER_TYPE_ID, DifyAskHumanLayerConfig from dify_agent.layers.dify_plugin import DifyPluginLLMLayerConfig from dify_agent.layers.execution_context import ( DIFY_EXECUTION_CONTEXT_LAYER_TYPE_ID, DifyExecutionContextLayerConfig, ) from dify_agent.protocol import DIFY_AGENT_HISTORY_LAYER_ID, DIFY_AGENT_MODEL_LAYER_ID from dify_agent.protocol.schemas import CreateRunRequest, RunComposition, RunLayerSpec request CreateRunRequest( compositionRunComposition( layers[ RunLayerSpec( nameprompt, typeplain.prompt, configPromptLayerConfig( prefixYou can ask a human only when the missing decision is required to continue., userReview the deployment plan and proceed only after getting the required approval., ), ), RunLayerSpec( nameexecution_context, typeDIFY_EXECUTION_CONTEXT_LAYER_TYPE_ID, configDifyExecutionContextLayerConfig( tenant_idreplace-with-tenant-id, user_idreplace-with-user-id, user_fromaccount, app_idreplace-with-app-id, agent_modesingle_step, invoke_fromdebugger, ), ), RunLayerSpec( nameDIFY_AGENT_HISTORY_LAYER_ID, typePYDANTIC_AI_HISTORY_LAYER_TYPE_ID, ), RunLayerSpec( nameask_human, typeDIFY_ASK_HUMAN_LAYER_TYPE_ID, configDifyAskHumanLayerConfig( max_fields4, max_actions2, allowed_field_types[paragraph, select], allow_file_fieldsFalse, ), ), RunLayerSpec( nameDIFY_AGENT_MODEL_LAYER_ID, typedify.plugin.llm, deps{execution_context: execution_context}, configDifyPluginLLMLayerConfig( plugin_idlanggenius/openai, model_provideropenai, modelgpt-5.2, ), ), ] ) )组合中各 layer 的角色plain.prompt负责业务指令execution_context提供租户/用户/应用上下文PYDANTIC_AI_HISTORY_LAYER_TYPE_ID提供消息历史dify.plugin.llm是模型 layer通过deps消费 execution_context layer。history layer 是恢复语义的硬前提。只要预期在人类回答后继续对话就必须包含 history layer。悬而未决的工具调用被存放在 pydantic-ai 消息历史里因此恢复 run 需要两样东西上一次返回的session_snapshot以及保持 history layer 仍存在的同一逻辑 composition。runner 侧对此有明确校验——见 runner.pyif deferred_tool_results is not None and history_layer is None: raise AgentRunValidationError( Deferred tool results require a history layer with prior message history. )此外 composition 层面只允许存在一个 ask-human layervalidate_ask_human_layer_compositionlayer.py会拒绝同名 type 的多个 layer。配置字段与双层护栏DifyAskHumanLayerConfig只控制“面向模型的工具身份与护栏”刻意不包含任何投递配置。字段定义见 configs.py字段类型默认值含义enabledboolTrue为 false 时该 layer 既不暴露工具也不注入 prompt 引导tool_namestrask_human模型可见的工具名必须是合法标识符tool_descriptionstr \| None默认描述文本可选的模型可见工具描述max_fieldsint8模型可请求的字段数上限0表示仅允许动作型请求max_actionsint4模型可请求的人类动作数上限allowed_field_typeslist[paragraph \| select \| file \| file-list][paragraph, select]运行时校验接受的字段类型allow_file_fieldsboolFalse未开启时文件字段类型直接拒绝开启后还须列入allowed_field_typesmax_markdown_charsint8000可选markdown正文的最大长度max_question_charsint1000必填question的最大长度max_field_label_charsint120每个字段 label 的最大长度max_action_label_charsint80每个动作 label 的最大长度配置上限之上还有服务端硬上限两者取较小值生效若配置超过硬上限请求校验阶段即失败、run 无法执行。硬上限常量定义在 configs.py字段硬上限max_fields16max_actions8max_markdown_chars20000max_question_chars4000max_field_label_chars200max_action_label_chars120实现上有两处值得注意tool_name必须是合法标识符。字段校验器用正则^[A-Za-z_][A-Za-z0-9_]*$全匹配校验configs.py非法命名会在配置校验时直接报错。文件字段的“双开关”策略。_validate_file_field_policy模型校验器要求只有当allow_file_fieldsTrue且allowed_field_types中包含file/file-list时文件字段才合法allow_file_fieldsFalse却在允许列表里写了文件类型配置本身就会被拒绝configs.py。文件字段变体目前属于“为前向兼容预留的词汇表”默认不开放。layer 会把这些上限自动转写成 prompt 提示。build_prompt_hintlayer.py生成的文本包含允许的字段类型、文件上传是否启用、字段/动作数上限、question/markdown与 label 长度限制并告知模型“若省略 actions系统会自动补一个 primary 样式的 Submit 动作”。客户端因此无需在系统提示里重复罗列限制但可追加业务侧指导例如何时才适合问人。模型能请求什么AskHumanToolArgs 契约启用后layer 暴露一个 external deferred tool其参数形状为AskHumanToolArgsschema.py字段类型含义titlestr \| None面向人类请求的可选短标题questionstr必填的问题/指令不能为空白markdownstr \| None可选的较长 Markdown 正文应按不可信的用户可见内容对待fieldslist[AskHumanField]供人类填写的可选结构化字段name 全局唯一actionslist[AskHumanAction]可选的动作按钮若省略Dify Agent 归一化为单个 primarySubmit动作urgencynormal \| high给下游系统的提示不是投递策略支持的字段变体判别字段为typeparagraph自由文本输入支持placeholder、defaultselect单选输入选项value必须非空且唯一default必须命中某个选项值schema.pyfile单文件输入仅在允许文件字段时可用file-list多文件输入仅在允许文件字段时可用可配max_filesschema.py。所有字段和动作都执行extraforbid即不允许携带未知属性字段name与动作id必须满足标识符规则。工具参数在模型调用后还会被再校验一次。校验入口_validate_tool_argslayer.py捕获ValidationError/ValueError并转成ModelRetry——也就是说模型一次越界的调用不会直接终结 run而是触发模型带着错误信息重试直到产出合法请求后才可能发出终止成功事件。归一化函数_validate_and_normalize_tool_args具体执行的护栏包括字段数不超过max_fields动作为空时补默认Submit动作数不超过max_actionsquestion/markdown/各 label 的长度上限字段类型必须在allowed_field_types内未开allow_file_fields时拒绝文件字段layer.py。另一个值得理解的细节工具函数本体_never_executed_tool只会抛出RuntimeErrorlayer.py因为该工具通过_prepare_tool_definition被改写成kindexternal的 deferred 工具layer.py参数 schema 直接取自AskHumanToolArgs.model_json_schema()。它的设计意图就是“永远不该在首次 run 中执行”真正的返回值来自人类经后续 run 注入。处理延迟的人类请求像处理普通事件一样流式或轮询 run 事件。成功的最终回答带event.data.output成功的人类请求带event.data.deferred_tool_call两者恰好只有一个分支被置值runner 中以result_kind区分见 runner.pydeferred_call None snapshot None async for event in client.stream_events(run_id): if event.type ! run_succeeded: continue snapshot event.data.session_snapshot if event.data.deferred_tool_call is not None: deferred_call event.data.deferred_tool_call else: final_output event.data.output break if deferred_call is not None: # 渲染你自己的面向人类的表单、入队通知、暂停外层工作流 # 或把请求存起来稍后处理。Dify Agent 不负责这部分。 print(deferred_call.tool_call_id, deferred_call.args)典型的延迟载荷长这样{ tool_call_id: call_01H..., tool_name: ask_human, args: { title: Deployment approval, question: Can we deploy version 2026.06.10 to production now?, fields: [ { type: paragraph, name: comment, label: Approval comment, required: false } ], actions: [ {id: approve, label: Approve, style: primary}, {id: reject, label: Reject, style: destructive} ], urgency: normal }, metadata: { layer_type: dify.ask_human, tool_name: ask_human, schema_version: 1 } }metadata的构造对应build_deferred_tool_call_payloadlayer.py其中schema_version当前为 1该方法还强制三条约束不支持 approval 请求、每次 run 恰好一个 deferred call当前版本为 MVP 限制、工具名必须与配置的tool_name一致——这三条正是后续排障表中故障症状的直接来源。安全提醒args是模型生成的内容。渲染给最终用户之前必须做校验与净化尤其markdown字段按不可信的用户可见内容对待。用人类结果恢复 run客户端收集到人类答案后用三要素创建新 run上一次的session_snapshot仍然包含 history layer 与 ask-human layer 的匹配 composition同名同序deferred_tool_results.calls[tool_call_id]中放入人类结果from dify_agent.layers.ask_human import AskHumanToolResult from dify_agent.protocol import DeferredToolResultsPayload human_result AskHumanToolResult( statussubmitted, action{id: approve, label: Approve}, values{comment: Approved for the planned window.}, messageThe human approved the deployment., ) resume_request CreateRunRequest( compositioncomposition_with_same_layer_names_and_order, session_snapshotsnapshot, deferred_tool_resultsDeferredToolResultsPayload( calls{deferred_call.tool_call_id: human_result.model_dump(modejson)}, ), )恢复结果的形状由AskHumanToolResult定义schema.pystatus取值为submitted/timeout/cancelled/unavailable之一除status外还有可选的action含合法标识符id与非空label、values字段名到值、message与rendered_content。Dify Agent 会把提供的结果作为原 external 工具调用的返回值交回 pydantic-ai模型随后继续运行。恢复的 run 可能产出最终output也可能再次产出deferred_tool_call——即 Agent 还需要又一轮人类交互。runner 在恢复 run 中会跳过新的 user 输入注入直接以deferred_tool_results驱动模型runner.py。超时与“人类不可用”也应作为工具结果回传而不是当作 Agent run 失败处理{ status: timeout, action: {id: __timeout, label: Timeout}, values: {}, message: The human did not respond before the workflow timeout. }客户端职责边界ask-human layer 刻意把产品决策留给调用方。客户端必须自行决定如何持久化延迟调用并与面向人类的任务做关联如何渲染并净化请求中的字段/动作如何选择接收人、渠道与超时策略授权谁可以作答如何把人类提交转换为AskHumanToolResult如何携返回的session_snapshot与匹配 composition 恢复 run。反过来有一条安全红线不要把收件人邮箱、workspace 成员 id、公开 URL、鉴权 token、超时策略放进工具参数。面向模型的请求是不可信内容不应让它反过来控制投递或授权——这正是DifyAskHumanLayerConfig文档字符串强调“Delivery, recipient selection, timeout policy, and other operational behavior are intentionally out of scope”的动机configs.py。排障速查表症状检查项run 报Deferred tool results require a history layer补上historylayer并携带上一次 snapshot 恢复对应 runner.py 的校验run 报pending tool call can be resumed在首次产生 deferred 调用的 run 中保持 history layer 处于激活状态runner.pyrun 报exactly one deferred call当前版本每次 run 仅支持一个 ask-human 调用应提示模型一次只问一个问题layer.pyrun 报tool name must be ...使用配置的tool_name不要只在下游表单代码里改名layer.py文件字段被拒绝设置allow_file_fieldsTrue并在allowed_field_types中包含file或file-listconfigs.pyrun_succeeded.data.output缺失检查run_succeeded.data.deferred_tool_call——这是“人类请求成功”不是 run 失败小结ask-human layer 把“Agent 何时该停下来问人”这件事收敛成一个模型可见的 external deferred tool配置层用DifyAskHumanLayerConfig声明护栏服务端硬上限兜底运行时层把工具改写为kindexternal、以 prompt 提示 双重校验ModelRetry 归一化保证请求合法终止事件用deferred_tool_call与output互斥地表达 run 结果。客户端则承担投递、授权、渲染与恢复的全部产品职责用session_snapshot 相同 composition deferred_tool_results完成闭环。相关实现集中在 dify-agent/src/dify_agent/layers/ask_human/ 包configs.py/schema.py/layer.pyrunner 侧的分支与校验在 dify-agent/src/dify_agent/runtime/runner.py配套文档为 dify-agent/docs/dify-agent/user-manual/ask-human-layer/index.md。【免费下载链接】difyBuild Agentic workflows, RAG pipelines, with rich AI model and tool support on one collaborative workspace. Deploy on cloud, VPC, or self-hosted, so teams move from prototype to production without rebuilding the stack.项目地址: https://gitcode.com/GitHub_Trending/di/dify创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表