mirror of
https://github.com/tvytlx/ai-agent-deep-dive.git
synced 2026-04-03 07:34:50 +08:00
Add teaching Python agent CLI with Poetry and CI
This commit is contained in:
162
docs/08-agent-runtime-loop.md
Normal file
162
docs/08-agent-runtime-loop.md
Normal file
@@ -0,0 +1,162 @@
|
||||
# 08. Agent 运行时主循环规格
|
||||
|
||||
> 目标:定义 Python 版本实现时最核心的运行时循环。该文档不是源码解释,而是实现规格。
|
||||
|
||||
## 1. 设计目标
|
||||
|
||||
主循环必须满足以下目标:
|
||||
|
||||
1. 能持续推进任务,而不是只做一次回答
|
||||
2. 能在每轮后根据工具结果重新决策
|
||||
3. 能在权限阻断、上下文压缩、工具失败时继续可控运行
|
||||
4. 能触发子 agent、后台任务、验证任务
|
||||
5. 能生成可追踪的消息流与 transcript
|
||||
|
||||
## 2. 主循环的输入
|
||||
|
||||
一次主循环至少需要以下输入:
|
||||
|
||||
- `messages`: 当前消息序列
|
||||
- `system_prompt`: 已组装完成的系统提示词
|
||||
- `tool_registry`: 当前可用工具集合
|
||||
- `tool_use_context`: 执行上下文(cwd、权限、session、任务状态)
|
||||
- `memory_context`: 注入后的记忆内容
|
||||
- `user_context`: 用户态上下文
|
||||
- `system_context`: 系统态上下文
|
||||
- `can_use_tool`: 权限判断函数
|
||||
- `max_turns`: 最大回合数
|
||||
- `task_budget`: 本轮任务预算(可选)
|
||||
|
||||
## 3. 主循环的输出
|
||||
|
||||
主循环每轮可能产出:
|
||||
|
||||
- 普通 assistant 消息
|
||||
- tool_use 请求
|
||||
- tool_result 回写
|
||||
- progress 消息
|
||||
- compact / summary 边界消息
|
||||
- 子任务启动事件
|
||||
- terminal state(完成 / 失败 / 中断)
|
||||
|
||||
## 4. 循环状态
|
||||
|
||||
实现时必须维护显式状态,而不是散落在局部变量中。
|
||||
|
||||
建议状态字段:
|
||||
|
||||
```python
|
||||
class QueryState:
|
||||
messages: list
|
||||
turn_count: int
|
||||
auto_compact_tracking: dict | None
|
||||
pending_tool_summary: object | None
|
||||
stop_hook_active: bool
|
||||
max_output_recovery_count: int
|
||||
has_attempted_reactive_compact: bool
|
||||
transition_reason: str | None
|
||||
```
|
||||
|
||||
## 5. 标准单轮流程
|
||||
|
||||
每轮执行顺序建议固定为:
|
||||
|
||||
1. 预处理当前消息
|
||||
2. 计算 token / budget 状态
|
||||
3. 调用模型
|
||||
4. 解析返回内容
|
||||
5. 如有工具调用,进入工具执行链
|
||||
6. 将工具结果追加回消息
|
||||
7. 如需压缩,执行 compact
|
||||
8. 决定是否继续下一轮
|
||||
9. 达到终止条件则返回 terminal state
|
||||
|
||||
## 6. 终止条件
|
||||
|
||||
至少支持以下终止条件:
|
||||
|
||||
- 模型明确结束任务
|
||||
- 达到 `max_turns`
|
||||
- 用户中断
|
||||
- 权限阻断且无可行替代方案
|
||||
- 发生不可恢复异常
|
||||
- 任务被后台化或移交
|
||||
|
||||
## 7. 工具调用处理要求
|
||||
|
||||
如果模型返回一个或多个工具调用:
|
||||
|
||||
- 必须按顺序或编排策略执行
|
||||
- 必须将每个 tool_result 写回消息流
|
||||
- 如果工具失败,失败信息也必须结构化回写
|
||||
- 严禁只在 UI 层显示,不回写到模型上下文
|
||||
|
||||
## 8. 压缩与恢复点
|
||||
|
||||
主循环必须内建以下钩子点:
|
||||
|
||||
- 调用模型前检查是否需要压缩
|
||||
- 工具结果过长时应用 result budget
|
||||
- prompt 过长时触发 compact / reactive compact
|
||||
- resume 时从 compact boundary 后恢复有效消息
|
||||
|
||||
## 9. 子 agent 与后台任务接入点
|
||||
|
||||
主循环必须允许以下事件打断常规路径:
|
||||
|
||||
- 启动 foreground subagent
|
||||
- 启动 background subagent
|
||||
- 接收 task notification
|
||||
- 继续 resume 某个已有 agent
|
||||
|
||||
## 10. Python 版推荐伪代码
|
||||
|
||||
```python
|
||||
def query_loop(params):
|
||||
state = init_state(params)
|
||||
|
||||
while True:
|
||||
if should_stop(state, params):
|
||||
return terminal_result(state)
|
||||
|
||||
state = maybe_compact(state, params)
|
||||
request = build_model_request(state, params)
|
||||
response = call_model(request)
|
||||
state.messages.append(response.assistant_message)
|
||||
|
||||
if response.tool_calls:
|
||||
tool_events = run_tools(response.tool_calls, params)
|
||||
state.messages.extend(tool_events)
|
||||
state.transition_reason = 'tool_round'
|
||||
continue
|
||||
|
||||
if response.should_launch_subagent:
|
||||
launch_subagent(response, params)
|
||||
state.transition_reason = 'subagent'
|
||||
continue
|
||||
|
||||
if response.is_terminal:
|
||||
return terminal_result(state)
|
||||
|
||||
state.turn_count += 1
|
||||
```
|
||||
|
||||
## 11. 实现边界
|
||||
|
||||
Python 第一版务必保证:
|
||||
- 单主循环是清晰、可测试的
|
||||
- 每轮状态可序列化
|
||||
- 每轮输出可回放
|
||||
- 每轮失败可定位
|
||||
|
||||
不要把主循环写成大量隐式副作用的脚本式逻辑。
|
||||
|
||||
## 12. 验收标准
|
||||
|
||||
程序员实现完成后,应满足:
|
||||
|
||||
1. 可以连续多轮处理任务
|
||||
2. 工具结果能回流并影响下一轮
|
||||
3. 超长上下文会压缩而不是直接崩溃
|
||||
4. 子任务可以插入主流程
|
||||
5. transcript 可完整记录轮次
|
||||
Reference in New Issue
Block a user