3.2 核心数据流:从用户输入到 AI 响应

模型: claude-opus-4-6 (anthropic/claude-opus-4-6) 生成日期: 2025-02-17


理解 OpenCode 架构的关键是理解数据如何从用户的一次键盘输入,流经整个系统,最终产生 AI 的回复。本节将完整追踪这条数据流。

3.2.1 用户消息 → Session.chat() → SessionPrompt.prompt() → LLM.stream()

当用户在 TUI 中输入一条消息并按下回车,以下调用链会依次触发:

用户按下回车


TUI 发送 HTTP POST 请求
POST /project/:id/session/:sid/message
body: { parts: [{ type: "text", text: "帮我实现一个排序函数" }] }


Server 路由处理 (routes/session.ts)


SessionPrompt.prompt(input)          ← session/prompt.ts

    ├── 1. Session.get(sessionID)     获取会话信息
    ├── 2. SessionRevert.cleanup()    清理未完成的回滚
    ├── 3. createUserMessage(input)   创建用户消息并存储
    ├── 4. Session.touch(sessionID)   更新会话时间戳
    └── 5. loop({ sessionID })        进入 Agentic Loop ←── 核心!

SessionPrompt.prompt() 的源码结构清晰地展示了这个流程:

loop() 函数是整个 Agentic Loop 的入口,它会:

  1. 从数据库加载会话的所有消息

  2. 解析当前应使用的 Agent 和 Model

  3. 组装 System Prompt(包括 AGENTS.md 指令、环境信息等)

  4. 注册所有可用的 Tools

  5. 创建一个 SessionProcessor

  6. 调用 LLM.stream() 发起流式 LLM 调用

  7. 处理流式响应(文本、思考链、工具调用)

3.2.2 流式响应处理:SessionProcessor 的 Agentic Loop

SessionProcessorsession/processor.ts)是 OpenCode 中最复杂也最重要的模块之一。它实现了完整的 Agentic Loop:

流式事件的处理顺序

每个 Part 的变化都会实时通过 Session.updatePart() 写入存储,并通过事件总线推送到前端,实现实时显示。

3.2.3 工具调用循环:Tool Call → Execute → Result → Continue

当 LLM 的响应中包含工具调用时,处理流程如下:

Doom Loop 检测

OpenCode 内置了 Doom Loop(死循环)检测机制:

如果 Agent 连续 3 次执行相同的操作模式而没有实质性进展,系统会触发 doom_loop 权限检查。根据配置,这可能会暂停执行并询问用户是否继续。这是防止 AI 陷入无限循环的安全措施。

3.2.4 完整的请求-响应时序图

将上述所有步骤串联起来,一次完整的对话交互的时序如下:

这张时序图展示了 OpenCode 的核心特点:

  1. 异步流式处理:从 LLM 的第一个 token 开始,用户就能看到响应

  2. 事件驱动:所有状态变化通过 Bus 广播,前端通过 SSE 接收

  3. 循环架构:工具调用和 LLM 生成交替执行,直到 LLM 决定停止

理解了这条核心数据流,后续章节对各个模块的深入分析就有了坐标系。

Last updated