当前位置: 首页 > news >正文

1000行代码实现极简版openclaw(附源码)(11)

10 - 完整数据流追踪github 源码(欢迎star)

目标

通过一个完整的例子,追踪数据在整个系统中的流动。

场景

用户输入:创建一个 test.txt 文件,内容是 "Hello"

数据流图解

┌─────────────────────────────────────────────────────────────────┐ │ Step 1: 用户输入 │ ├─────────────────────────────────────────────────────────────────┤ │ TerminalChannel.start() │ │ └── rl.question('You: ', input) │ │ └── input = "创建一个 test.txt 文件,内容是 \"Hello\"" │ └────────────────────────┬────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ Step 2: Channel 创建 Message │ ├─────────────────────────────────────────────────────────────────┤ │ const message = { │ │ id: "uuid-1", │ │ role: "user", │ │ content: "创建一个 test.txt 文件,内容是 \"Hello\"", │ │ timestamp: 1234567890 │ │ } │ │ │ │ this.onMessage?.(message, reply) // 调用 Gateway 注入的回调 │ └────────────────────────┬────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ Step 3: Gateway.handleMessage() │ ├─────────────────────────────────────────────────────────────────┤ │ const sessionId = "terminal_default" │ │ let session = this.sessions.get(sessionId) │ │ │ │ // 新会话,创建 Session 对象 │ │ session = { │ │ id: "terminal_default", │ │ channelType: "terminal", │ │ messages: [], │ │ createdAt: 1234567890, │ │ updatedAt: 1234567890, │ │ metadata: {} │ │ } │ │ this.sessions.set(sessionId, session) │ │ │ │ // 调用 Agent │ │ const response = await this.agent.process(message.content, session)│ └────────────────────────┬────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ Step 4: Agent.process() - 添加用户消息 │ ├─────────────────────────────────────────────────────────────────┤ │ session.messages.push({ │ │ id: "uuid-1", │ │ role: "user", │ │ content: "创建一个 test.txt 文件,内容是 \"Hello\"" │ │ }) │ │ │ │ // 进入 ReAct 循环 │ │ const response = await this.reactLoop(session, depth=0) │ └────────────────────────┬────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ Step 5: Agent.reactLoop() - 第 1 轮 THINK │ ├─────────────────────────────────────────────────────────────────┤ │ this.setState('thinking') │ │ │ │ // 构建 LLM 请求 │ │ const messages = [ │ │ { role: 'system', content: 'You are helpful...' }, │ │ { role: 'user', content: '创建一个 test.txt 文件,内容是 "Hello"' }│ │ ] │ │ │ │ const request = { │ │ model: 'deepseek-chat', │ │ messages: messages, │ │ tools: [write_file, read_file, list_files, ...] │ │ } │ │ │ │ const response = await provider.complete(request) │ │ │ │ // LLM 返回 │ │ response = { │ │ content: '我来创建文件', │ │ toolCalls: [{ │ │ id: 'call-1', │ │ name: 'write_file', │ │ parameters: { path: 'test.txt', content: 'Hello' } │ │ }] │ │ } │ └────────────────────────┬────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ Step 6: Agent.reactLoop() - 第 1 轮 ACT │ ├─────────────────────────────────────────────────────────────────┤ │ this.setState('acting') │ │ │ │ // 添加 assistant 消息(关键!) │ │ session.messages.push({ │ │ id: "uuid-2", │ │ role: "assistant", │ │ content: '我来创建文件', │ │ metadata: { │ │ toolCalls: [{ id: 'call-1', name: 'write_file', ... }] │ │ } │ │ }) │ │ │ │ // 执行工具 │ │ const tool = this.tools.get('write_file') │ │ const result = await tool.execute({ │ │ path: 'test.txt', │ │ content: 'Hello' │ │ }) │ │ // result: "已写入: test.txt" │ └────────────────────────┬────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ Step 7: Agent.reactLoop() - 第 1 轮 OBSERVE │ ├─────────────────────────────────────────────────────────────────┤ │ // 添加 tool 消息 │ │ session.messages.push({ │ │ id: "uuid-3", │ │ role: "tool", │ │ content: '已写入: test.txt', │ │ metadata: { toolCallId: 'call-1' } │ │ }) │ │ │ │ // 当前 session.messages: │ │ [ │ │ { role: 'user', content: '创建...' }, │ │ { role: 'assistant', metadata: { toolCalls: [...] } }, │ │ { role: 'tool', content: '已写入...' } │ │ ] │ │ │ │ // 递归进入第 2 轮 │ │ return this.reactLoop(session, depth=1) │ └────────────────────────┬────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ Step 8: Agent.reactLoop() - 第 2 轮 THINK │ ├─────────────────────────────────────────────────────────────────┤ │ this.setState('thinking') │ │ │ │ // 构建 LLM 请求(包含完整历史) │ │ const messages = [ │ │ { role: 'system', content: 'You are helpful...' }, │ │ { role: 'user', content: '创建一个 test.txt 文件...' }, │ │ { role: 'assistant', content: '我来创建文件', tool_calls: [{...}] },│ │ { role: 'tool', content: '已写入: test.txt', tool_call_id: 'call-1' }│ │ ] │ │ │ │ const response = await provider.complete(request) │ │ │ │ // LLM 看到历史里已经有 write_file 的结果,任务完成 │ │ response = { │ │ content: '文件已创建完成!', │ │ toolCalls: [] // 无工具调用 │ │ } │ └────────────────────────┬────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ Step 9: Agent.reactLoop() - 完成 │ ├─────────────────────────────────────────────────────────────────┤ │ // 没有 toolCalls,任务完成 │ │ this.setState('idle') │ │ │ │ return { │ │ id: "uuid-4", │ │ role: "assistant", │ │ content: "文件已创建完成!", │ │ timestamp: 1234567890 │ │ } │ └────────────────────────┬────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ Step 10: Gateway 返回响应 │ ├─────────────────────────────────────────────────────────────────┤ │ session.messages.push(response) │ │ │ │ // 调用 Channel 的 reply 回调 │ │ reply(response) │ └────────────────────────┬────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ Step 11: Channel 显示给用户 │ ├─────────────────────────────────────────────────────────────────┤ │ console.log(`\nAI: ${reply.content}\n`) │ │ │ │ 输出: │ │ AI: 文件已创建完成! │ └─────────────────────────────────────────────────────────────────┘

总结

通过这个追踪,我们可以看到:

  1. 数据是如何流动的:Channel → Gateway → Agent → LLM → Tools → …
  2. 消息历史的重要性:让 LLM 看到完整上下文
  3. ReAct 循环的工作方式:Think → Act → Observe → Loop

完结

恭喜!你已经完成了 TurboClaw 的完整教程。你现在应该能够:

下一步:动手实践,尝试添加自己的工具和功能!

http://www.jsqmd.com/news/534597/

相关文章:

  • 华为OD机考双机位C卷 - 区间连接器 (Java)
  • Microfire_Mod-EC:嵌入式高精度电导率测量模块解析
  • STM32水质检测系统设计与实现
  • 微信消息自动转发终极指南:零代码实现跨群智能同步
  • CPU时间单位
  • Windows/Linux双平台实测:TruevisionDesigner搭建OpenDRIVE地图全流程(附Carla兼容测试)
  • 别再只当它是个时钟!EPSON RX8010SJ RTC的5个隐藏玩法,让你的嵌入式项目更智能
  • 基于光子晶体光纤仿真与模式分析的SPR传感器技术研究:增强石墨烯-黑磷等离子体谐振效应的探索
  • 仅限内部技术团队流通的Dify异步接入SOP(含安全审计清单+可观测性埋点规范)
  • Pixel Dream Workshop效果实测:不同VAE tiling尺寸对1024x1024像素画渲染耗时影响
  • SEO_本地中小企业做好SEO推广的完整指南
  • 终极iOS越狱指南:使用palera1n突破iOS 15.0+设备限制的完整方案
  • TermControl:嵌入式轻量级VT100终端控制库
  • LFM2.5-1.2B-Thinking-GGUF开发者实操:32K长上下文在技术文档理解中的应用
  • 基于PyQt5与Matplotlib构建产品级高级可视化工具库
  • ChatTTS最新模型实战:从语音合成到生产环境部署的完整指南
  • yuzu模拟器配置与优化全攻略:从安装到流畅游戏
  • 别再手动写ALTER了!用Navicat结构同步对比两个MySQL数据库,一键生成变更脚本
  • vSphere集群运维实录:我是如何用DRS规则搞定‘主备分离’和‘亲密无间’的
  • GPT-SoVITS企业级部署指南:5大架构设计与性能优化策略
  • CKAN:坎巴拉太空计划的开源模组管理解决方案
  • 清单来了:2026 最新降AIGC网站测评与推荐
  • CString处理中文字符串的坑:Left/Mid/Right截取乱码问题与解决方案
  • Z-Image-Turbo-rinaiqiao-huiyewunv 与传统渲染器联动:作为Blender/Maya的创意灵感加速器
  • Llama-3.2V-11B-cot惊艳案例:从产品包装图中识别隐藏营销话术逻辑
  • ArcGIS 10.8实战:5分钟搞定全球海拔数据裁剪到中国行政区划(附shp文件下载)
  • html video rtsp流 浏览器网页显示监控视频实时画面(无浏览器插件)
  • PCIe协议栈深度解析:从TLP报文到数据流的端到端旅程
  • 统计人专属!统计插件002→VBA一键模糊匹配多列数据(附代码)
  • 从耳机降噪到智能家居:拆解知存WTM2101芯片,看存内计算如何落地你的生活