进阶第 2 章:请求管线
业务问题
面试官问“一次用户输入到底发生了什么”,你需要能沿着真实管线讲清楚,而不是只说“调了模型”。
交互图解:一次 Agent Turn 完整调用链 · 查看图解导读
核心原理
一次请求通常经过:
text
输入进入 inbox
-> 打开 turn
-> 组装 system prompt 和 tool schema
-> agent/pre-step
-> 写入用户消息
-> 派生历史
-> agent/request
-> llm/stream
-> 组装 assistant message
-> 工具调用或结束这里有两种事件:
- durable session event:写入日志,例如
user/message、assistant/message、tool/result。 - live extension point:用于策略和拦截,例如
agent/pre-step、agent/request。
真实项目中的映射
AI 编码助手不能直接执行模型说的一切。请求管线需要给策略层插入机会:
- pre-step:决定模型看到什么。
- request:决定请求配置。
- llm/stream:记录或重试流式调用。
- tools/pre-execute:决定工具是否允许。
- tools/post-execute:检查或替换工具结果。
DeepSeek Harness 对应实现
DeepSeek Harness 的 turn flow 在 docs/architecture.md 中有完整描述。
关键 waterfall 事件:
agent/pre-stepagent/requestagent/request-errorllm/streamtools/pre-executetools/executetools/post-execute
这些监听器必须调用 next() 才能委托给下一层。
进一步阅读:
docs/architecture.md#turn-flowpackages/core/agent-loop/src/agent.ts
代码示例
ts
type Next<T> = () => Promise<T>
interface PipelineStep<T> {
run(value: T, next: Next<T>): Promise<T>
}
async function runPipeline<T>(steps: PipelineStep<T>[], value: T): Promise<T> {
let index = 0
const next = (): Promise<T> => {
const step = steps[index]
index += 1
if (!step) return Promise.resolve(value)
return step.run(value, next)
}
return next()
}这个例子是 waterfall 的最小实现。策略层可以包装结果或直接短路。
面试追问
问:durable event 和 live event 有什么区别?
回答要点:
- durable event 写入会话日志,能持久化和回放。
- live event 是运行时扩展点,不一定持久化。
- 模型可见内容必须来自 durable event。
问:waterfall 和普通 event listener 有什么区别?
回答要点:
- waterfall 返回一个值。
- listener 可以调用
next()委托。 - listener 也可以不调用
next()直接短路。
问:工具调用为什么放在模型响应之后?
回答要点:
- 模型先生成工具调用意图。
- 运行时解析和校验。
- 执行后结果回传给模型。
- 这样才能继续下一轮推理。
实践任务
画出“用户输入 -> 模型 -> 工具 -> 模型 -> 最终回答”的时序图,并标出每个阶段应记录什么事件。
验收标准
- 能画出完整请求管线。
- 能区分 durable event 和 live event。
- 能解释 waterfall 的
next()语义。