Appearance
AI 智能体请求生命周期
本页解释一次聊天请求如何从 HTTP/外部渠道进入 Agent 运行时,如何经过队列和 session 执行器,最后以消息、SSE、轨迹和运行状态四种形式落地。阅读顺序建议结合请求链路与时序和智能体执行引擎。
1. 入口模式
AiChatbotAgentController 的 /v1/chatbot/{agentId}/sessions/{sessionId}/chat 有三种行为:
| 请求组合 | 服务端行为 | 客户端下一步 |
|---|---|---|
stream=true&sse=sync | 当前请求直接获得 SseEmitter,边执行边推送 | 持续消费 SSE,等待完成/错误 |
stream=true&sse=async | 用户消息先入队,返回 messageId | 先建立 /sse/connect,再消费流 |
stream=false | 同步等待 handleNormalChat 返回 | 读取 R<T>,仍需判断业务终态 |
sessionId=new 时 Controller 先创建会话;已有 session 则验证 Agent、用户和租户归属。创建会话时可能同时绑定 FileRoom/Sandbox workspace,这个绑定会在后续 load_config 转换为 AgentConfig.sandboxRoomId,不能由每一轮请求随意替换。
2. 接受消息与持久化
AgentChatServiceImpl 接受消息后生成或补齐以下标识:
| 标识 | 生命周期 | 用途 |
|---|---|---|
clientMessageId | 客户端请求级 | pause/resume/cancel 和用户消息去重 |
messageId | 队列消息级 | SSE、错误和队列日志关联 |
turnId | 用户一轮输入 | JSONL 聊天历史和分支投影 |
runId | 一次 Agent 执行 | checkpoint、轨迹、取消和计费关联 |
runVersion | session 当前运行版本 | CAS 更新,拒绝旧运行迟到事件 |
traceId | 可观测性上下文 | 节点、LLM、工具、RAG 日志关联 |
启用 JSONL 持久化时,接受用户输入会先写入 session 事件账本,再提交队列;这样即使 worker 尚未启动,也能从 durable inbox 恢复。AgentMessage 会同时保留原始 content 和可供模型使用的 modelContent,附件链接、联网搜索模式、Bearer Token 和 billing 预冻结号也随消息传播。
3. 调度器分发
CentralizedAgentMessageDispatcher 由一个 dispatcher 线程从 AgentMessageQueue.poll() 取消息,再按 sessionId 获取独占的单线程虚拟线程执行器:
调度不变量:
- 同一
sessionId的用户输入、resume、cancel 和子 Agent 回调 FIFO 串行。 - 不同 session 可以并行,线程是虚拟线程,但底层模型/工具仍受各自连接池和限流约束。
submitLocal用于回复目标保存在当前节点内存的外部 IM;直接放入共享队列可能导致消费节点找不到回调对象。- 队列实现可为 Memory、Redis 或 RocketMQ;切换实现不能改变
AgentMessage字段语义。 - 队列满、worker 拒绝和响应通道超时都必须写失败终态,不能只打印日志。
4. 智能体类型路由
dispatcher 从数据库读取 AgentType 后选择执行器:
| AgentType | 执行器 | 说明 |
|---|---|---|
CHATBOT | AiChatbotAgentFactory 创建的 Agent | 当前实现继承自主规划外壳 |
GENERATION | GenerationAgent | 内容生成型调用 |
TOOL_CALL | ToolCallAgent | 工具调用型调用 |
DOMAIN_EXPERT | AutoPlanningAgent | 主动规划和 Agentic Loop |
WORKFLOW | 当前抛出不支持异常 | 不能假定已有工作流执行器 |
Agent 类型不存在或解析失败时当前代码会降级 AutoPlanningAgent;新增类型时必须同时更新 dispatcher、管理 API、前端选择项和恢复时的 graph 版本策略。
5. 单次智能体执行
worker 进入 Agent 前会:
- 从
ChatSessionManager读取活动 session,检查过期、状态和最大轮数。 - 从
AgentResponseChannelRegistry等待可用响应通道,等待超时则失败并写 pending error。 - 绑定
McpSessionContext,让@Tool、Feign/MCP 和 Sandbox 下游取得 session、Agent、user 上下文。 - 启动
ConversationContext和TraceLifecycle,记录原始用户输入、流式模式和 runId。 - 调用 Agent 的
processMessage,在 finally 中刷新响应快照、释放运行时和 active worker。
自主规划路径进入 AutoPlanningAgent 主图:
text
load_config -> intent_recognition -> web_search_prefetch -> planning
-> agentic_loop(init/reasoning/acting/refining/checkpoint)
-> task_end主图、子图、路由信号和状态桥接详见智能体执行引擎。
6. 终态顺序
一个运行可能出现 QUEUED、RUNNING、PAUSE_REQUESTED、PAUSED、COMPLETED、FAILED、CANCELLED 或 RECOVERY_BLOCKED。终态处理需要遵循以下顺序:
text
刷新 token buffer
-> 写 assistant response snapshot
-> 写最终轨迹/聊天历史
-> 更新 run-control 和数据库运行状态
-> 发送 complete/error/cancel 事件
-> 释放 channel、LoopRuntime、active worker客户端断线只代表传输通道不可用,不代表 Agent 取消。取消必须调用 /cancel;暂停必须等待 refining -> checkpoint 安全点。普通聊天 SSE 通过 pending event 和回答快照恢复,轨迹 SSE 通过 Last-Event-ID/sequence 恢复。
7. 失败与重试边界
| 位置 | 当前策略 | 不应做的事 |
|---|---|---|
| 配置加载 | 记录 error,跳过后续规划或直接进入 task end | 带空配置调用模型 |
| LLM 调用 | 按节点重试/记录 finish reason | 无限重试 |
| 工具调用 | 工具节点最多三次外层尝试,并有超时兜底;Agentic Loop 另有 journal | 失败后无记录重跑副作用 |
| RAG | 返回结果或错误字符串,由循环决定后续动作 | 把空检索当成事实 |
| channel | 等待有限时间,失败写 pending error | 阻塞 worker 永不退出 |
| 恢复 | 版本、配置、surface digest 不一致时 RECOVERY_BLOCKED | 清空状态重新执行 |
排障时先按 runId -> messageId -> traceId -> sessionId 关联日志,再查看最后一个 graph node、工具 journal 和响应通道。不要只看 Controller 的 HTTP 200。