多轮对话
多轮对话指模型能延续上一轮结论与约束继续推进:你不必在每句里重复「刚才建的 Flask 项目」,只要让多次 run() 落在同一条会话上即可。本篇沿用第 01 篇的环境:模型 qwen3.5-plus,CODY_MODEL_BASE_URL=https://coding.dashscope.aliyuncs.com/v1,客户端用 AsyncCodyClient(workdir="...") 不显式传模型,由环境变量统一生效。
若尚未配置,可在 shell 中执行:export CODY_MODEL=qwen3.5-plus、export CODY_MODEL_API_KEY=sk-xxx、export CODY_MODEL_BASE_URL=https://coding.dashscope.aliyuncs.com/v1。需要显式写在代码里时,可用 Builder:Cody().workdir(".").model("qwen3.5-plus").base_url("https://coding.dashscope.aliyuncs.com/v1").api_key("sk-xxx").build()。
最简多轮示例
下面是一段可直接运行的脚本:第一轮让 Agent 创建应用,后两轮在同一会话里追加功能。先跑通,再读后面的机制说明。
import asyncio from cody import AsyncCodyClient async def main(): async with AsyncCodyClient(workdir="/my/project") as client: # 第一轮:自动创建 session r1 = await client.run("创建一个 Flask 应用,文件名 app.py") sid = r1.session_id # 自动生成,必须保存 # 第二轮:传入 session_id 保持上下文 r2 = await client.run("给这个 Flask 应用添加 /health 端点", session_id=sid) # 第三轮:继续 r3 = await client.run("再添加 JWT 用户认证", session_id=sid) print(r3.output) asyncio.run(main())
为什么要传 session_id?
从 v1.7.1 起,首次 run() 会自动创建会话并把 id 放在 result.session_id。后续轮次若传入同一个 session_id,Runner 会从库里取出该会话的完整消息历史,再与本轮用户消息一起发给模型,因此模型知道「Flask 应用」「app.py」等前文。若不传 session_id,每次调用相当于新开一条对话,上下文断裂,后两轮可能当成无关任务处理。
session_id 的本质
- 第一次
run()不传session_id时自动建会话,返回值里带有session_id。 - 会话与消息持久化在本地 SQLite,默认路径为
~/.cody/sessions.db(与全局配置一致)。 - 每次带某
session_id调用run()时,该会话已存储的用户/助手消息会作为上下文注入,再追加本轮输入。
手动管理会话
自动化脚本里靠返回值里的 id 就够;若要做控制台、IDE 插件或「会话列表」,可用下列 API:创建带标题的会话、列出历史、拉取详情(含消息)、删除,以及按工作目录取最近会话(v1.7.4+)。
# 创建自定义标题的会话(可选 model / workdir 覆盖) session = await client.create_session( title="重构 auth 模块", model="qwen3.5-plus", # 可选 workdir="/path/to/project", # 可选 ) r = await client.run("分析 auth.py 的问题", session_id=session.id) # 列出历史会话 sessions = await client.list_sessions(limit=10) for s in sessions: print(f"{s.id}: {s.title}") # SessionInfo: id, title, created_at 等 # 查看会话详情(含消息历史) detail = await client.get_session(session.id) for msg in detail.messages: print(f"{msg['role']}: {msg['content'][:80]}") # 删除会话 await client.delete_session(session.id) # 获取某 workdir 下最近会话(v1.7.4+) latest = await client.get_latest_session(workdir="/path/to/project")
与「只靠第一次 run() 自动建会话」相比,create_session() 适合要提前固定标题、或在跑任务前就把 id 交给 UI 的场景;run() 仍是最常见的入口。
典型使用场景对比
| 场景 | 是否传 session_id |
效果 |
|---|---|---|
| 单次任务(CI、批处理脚本) | 不传 | 每次独立,互不串联,避免历史污染 |
| 多轮交互(同一功能迭代) | 始终传同一个 | 模型记住前几轮约定与产出 |
| 恢复历史对话 | 传已存在的 session_id |
从断点继续,可与 list_sessions / get_latest_session 配合 |
务必自行保存业务关心的 session_id(内存变量、数据库或前端状态)。进程重启后 id 仍在 SQLite 里,可通过 list_sessions() 或 get_latest_session(workdir=...) 找回再传给 run()。
小结
多轮对话的枢纽是同一会话标识:自动路径下保存首轮返回的 session_id 即可;需要产品化能力时再组合 create_session / list_sessions / get_session / delete_session。下一篇 流式输出全解 会在保持会话的前提下,讲解如何边生成边消费模型输出。