DEEPSEEK HARNESS · OFFLINE TUTORIAL
08 · Agent Loop
Inbox、Turn、Step、停止与错误
1. 一次完整 Turn
turn/start
│
claim inbox input
│
assemble prompt + tool schemas
│
agent/pre-step
│
└─ enter(messages)
│
step/start
│
user/message
│
deriveMessages()
│
agent/request
│
llm/stream
│
assistant/chunk*
│
assistant/message
│
tool/call*
│
tools/pre-execute
│
tools/execute
│
tools/post-execute
│
tool/result*
│
step/end
│
continuation / next input?
│
no
│
agent/turn-stopping
│
turn/end
2. 脑内伪代码
async function drive(agent) {
while (agent.hasWork()) {
append("turn/start")
while (agent.turnHasWork()) {
const claimed = inbox.claim()
const decision = await waterfall("agent/pre-step", claimed)
if (decision.reject) break
append("step/start")
appendEnteredMessages(decision.messages)
const history = session.deriveMessages()
const request = assembleRequest({ history, systemPrompt, tools })
const output = await llm.stream(request)
appendAssistant(output)
await executeTools(extractToolCalls(output))
append("step/end")
}
await serial("agent/turn-stopping")
append("turn/end")
}
}
3. Inbox 为什么比 run(prompt) 更丰富
输入可以有 follow-up、steer、inject 等不同语义。特别是 inject,可以加入“下一次模型可见上下文”,但未必自己唤醒 driver。
4. Agent 与 AgentLoop 分开
Interface ≠ Driver implementation。其它插件尽量依赖 Agent handle,而不是具体 loop class。这样 loop strategy 本身也可以替换。
5. 精读顺序
- Service 如何暴露。
- Concrete Agent class。
- send / inbox / deriveMessages / request / stream。
- tool-calls scheduler。
- runtime-context / invariant。
- cancellation / error / retry / stopping。
6. 真正难点
- 什么时候“欠工作”?
- 什么时候应再 Step 一次?
- Streaming 中收到 steer 怎么办?
- 工具执行中 cancel 怎么办?
- 崩溃后如何判断副作用做到哪一步?
只有当变化属于所有 Agent 都共享的 generic control-flow semantics,且现有 seam 无法正确表达时,才优先考虑改 Agent Loop。