用户在同一次对话中多次调用同一个 Skill,Skill 内部如何维护会话级别的状态?

面试官:“用户在同一次对话里可能多次调用同一个 Skill,比如反复查询不同城市的天气。Skill 内部怎么维护这种会话级别的状态?”

候选人:

“会话状态维护的核心矛盾是:Skill 天生是无状态的函数,但用户期望它有记忆。 解决方法不是在 Skill 里写死状态逻辑,而是让 Agent 框架在每次调用 Skill 时,把一个会话作用域的状态对象透明地注入给它。这样 Skill 就能在多次调用之间记住上次聊到哪了、用户偏好是什么。

我分三种场景,从简单到复杂来说。


场景一:基于 SessionContext 的显式状态存取

这是最通用、解耦最好的方式。Agent 框架为每个对话会话维护一个 SessionContext 对象,它和任务级的 TaskContext 不同——TaskContext 在一次任务完成后就销毁了,而 SessionContext 的生命周期跟整个对话会话绑定,可能跨越多次任务、多轮交互。

Skill 在元信息里声明自己需要读写的会话键:

{
  "session_state": {
    "reads": ["weather.last_city", "weather.units"],
    "writes": ["weather.last_city", "weather.last_query_time"]
  }
}

每次 Skill 被调用时,编排引擎自动从 SessionContext 中提取这些键注入给 Skill;Skill 执行完后,引擎把声明要写的键写回 SessionContext

举例:用户连续问“北京天气”“上海天气”“深圳天气”。第一次查北京后,Skill 把 weather.last_city = "北京" 写入会话状态。第三次问“深圳呢”时,Skill 没有收到城市名参数,但它可以从 weather.last_city 读取上下文推断——不过实际上城市名是用户给的,真正有用的是它记住了 weather.units = "celsius",这样用户说过一次“用摄氏度”后,后续查询都不用重复说。


场景二:Skill 内部的链式调用状态

有时候同一个 Skill 在一次任务里被调用多次,而且每次的调用是同一个流程的不同阶段。比如一个“填报销单” Skill,第一步让用户描述费用,第二步让用户上传发票,第三步确认提交。

这种情况下,状态更适合放在任务级的 TaskContext 里,而不是会话级。因为如果用户隔了一天又来报销,他不希望看到上次填了一半的老报销单。TaskContext 跟这次报销任务绑定,任务结束就清理。

Skill 内部通过一个 step 字段来判断当前处于哪个阶段:

// TaskContext 中报销 Skill 的状态
{
  "expense_report": {
    "step": "upload_invoice",
    "completed_steps": ["describe_expense"],
    "amount": 1280,
    "category": "差旅费"
  }
}

编排引擎调用 Skill 时,把这个状态注入。Skill 发现自己 step == "upload_invoice",就直接展示上传发票的引导,而不是重新从描述费用开始。


场景三:用户偏好与记忆

有些状态需要跨会话持久化,比如用户说“以后查天气默认用摄氏度”,这已经不是会话级别的状态了,而是用户级别的长期偏好。

这种状态下沉到用户画像服务或长期记忆存储(如数据库或向量库)。Skill 在元信息里声明自己需要读取 user_profile.preferred_temperature_unit。编排引擎调用 Skill 前,不仅注入会话上下文,还从用户画像服务获取长期偏好注入。

三者的生命周期对比:

查看内嵌表格