






















LangChain的DeepAgents已经发布有段时间了,最近的几个版本基本覆盖了大多数智能体都应该有的功能。本笔记基于 LangChain 的 DeepAgents 框架,演示如何构建了一个具有角色扮演能力的 AI 助手,并集成了自定义技能系统。以此方便后续的knowledge review以及vibe coding的reference。
from dotenv import load_dotenv
import os
# 加载 .env 文件中的环境变量
load_dotenv()
# 设置环境变量供 deepagents 使用(OpenAI 兼容格式)
os.environ["OPENAI_API_KEY"] = os.getenv("DEEPSEEK_API_KEY", "")
os.environ["OPENAI_API_BASE"] = os.getenv("DEEPSEEK_API_BASE", "https://api.deepseek.com/v1")
这里我们使用在线版本的deepseek。
尝试过使用本地的小模型,需要留意的是,deepseek的小参数量模型,不支持工具的调用。即使换到qwen的小模型,对工具的调用也总会出莫名其妙的问题。所以为方便学习和测试,建议走在线的模型。
为了演示方便,这里创建两个方法作为DeepAgent的工具。
from datetime import datetime
def get_time():
"""Get current time"""
return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
def get_location():
"""Get location"""
return "北京"
为方便演示,位置查询的output直接写死。
注:方法要有注释,标注这个方法是干什么的,方便智能体的了解,不然会报错。
from langgraph.checkpoint.memory import InMemorySaver
checkpointer1 = InMemorySaver()
由于大模型的对话都是无状态的,比如你第一次对话问:来一首唐诗,第二次对话追问:再来一首,那么大模型会不知道到底再来一首啥。LangChain封装了这么一套方法来维护对话的状态。
代码讲解:
InMemorySaver 是 LangGraph 提供的内存检查点存储thread_id 区分不同的对话线程from langchain.agents.middleware import SummarizationMiddleware
middleware=[
SummarizationMiddleware(
model="deepseek:deepseek-chat",
trigger=("tokens",1000),
keep=("messages",3)
)
]
LangChain通过中间件的方式,来处理模型对话历史过长的问题,处理的方法有很多,比如消息裁剪等。这里演示的是更常用的,将历史对话进行大模型语义汇总的方式,基本的方法就是将指定久远之外的消息汇总成一个简短的摘要。
代码讲解:
SummarizationMiddleware:摘要中间件,用于优化长对话的上下文管理model:用于生成摘要的模型trigger=("tokens",1000):当上下文达到 1000 tokens 时触发摘要keep=("messages",3):保留3 条消息如果keep的messages设置为3,那么最近的两条message会被完整保留,第三条是根据以前的会话记录summaize下来的信息。
from deepagents.backends import LocalShellBackend
backend=LocalShellBackend(
root_dir=".",
virtual_mode=True
)
这个是用来确保,智能体能够读取到skills,并且能够运行里面的脚本。
代码讲解:
LocalShellBackend:本地 Shell 执行后端root_dir=".":工作目录根路径,设置为当前目录virtual_mode=True:启用虚拟模式,限制文件访问范围,提高安全性from deepagents import create_deep_agent
agent = create_deep_agent(
model="deepseek:deepseek-chat",
system_prompt="你是于谦,捧话之王,说话坏简介明了直奔主题。",
tools=[get_time, get_location],
checkpointer=checkpointer1,
middleware=[
SummarizationMiddleware(
model="deepseek:deepseek-chat",
trigger=("tokens",1000),
keep=("messages",3)
)
],
backend=LocalShellBackend(
root_dir=".",
virtual_mode=True
),
skills=["./skills"],
)
跟传统的create_agent比,创建deepagent的方法对应的是create_deep_agent。大多数的传入参数基本都是一样的。
参数详解:
| 参数 | 说明 |
|---|---|
model |
使用的模型名称,这里使用 DeepSeek 的 deepseek-chat 模型 |
system_prompt |
系统提示词,定义 Agent 的角色和行为风格 |
tools |
工具函数列表,Agent 可以调用这些函数 |
checkpointer |
记忆检查点,用于保存对话状态 |
middleware |
中间件列表,用于处理上下文摘要等任务 |
backend |
执行后端,用于运行本地命令 |
skills |
技能目录列表,加载自定义技能扩展 |
配合智能体的记忆功能使用的。
config = {"configurable":{"thread_id":"1"}}
这个config是需要放在后续的invoke里的。(其实这里没太想明白,为什么不放在构造deepagent的构造函数里。)
代码讲解:
thread_id:对话线程标识符thread_id 可以延续之前的对话thread_id 会开启新的对话线程index=1
while(True):
print(f"### 第{index}轮对话 ###")
query = input("请输入:")
if query == "exit":
print("退出")
break
results=agent.invoke(
{"messages": [{"role": "user", "content": query}]},
config=config
)
for message in results["messages"]:
message.pretty_print()
index+=1
这里我们演示一个HR的请假系统,相应的代码我们只定义了接口,为了演示方便不做具体的实现以及系统的对接,只返回固定的output。
通常我们建议单独的一个skills目录保存所有skills,然后通过每个子目录来保存不同的skill。
skills/
└── HR/
└── SKILL.md
文件路径:skills/HR/SKILL.md
---
name: HR assistant
description: HR 助手
---
这两个配置是每个skill必须都要包含的,包括:
name:技能的唯一标识符description:技能的简短描述本技能是 HR 系统的 AI 助手,根据系统接口文档和用户的问题,直接调用相应的接口完成操作。当用户说"小赵"时触发。
根据这段声明,我们定义了触发机制为:
这部分包含skill里都有什么功能:
### 1. 请假
- **功能**:创建新的请假申请
- **需要确认的信息**:
- 姓名
- 请假开始时间
- 请假结束时间
- 请假类型(病假,事假,年假,婚假,丧假,产假,其他)
- **操作流程**:
1. 检查用户提供的信息是否完整
2. 如果有任何信息不完整,依次向用户确认
3. 所有信息确认后,让用户再次确认所有信息
4. 调用 `create_leave_application` 函数创建请假申请
根据这段描述我们可以看到,这里我们要求skill:
信息收集:
信息确认:
执行操作:
---
name: HR assistant
description: HR 助手
---
# HR 助手
## 功能说明
本技能是HR系统的AI助手,根据系统接口文档和用户的问题,直接调用相应的接口完成操作。当用户说"小赵"时触发。
## 支持的功能
### 1. 请假
- **功能**:创建新的请假申请
- **需要确认的信息**:
- 姓名
- 请假开始时间
- 请假结束时间
- 请假类型(病假,事假,年假,婚假,丧假,产假,其他)
- **操作流程**:
1. 检查用户提供的信息是否完整
2. 如果有任何信息不完整,依次向用户确认
3. 所有信息确认后,让用户再次确认所有信息
4. 调用 `create_leave_application` 函数创建请假申请
### 请假代码的具体实现
```python
def create_leave_application(name, start_time, end_time, leave_type):
"""
创建新的请假申请
参数:
- name: 姓名
- start_time: 请假开始时间(格式:YYYY-MM-DD HH:MM)
- end_time: 请假结束时间(格式:YYYY-MM-DD HH:MM)
- leave_type: 请假类型(病假,事假,年假,婚假,丧假,产假,其他)
返回:
- 申请结果字典
"""
#实现方法略
return {
"success": True,
"message": "请假申请已创建",
"data": {
"name": name,
"start_time": start_time,
"end_time": end_time,
"leave_type": leave_type,
"status": "pending"
}
}
```
用户对话流程:
以下是一段测试对话。
我比较喜欢的一个点是,通过skill,以及智能体的加持,对于参数的输入就灵活了很多,在体验上更人性化。比如接口对日期格式的要求是yyyy-MM-dd,跟智能体对话的时候你只要说明天或者后天,那么智能体会根据接口的定义自动转换成符合要求的日期格式。
用户:小赵,我想休一天的假
Agent:好的,我是 HR 助手小赵。请问您的姓名是?
用户:我是哈士奇
Agent:好的,哈士奇。请问您想请哪一天的假?
用户:后天
Agent:好的,后天(2026-05-21)。请问您想请什么类型的假?
可选类型:病假、事假、年假、婚假、丧假、产假、其他
用户:年假
Agent:请确认以下请假信息:
- 姓名:哈士奇
- 请假类型:年假
- 开始时间:2026-05-21 09:00
- 结束时间:2026-05-21 18:00
以上信息是否正确?
用户:正确
Agent:✅ 请假申请已成功创建!
申请状态:pending(待审批)
关于上下文的汇总,由于需要比较多的智能体对话,所以测试结果不放在这里,感兴趣的朋友可以自己跑下代码,然后在输出部分看智能体是如何summarize历史对话记录的。
模块化设计:
记忆管理:
技能系统:
系统提示词设计:
工具函数编写:
技能开发:
AssertionError: Please remove duplicate middleware instances.另目前很多vibe coding生成langchain的deepagents代码都会有很多问题,主要是因为这个东西太新了,很多智能体即使有再牛的上下文系统也不知道该如何去生成正确的代码,所以需要自己去鉴别一下。
目前LangChain的DeepAgents已经支持了跟智能体相关的大多数方法,通过学习DeepAgents,我们也可以顺便理解目前市面上主流的智能体其背后是如何工作的。此文做阶段性的学习总结,方便后续的review以及供vibe coding参考。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。