Skip to content
签到签到

进阶第 2 章:请求管线

业务问题

面试官问“一次用户输入到底发生了什么”,你需要能沿着真实管线讲清楚,而不是只说“调了模型”。

交互图解:一次 Agent Turn 完整调用链 · 查看图解导读

核心原理

一次请求通常经过:

text
输入进入 inbox
-> 打开 turn
-> 组装 system prompt 和 tool schema
-> agent/pre-step
-> 写入用户消息
-> 派生历史
-> agent/request
-> llm/stream
-> 组装 assistant message
-> 工具调用或结束

这里有两种事件:

  • durable session event:写入日志,例如 user/messageassistant/messagetool/result
  • live extension point:用于策略和拦截,例如 agent/pre-stepagent/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-step
  • agent/request
  • agent/request-error
  • llm/stream
  • tools/pre-execute
  • tools/execute
  • tools/post-execute

这些监听器必须调用 next() 才能委托给下一层。

进一步阅读:

  • docs/architecture.md#turn-flow
  • packages/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() 语义。