Agent Engine
解释驱动 Agent 推理与动作循环的编排逻辑,以及它和运行时、工具、记忆与 AI Service 的职责边界。
[!info] related notes
- 所属 MOC: AI Agent Application MOC
- 上游概念: Agent, Augmented LLM
- 并列概念: Agent Runtime
- 下游组件: Tool Registry, Memory Manager, RAG Engine
Agent Engine
一句话定义
本文用 Agent Engine 指负责驱动 Agent 推理-动作循环的编排组件。它不是 LLM 本身,而是包住 LLM 的那层逻辑:决定何时调用模型、如何分发工具、怎样管理状态、何时停止。
它解决什么问题
单次模型调用不会自动完成应用侧的工具执行与后续调度。Agent 往往还需要:
- 多轮推理:模型说”我要先查数据”→ 执行查询 → 结果回传 → 模型继续推理
- 工具管理:注册、发现、执行、结果处理
- 状态维护:当前任务进度、已执行步骤、中间结果
- 记忆管理:短期对话历史、长期用户画像
- 可观测性:每次 LLM 调用的 token 消耗、延迟、决策路径
Agent Engine 把这些能力封装成一个可复用的模块。
核心原理
与 Agent Runtime 的关系
这两个概念容易混淆:
| Agent Engine | Agent Runtime | |
|---|---|---|
| 关注点 | 推理逻辑、工具编排、知识检索 | 执行环境、生命周期、状态持久化 |
| 类比 | 大脑 | 身体 |
| 典型组件 | LLM 调用、Tool Registry、RAG、Memory | Run、Step、Checkpoint、Trace、Timeout |
Engine 与 Runtime 并没有跨框架统一的划分:本笔记用 Engine 强调循环内的编排逻辑,Runtime 则覆盖执行生命周期和控制边界。LangGraph 等框架可以同时承担两者。RAG、独立 Planner 和长期记忆是按需组件,不是每个 Engine 的必备模块。
Engine 的核心组成
┌─────────────────────────────────────┐
│ Agent Engine │
│ │
│ ┌──────────┐ ┌──────────────┐ │
│ │ Planner │ │ LLM Gateway │ │
│ │ (规划器) │ │ (模型网关) │ │
│ └────┬─────┘ └──────┬───────┘ │
│ │ │ │
│ ┌────▼───────────────▼───────┐ │
│ │ Agent Loop │ │
│ │ (推理-动作循环) │ │
│ └────┬───────────┬───────────┘ │
│ │ │ │
│ ┌────▼────┐ ┌────▼──────────┐ │
│ │ Tool │ │ RAG Engine │ │
│ │Executor │ │ (检索增强) │ │
│ └─────────┘ └───────────────┘ │
│ │
│ ┌─────────────────────────────┐ │
│ │ Memory Manager │ │
│ │ (短期 + 长期记忆) │ │
│ └─────────────────────────────┘ │
└─────────────────────────────────────┘
Agent Loop 核心逻辑
以下是控制流伪代码,llm、事件与消息转换函数都是应用自定义抽象,并非可直接运行的 SDK 示例。工具执行前的授权、超时、取消和副作用去重由运行时负责。
messages = build_messages(context)
stop_reason = step_limit
for step in bounded_steps:
if retrieval_is_needed:
messages = inject_retrieved_context(messages)
response = call_model(messages, available_tool_schemas)
messages.append(assistant_message(response))
if response contains tool_calls:
for call in response.tool_calls:
result = execute_authorized_tool_with_runtime_controls(call)
messages.append(tool_result(call.id, result))
continue
final_output = validate_final_output(response)
stop_reason = completed
break
persist_run_state(messages, stop_reason)
emit_terminal_result(stop_reason)
必须先记录包含工具调用的 assistant 消息,再写入与 call ID 对应的工具结果;否则后续模型请求可能缺少调用上下文。达到步数上限应记录明确的停止原因,不能伪装成正常完成。这里的状态持久化也不等于把整段对话写入长期用户记忆。
在 React + Go + Python AI Service 架构中的位置
在这种三层架构方案中,可以把 Agent Engine 放在 Python AI Service 内部:
- 向上: 接收 Go 后端传来的 Context Bundle
- 向下: 调用 LLM Provider、Tool Executor、RAG Engine、Memory Manager
- 对外: 通过 SSE 流式输出事件到 Go 后端
典型工程实现
模块结构
以下是目录设计示例,不表示本仓库或某个部署已经存在这些模块;Engine 也可以运行在其他语言或进程中。
apps/ai-service/
engine/
agent_engine.py # Agent Engine 主逻辑
planner.py # 任务规划器
loop.py # Agent Loop
tools/
registry.py # Tool Registry
executor.py # Tool Executor
rag/
retriever.py # 检索器
reranker.py # 重排序
memory/
short_term.py # 短期记忆(对话历史)
long_term.py # 长期记忆(用户画像)
llm/
provider.py # LLM Provider 抽象
gateway.py # Model Gateway
与 LangGraph 的关系
LangGraph 的 StateGraph 可以表达这种循环;条件路由使用 add_conditional_edges,普通 add_edge 只连接节点。下面假定 AgentState、call_llm、execute_tool 和 has_tool_calls 已按应用消息格式定义;LLM 节点需保存 assistant 响应,工具节点需保存对应结果。
from langgraph.graph import StateGraph, START, END
graph = StateGraph(AgentState)
graph.add_node("llm", call_llm)
graph.add_node("tool", execute_tool)
graph.add_edge(START, "llm")
graph.add_conditional_edges(
"llm",
lambda state: "tool" if has_tool_calls(state) else "done",
{"tool": "tool", "done": END},
)
graph.add_edge("tool", "llm")
app = graph.compile()
图的终止边只定义正常退出路径;运行时仍需限制步数、处理失败与取消。该片段没有实现业务节点,也不是某个项目的运行验证记录。
常见设计模式
- ReAct 模式: Reasoning + Acting 的循环
- Plan-and-Execute 模式: 先规划步骤,再逐步执行
- Evaluator-Optimizer 模式: 生成 + 评估的闭环
- Multi-Agent 模式: 多个 Engine 协作
常见坑
- Engine 和 Runtime 职责不分: Engine 管推理逻辑,Runtime 管执行环境
- 没有最大步数限制: Agent 可能无限循环
- 工具执行不做隔离: 一个工具崩溃影响整个 Engine
- 上下文预算缺失: 历史、检索结果和工具输出持续增长,超过模型窗口;需要选择、截断或压缩,并保留必要的工具调用配对
和其他概念的关系
- vs Agent Runtime: Engine 是推理层,Runtime 是执行环境层
- vs Planner: Planner 可以是 Engine 的子模块,也可以由模型调用隐式完成规划
- vs AI Service: AI Service 是服务边界,可以容纳 Engine;两者并非固定绑定
- vs Agent Loop: Agent Loop 是 Engine 的核心执行逻辑
学习检查
- 工具结果回传前,为什么还需要保存 assistant 的工具调用消息?
- 没有 RAG 和长期记忆的系统能否拥有 Agent Engine?
- 正常完成、步数耗尽和工具失败为何需要不同的终态?