开发日志13-【studyAgent】-操作数据库
一、扩展Agent tool
在上一篇博客中,我们成功把“研途 Buddy”从一个无状态的问答机器,重构成了拥有长期记忆、能隔离多窗口的有状态 Agent (Stateful Agent)。它不仅能和用户探讨 408 考研策略,还能调用内置引擎生成精美的复习思维导图,但这还不够。我决定为 Agent 赋予真正的“行动能力(Action)”——让它在征得用户同意后,自动推算日期,将庞大的学习计划精准拆解,并写入数据库的 TodoList 中。这使得它更像一个Agent了,能够进行工具编排调用,可对接外部工具数据库,拥有操作数据库的权限,自主判断什么时候用工具、用哪个工具、组装入参。
二、具体实现
- 挑战一:时间盲区与用户意图识别
存在问题:要让 Agent 写 TodoList,面临的第一个问题就是时间概念。大模型本身是没有“今天、明天、大后天”这种相对时间坐标的。如果用户说“大后天我要坐高铁,没法看书”,Agent 极有可能把任务排到 1970 年或者乱编一个日期。
同时,我们绝不能让 Agent 变成一个不受控制的“自动添加机”,它必须拥有明确的意图识别与授权机制。
解决方法:动态系统提示词
在每次组装发给大模型的 messages 时,我利用 Python 后端动态注入了当天的精确时间上下文,并定下了规则:
SYSTEM_PROMPT = f"""
【当前时间上下文】
今天是:{current_date},{day_of_week}。
【核心行为准则】
1. 意图识别与征询:制定完计划后,必须询问:“需要我将这份规划加入你的每日待办清单(TodoList)吗?”
2. 绝对服从授权:只有在用户明确同意后,才能调用 `add_tasks_to_todolist` 工具。
3. 智能日期推导:理解用户的日期偏移。遇到用户外出的日期必须跳过顺延,过去的日期绝对不能排期。
"""
这完美解决了 Agent 的时间感知问题。现在,它知道今天是周四,也就能准确算出“大后天”是周日,并在排期时优雅地跳过这一天。
2. 任务颗粒度
存在问题:定义好 Tool Call 工具后,我进行了第一次测试。结果 Agent 生成的任务竟然是这样的:
{"task_date": "2026-05-11", "content": "第一天:运输层核心概念与UDP(4小时)"}
这只是一个大纲,模型虽然根据上下文记忆窗口明白用户要添加的学习内容,但显然自己又进行了一遍总结归纳。
解决方法:我之前的思维导图生成工具,严格限制了输出结构:一级节点(天数) -> 二级节点(核心章节) -> 三级节点(具体知识点),我们需要让用户“所见即所得”,也就是用户得到的思维导图是什么样,加入todolist的任务就是什么样。
这里修改system_prompt:
SYSTEM_PROMPT = f"""你是'研途 Buddy'的专属复习规划师。
【当前时间上下文】
今天是:{current_date},{day_of_week}。
【核心行为准则】
1. 意图识别与征询:当你为用户制定完学习计划后,必须主动询问:“需要我将这份规划拆解并加入你的每日待办清单(TodoList)吗?”
2. 绝对服从授权:只有在用户明确表示“加入”、“好的”、“可以”等同意指令后,你才被允许调用 `add_tasks_to_todolist` 工具。绝不能未经允许擅自添加。
3. 智能日期推导:深刻理解用户的日期偏移要求。如果今天是 2026-05-10,用户说“明天开始”,则任务从 2026-05-11 开始排布。如果用户指出某天“要外出/有事”,你必须在排布任务时跳过那一天,将任务顺延。过去的日期绝对不能安排任务。
4. 任务映射法则(最高优先级)
当你准备把规划加入待办清单时,**绝对禁止**你自己概括或重写任务!
你必须严格按照你刚刚生成的思维导图结构进行提取:
- 将【一级节点】(如“第一天”)映射为真实的 `task_date`。
- 将对应的所有【三级节点】(具体知识点)的 title 原封不动地提取出来,作为清单的 `content`。
- 绝不能把一级节点(天数)或二级节点(章节大类)直接作为任务塞进去。”。
"""
并且同时修改工具描述:
"properties": {
"task_date": {
"type": "string",
"description": "根据【一级节点】(如'第一天')和用户要求的起始时间,推算出的精确执行日期 (YYYY-MM-DD),且不能早于今天"
},
"content": {
"type": "string",
"description": "必须严格、逐字提取思维导图中对应的【三级节点】的 title(例如 '5.3 用户数据报协议(UDP)报文段结构'),作为具体的任务内容。"
}
},
这使得大模型的推理逻辑瞬间变得极其清晰:
看日期: 第一天对应 2026-06-11。
查导图结构: 找到“第一天”分支下的所有叶子节点(三级节点)。
精准组装: 循环提取,生成完美的 Array JSON。
3. 代码改进
首先增加一个Agent Tool,并定义该tool的函数execute_add_tasks_to_todolist,这个函数会接收 Agent 解析好的任务数组,批量写入数据库,注意工具的描述设计,这是模型判断是否调用该工具的关键:
"description": "当且仅当用户明确同意时调用。用于将思维导图中的数据映射并写入数据库。"
然后在agent的循环体中增加判断是否调用add todolist工具的逻辑:
elif function_name == "execute_add_tasks_to_todolist":
tasks_list = function_args.get("tasks", [])
function_result = await crud_plan.execute_add_tasks_to_todolist(
tasks_data=tasks_list,
user_id=current_user_id,
db=db
)
- 效果展示
(1)user:“帮我生成一份学习计划,我想四天学完数据结构的二叉树部分,每天学一个小时”
模型思考过程:
模型回答:“我已经为您生成了一份四天掌握数据结构二叉树部分的学习计划,每天学习一小时。以下是详细的学习安排:…(具体学习规划)需要我将这份规划拆解并加入你的每日待办清单(TodoList)吗?”
(2)user:“加入todolist,从13号开始学习,不过14号我要外出,不能学习”
模型思考过程:

模型回答:“✅ 学习计划已成功添加到您的待办清单!…(具体任务规划) 已为您跳过6月14日的学习安排,总共添加了23个具体的学习任务。祝您学习顺利!🎯”
(3)此时再看todolist:
可以发现13、15、16、17四天被安排上了任务,查看具体任务清单:
Agent完美操作数据库!将具体的任务加入了todolist!
更多推荐

所有评论(0)