Dify Agent Prompt Layer 详解:如何为一次 Agent Run 组装系统提示词与用户输入
2026/9/5 18:50:48 网站建设 项目流程

Dify Agent Prompt Layer 详解:如何为一次 Agent Run 组装系统提示词与用户输入

【免费下载链接】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 采用“层(Layer)”架构组织每次运行(run)的能力单元,其中 Prompt Layer(type id 为plain.prompt)负责为当前 run 提供系统提示词片段(prefix/suffix)与用户输入片段(user)。本文以 Prompt Layer 用户手册 为核心,结合 PromptLayer 源码实现、运行器校验逻辑 和 compositor 聚合逻辑,讲清楚它的配置字段、组装时序、空 prompt 拒绝规则以及它与 history layer 的协作边界,帮助你在构建 create-run 请求时正确编排 prompt 片段。

Prompt Layer 的定位与适用场景

在 Dify Agent 的请求体中,Prompt Layer 是一个普通的RunLayerSpec,type id 为plain.prompt。它承载三类内容:

  • 本次 run 应发送的系统指令prefix,以及可选的suffix);
  • 当前用户输入user)。

这是 run API 提交用户输入的唯一入口——API 不接受顶层user_prompt字段。这一点可以从运行器代码得到印证:runner.py 在进入 run 后直接读取run.user_prompts(由所有层聚合而来),并以此作为 pydantic-ai 的 run 输入,请求体中并不存在独立的用户输入字段。

Prompt Layer 与其他层(如模型层、工具层)平级参与构图,源码注释说明了它的定位:它是构建在agenton.layers.types之上的小型具体实现,刻意保持与 compositor 图构建无关,以便在配置、示例和更高层的动态层中复用(见 basic.py)。

配置字段说明

PromptLayerConfig的完整字段定义在 basic.py:

字段类型含义
prefixstrlist[str]收集在其他 prompt 内容之前的系统提示词片段。
userstrlist[str]当前 run 的用户消息片段。
suffixstrlist[str]收集在 prefix 内容之后的系统提示词片段。

三个字段默认值均为空列表。另外需要注意两个源码层面的约束:

  • 配置类使用了model_config = ConfigDict(extra="forbid"),即请求中传入未知字段会被 Pydantic 校验直接拒绝,这是一个常见的报错来源;
  • 字符串与列表两种写法都合法。PromptLayer提供了prefix_prompts/suffix_prompts/user_prompts三个属性,将字符串归一化为单元素列表后再参与聚合(见 basic.py),因此调用方无论传str还是list[str],运行时的处理路径是一致的。

测试用例 test_basic.py 也验证了PLAIN_PROMPT_LAYER_TYPE_ID == "plain.prompt"以及PromptLayer.type_id与该常量一致,确认了 type id 的稳定性。

系统提示词的组装顺序

当图中存在多个会贡献 prompt 的层时,聚合顺序由 compositor 决定。从 run.py 的prompts属性 可以看到:

  1. 按 slot 顺序收集所有层的prefix片段;
  2. 倒序收集所有层的suffix片段;
  3. 每个片段经过所在层的wrap_prompt包装(允许层对片段做二次加工),最后统一交给prompt_transformer处理。

这意味着prefix位于系统提示词的前部,suffix位于尾部;倒序收集 suffix 的设计使得后声明的层的 suffix 更靠近 prefix 内容、先声明的层的 suffix 排在最末尾。如果你的 run 中只有 prompt layer 一个系统提示词来源,这套细节不会产生影响;只有在多层同时贡献系统片段(例如 Dify 内置的知识检索层也会贡献user_prompts,见 knowledge 层实现)时才需要关注顺序。

基本用法

手册给出的最小示例:用一个RunLayerSpec声明名为prompt的层,config 中分别传入一条系统指令和一条用户输入:

from agenton_collections.layers.plain import PLAIN_PROMPT_LAYER_TYPE_ID, PromptLayerConfig from dify_agent.protocol import RunLayerSpec prompt_layer = RunLayerSpec( name="prompt", type=PLAIN_PROMPT_LAYER_TYPE_ID, config=PromptLayerConfig( prefix="You are a concise assistant.", user="Summarize the incident in one paragraph.", ), )

这里name="prompt"约定俗成的名字而非保留字:运行时不对层名做保留,但官方示例(如 run_server_sync_client.py)与调度器测试(test_run_scheduler.py)都使用prompt作为该层的名称,建议保持一致以便他人阅读。type则必须是PLAIN_PROMPT_LAYER_TYPE_ID(即字符串"plain.prompt"),运行时按 type id 反查层工厂来实例化,写错 type 会导致构图失败。

多片段写法:列表形式的 prefix / user / suffix

当调用方希望把若干提示词片段保持独立(而仍然只发送一个 run)时,使用列表:

prompt_layer = RunLayerSpec( name="prompt", type=PLAIN_PROMPT_LAYER_TYPE_ID, config=PromptLayerConfig( prefix=[ "You are an incident response assistant.", "Prefer concrete mitigation steps.", ], user=[ "Database latency is elevated.", "Return the likely severity and next actions.", ], suffix="Do not invent metrics that are not provided.", ), )

列表写法在多片段场景下的实际收益体现在两处:

  • 系统侧prefix列表中的每个片段会按顺序拼接进系统提示词流,suffix同理放在尾部。像“角色设定 + 回答风格偏好”这类天然分段的指令,用列表比手动用换行拼接更清晰,也便于后续按来源增删片段。
  • 用户侧user列表中的多个片段最终会一起作为 run 输入。从 agent_factory.py 的normalize_user_input可以看到运行时的归一化规则:只有当聚合结果恰好是“单个字符串”时才作为str传入 pydantic-ai,否则整体以列表形式传入,从而保留多部分(multi-part)提示词的语义。

空用户输入的拒绝机制

手册指出:当有效用户 prompt 为空或仅含空白字符时,Dify Agent 会拒绝 create-run 请求。这条规则的实现在 user_prompt_validation.py:

EMPTY_USER_PROMPTS_ERROR = "run.user_prompts must not be empty" def has_non_blank_user_prompt(user_prompts: Sequence[UserContent]) -> bool: for prompt in user_prompts: if isinstance(prompt, str): if prompt.strip(): return True else: return True return False

关键细节有三点:

  1. 校验发生在 run 入口内部,即 compositor 构建完成、层实例化并经过 transformer 转换之后。源码注释明确说明这样做是为了“让运行时执行使用与实际 pydantic-ai 输入相同的转换后 prompt”,避免校验的是原始配置、执行的是转换后内容的偏差;
  2. 字符串片段按strip()判定""" "都不算有效输入;非字符串片段(富媒体/消息部件)直接视为有效内容,因为富内容没有统一的空白表示;
  3. 校验失败时,runner.py 抛出AgentRunValidationError("run.user_prompts must not be empty")。注意存在一个豁免条件:如果本次 run 携带的是延迟工具结果(deferred tool results),则跳过该校验——因为工具结果回传场景下用户 prompt 本来就可以为空。

Prompt 如何进入模型:run 级 instructions 与记忆隔离

理解了 prompt 的“入口”,还要知道它的“出口”。运行器在调用agent.run时做了明确的分工(见 runner.py):

  • 用户输入normalize_user_input(user_prompts)作为 run 的输入传入;
  • 系统提示词instructions=run.prompts or None,即聚合后的 prefix/suffix 系统片段,以pydantic-ai 的 run 级 instructions形式传入,而不是被硬编码进模型层的系统提示。

agent_factory的模块 docstring 也点明了这一设计:“The runner passes Dify system prompts as run-level instructions”。这种“系统提示按 run 注入”的方式带来一个重要的行为边界:

当前 run 的系统提示词是瞬态(transient)的,不会写入会话记忆。

这与手册 Notes 中最后一条对应:当 history layer 存在时,当前系统 prompt 以 run 级 instructions 传入,不会被保存到 memory。history.py 的 docstring 明确写道:“Current system instructions belong to each run and are never (persisted)”,其持久化实现replace(message, instructions=None)在落盘前会把消息上的瞬态 instructions 清除。因此:

  • 你想在每轮对话中稳定生效的规则,写进prefix/suffix即可,不用担心污染历史;
  • 但反过来说,历史轮次中曾用过的系统指令也不会自动出现在当前 run 的上下文中——每轮的 prefix/suffix 只来自当前请求的层配置。

实践建议与注意事项

  1. 用户输入一律走 prompt layer。不要假设存在user_prompt顶层字段;只填了prefix没填user的请求(且无延迟工具结果)会以run.user_prompts must not be empty失败。
  2. 层名用prompt,type 用plain.prompt。名字不保留但建议遵守约定;type id 是反查工厂的依据,必须精确。
  3. 多来源系统指令时注意 suffix 倒序聚合:多个层同时提供 suffix 时,先声明的层其 suffix 排在最后,可按此设计指令的优先级。
  4. 配合 history layer 使用时,系统指令按 run 生效、不落盘;跨轮上下文只通过history层持久化的消息历史传递。
  5. 配置字段是封闭的extra="forbid"意味着拼写错误(如sys_prompt)会直接触发校验失败,而不是被静默忽略。

参考实现与测试

内容路径
用户手册(本文主体)dify-agent/docs/dify-agent/user-manual/prompt-layer/index.md
PromptLayerConfig/PromptLayer实现dify-agent/src/agenton_collections/layers/plain/basic.py
空 prompt 校验dify-agent/src/dify_agent/runtime/user_prompt_validation.py
run 执行与校验触发点dify-agent/src/dify_agent/runtime/runner.py
系统/用户 prompt 聚合dify-agent/src/agenton/compositor/run.py
记忆持久化清除瞬态指令dify-agent/src/dify_agent/runtime/history.py
层 type id 单测dify-agent/tests/local/agenton_collections/layers/plain/test_basic.py
协议层 schema 测试dify-agent/tests/local/dify_agent/protocol/test_protocol_schemas.py
调度器中 prompt layer 用例dify-agent/tests/local/dify_agent/runtime/test_run_scheduler.py
客户端示例dify-agent/examples/dify_agent/dify_agent_examples/run_server_sync_client.py

综上,Prompt Layer 是 Dify Agent 中“提示词即配置”的核心载体:prefix/suffix系统片段按 compositor 的顺序规则聚合为 run 级 instructions,user片段构成经过空值校验的 run 输入,且系统指令与记忆持久化严格隔离。掌握这三条链路,就能在任何包含 Dify Agent 模型层、history 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

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询