图_7Agent对话编排模块
对应 [[7_代码实现_Agent 对话编排]]。把历史、工具调用、证据、HITL、长期记忆和 SSE 汇成一次完整对话。
正常问答
加载会话与 metadata → 建立本轮 ctx → 保存用户消息 → “长期笔记 + 最近 6 条历史 + 当前问题” → 创建并运行 Agent → Tool / RAG → 读取结构化 Trace → 标准化追问或保留回答 → 更新 metadata → 保存 AI 消息和 Trace → 关闭 ctx。
跨轮 HITL
只有存在有效 resume_state 时,主入口才绕过外层 Agent,调用 _resume_rag_from_hitl_sync() → pipeline.resume_rag_from_hitl()。返回后,有证据就通过主模型生成回答,仍缺信息就重建 pending_hitl。合法 pending_hitl 却无快照时,使用拼接补充的兼容路径重新进入 Agent;不能把“存在 pending_hitl”都画成直接恢复。
流式与持久化
正常分支由内部 _agent_worker() 生产文本事件,ctx 把 RAG 步骤写进同一个 Queue,外层异步生成器按 SSE 格式输出。Trace 和 hitl_request 在主文本之后发送。[DONE] 发出后还要更新笔记和保存消息,直到生成器结束才完成收尾;图中按源码保留这一顺序。
函数框不是一份新实现;路径和函数名均映射本版本源码。内嵌 _agent_worker() 保持函数橙色,不画成类。工具选择和答案生成交给 Runtime 装配的 Agent;Service 负责业务状态与输出协议。
图形约定
绿色是目录,蓝色是文件,紫色是类,橙色是函数;标题中的名称与职责之间保留 12 个空格。类框中的编号通常对应其方法;函数框的编号描述内部步骤。没有组合,矩形宽高可分别调整。
导航
[[项目实现|查看项目实现总图]] · [[图_1数据存储模块|数据存储模块]]
Excalidraw Data
Text Elements
07 Agent对话编排模块 · 实现结构 ^cf89dc48
目录 → 文件 → 类 / 函数;框内编号表示局部职责,箭头表示主要调用。 ^da13d1e1
backend/ 承载本模块的后端代码 ^0800a602
chat/ 承载会话问答的业务编排 ^afcc15b0
[[7_代码实现_Agent 对话编排#2. 模块实现|service.py]] 同步 / 流式主入口及其辅助流程 ^86593fcd
chat_with_agent() 执行一轮同步问答
- storage.load_with_meta():取历史、笔记、pending_hitl
- 创建 ctx、重置预算;先保存当前 Human 消息
- 有有效恢复快照 → 直接续接 RAG;否则创建 Agent.invoke()
- 读取 Trace;若需澄清,用标准追问覆盖模型文本并建 pending_hitl
- 更新标题 / 笔记 / 待处理状态,保存 AI 消息与 rag_trace
- 返回 {response, rag_trace};finally ctx.close() ^7fcd9c81
chat_with_agent_stream() 产生本轮 SSE 事件
- 先发 rag_step;加载历史,创建 Queue 与流式 ctx,保存 Human
- 正常分支:启动 _agent_worker(),消费 Queue 并逐条 yield
- HITL 恢复:线程执行 RAG 并转发步骤,再 model.astream() 回答
- 输出 trace / hitl_request 和 [DONE];断开时取消 Agent 任务
- [DONE] 后继续更新笔记与落库;finally ctx.close() ^ed8d8b15
_agent_worker() 流式入口内部的生产协程
- Agent.astream(stream_mode="messages", recursion_limit=8)
- 只取 AI 文本;跳过工具调用片段,HITL 时抑制普通回答
- 向 Queue 写 content / error,最后写内部 None 哨兵 ^5a3543aa
同步 invoke 同样设置 recursion_limit=8。 [DONE] 是应用事件;不代表后续笔记更新和 PG 提交已完成。 ^d1a0d9f2
_build_context_messages() 控制本轮送给 Agent 的上下文
- 长期 persistent_note → SystemMessage
- 只取最近 6 条历史消息,再追加当前 HumanMessage ^fbd18eb9
_build_pending_hitl() 构造跨轮等待状态
- 组合原问题、追问、选项、已补充答案和恢复快照
- PendingHitlState 校验后写入 metadata.pending_hitl ^81b7bc12
_resume_rag_from_hitl_sync() 绕过外层 Agent 续接检索
- 从 pending_hitl 取快照,调用 pipeline.resume_rag_from_hitl()
- 缺快照时返回 None,由主入口保留兼容回退路径 ^f10c808b
_current_pending_hitl() 读取并校验已有追问
- 校验 PendingHitlState;无效值按未等待处理
- _pending_resume_state():提取快照
- _build_hitl_resume_query():无快照兼容路径拼接补充 ^97381911
_build_hitl_event() 生成流式追问事件
- 从 pending_hitl 选择前端所需字段
- _format_hitl_message():生成同步返回与历史保存的追问正文 ^12d7eef6
_answer_resumed_rag_sync() 基于恢复后的真实证据回答
- 无证据 → _no_knowledge_response() 固定提示
- 有证据 → _build_resume_answer_messages() → model.invoke()
- 仍需 HITL 时由主入口继续追问,不调用本回答分支 ^aaeb2a58
_should_update_persistent_note() 判断是否需要更新长期笔记
- 已有笔记,或历史消息数超过 6 条时更新 ^bbc80d03
_update_persistent_note_sync() 压缩保留长期关键信息
- FAST_MODEL:旧笔记 + 本轮问答;首次纳入更早历史
- 提示限制约 500 中文字;调用失败时保留旧笔记 ^b8acde16
update_persistent_note() 让流式收尾异步等待笔记更新
- run_in_executor() 调用同步摘要函数,避免阻塞事件循环 ^ceb25812
generate_session_title() 为首次会话生成短标题
- 本地截取首条用户文本,最多 16 字;不请求模型 ^7296277d
其余小工具合并阅读: _is_hitl_trace() / _hitl_route_from_trace() / _hitl_prompt_from_trace() / _hitl_options_from_trace():识别追问 _existing_hitl_answers():保留补充历史;_extract_ai_content() / _format_retrieved_chunks():整理模型输入输出 ^668b0c3b
主链依赖:图 6 的 Storage / ctx / Runtime → 图 5 工具 → 图 4 RAG;有效 HITL 恢复直接进入图 4。 ^6da9005d
Element Links
86593fcd: [[7_代码实现_Agent 对话编排#2. 模块实现]]
%%
Drawing
1 | N4IgLgngDgpiBcIYA8DGBDANgSwCYCd0B3EAGhADcZ8BnbAewDsEAmcm+gV31TkQAswYKDXgB6MSgw4CxAHSp6AWzJJMMJTEZgaCANqg8CEKgBmADgCcuVABZzqyLGNgUYVcgS2ArOQitfECI8MH4EbwBGc3J+GGwAc0EvbzlLAAYMzKzMgDZydEZ49QQ09jB8egBrGABhekx6fGMAYgiWAGY02wB2VQAjdFRK+IrORlw6hqbEcoKaKHR8LXdyU2 |
%%