LangChain @dynamic_prompt 用于任务感知型系统指令
一个 LangChain HR 智能体通过运行时上下文中的 @dynamic_prompt 中间件来替换休假、福利及行政系统相关的提示词,而授权逻辑则保留在代码中。
LangChain 的 @dynamic_prompt 装饰器会根据运行时上下文来构建系统提示词,而非使用嵌入在智能体定义中的固定字符串。
每当指令需要根据当前任务、角色、租户、工作流阶段或应用程序设置而变化时,都可以使用该装饰器——无需为每种情况创建单独的智能体。
举个具体例子:一名人力资源助理负责处理休假与考勤、员工福利以及人力资源管理事务。同一个智能体实例会根据用户选择的业务类别切换其系统指令。模型看到的仍为同一场对话,只有不可见的系统前置内容会发生变化。
运行时上下文与授权机制
运行时上下文是应用程序为本次调用提供的数据——任务键、区域设置、套餐层级、功能开关等。@dynamic_prompt会读取这些数据并返回即将进行的模型调用所需的系统提示语。
它并非一种访问控制机制。权限检查应在应用层或相关工具中实现。该装饰器仅用于设定要告诉模型执行的任务内容。将两者混为一谈是个常见错误:仅仅在提示语中写“你是管理员”并不能赋予管理员级别的API权限。
其能发挥作用的实际场景
- 在共享智能体上为不同任务提供定制化的指令集
- 根据角色调整提示语的语气、深度或示例内容
- 面向多租户的SaaS系统,为不同客户提供不同的策略文本
- 在工作流的不同阶段根据需求设置不同的约束规则
- 通过功能开关在不重新部署智能体的情况下改变模型行为
逐步讲解:具有三项任务的HR助手
界面中显示的任务包括:
- 请假与考勤
- 员工福利
- HR管理
角色:员工或管理员。请假和福利功能两者均可使用;HR管理功能仅限管理员操作。这种角色划分决定了控制点应设置在哪里。
1. 定义上下文对象
UserContext包含应用程序在代理运行时填充的字段。task决定@dynamic_prompt应返回哪个指令块。role会在调用代理执行管理任务之前由应用程序进行验证。将角色信息排除在提示词生成器之外有助于简化安全审计工作。
2. 动态构建提示词
@dynamic_prompt
def hr_dynamic_prompt(request):
user = request.runtime.context
if user.task == "leave":
return """
You are an HR assistant responsible for Leave and Attendance.
Help the user with questions about:
- Leave types
- Leave balances
- Leave application
- Leave carry-forward
- Attendance
Answer only within the Leave and Attendance area.
Keep the response clear and concise.
"""
elif user.task == "benefits":
return """
You are an HR assistant responsible for Employee Benefits.
Help the user with questions about:
- Health insurance
- Employee benefits
- Wellness programs
- Company benefit programs
Answer only within the Employee Benefits area.
Keep the response clear and concise.
"""
elif user.task == "admin":
return """
You are an HR Administration assistant.
Help the user with administrative HR processes such as:
- Employee onboarding
- Employee offboarding
- HR documentation
- Employee records
- Administrative procedures
Answer only within the HR Administration area.
Keep the response clear and concise.
"""
return """
You are a general HR assistant.
Answer the user's question clearly and concisely.
"""
该装饰器将函数标记为中间件。LangChain会传递模型请求,你需要获取request.runtime.context。当task为"leave"时,返回离职相关指引;当为"benefits"时,返回福利相关信息;当为"admin"时,返回管理相关指导。一个智能体图谱,多种系统提示语,无需重复配置工具连接。
3. 仅一次连接模型与智能体
同一个聊天模型和智能体可处理所有任务。将hr_dynamic_prompt注册为中间件,这样LangChain会在模型处理步骤之前调用它。工具、内存和回调函数保持共享,仅前置内容会发生变化。
4. 将用户界面选项映射到任务键
一个简单的菜单可将面向用户的标签映射为固定键:
1 → 离职 2 → 福利 3 → 管理
这些键会成为上下文对象中的task字段。稳定的键非常重要:无需重写提示函数即可更改用户界面文本。
5. 在装饰器之外进行授权
管理员权限控制会在agent.invoke执行之前发生。如果员工选择了“人力资源管理”,应立即以明确的错误信息终止流程。动态提示仅用于修改指令,无法决定权限归属。应将拒绝处理逻辑放在已有日志和指标记录的应用代码中。
6. 将上下文传递给调用函数
context=UserContext(
user_name="Nachiket",
role="admin",
task="leave"
)
在模型处理阶段,@dynamic_prompt会检测到task="leave",并返回相应的休假系统提示。用户的问题仍会以普通消息的形式发送。上下文与聊天历史记录得以清晰分离。
7. 显示答案
print("\nAssistant:")
print(result["messages"][-1].content)
代理的最终消息内容就是您输出到控制台或在用户界面中显示的内容。在此基础上,您可以添加流式数据、引用信息或工具调用轨迹,而无需修改动态提示中间件。
为何这种模式具有扩展性
您无需为每个产品界面单独创建代理实例。指令始终与中间件函数位于同一位置,因此产品内容编写者可以在一处编辑文案。角色和权限也保存在应用程序代码中,便于进行安全审查。模型始终会收到针对当前场景定制的提示——无需硬编码三个独立的代理或三种不同的部署方式。