从零开始构建你自己的 AI Agent - v0: Bash Agent

0 阅读26分钟

教程来自:https://github.com/shareAI-lab/learn-claude-code

官方仓库已经找不到旧版教程(v0-v4),我备份到了自己的仓库:v0: Bash 就是一切

以下是shareAI-lab/learn-claude-code旧版教程原文

v0: Bash 就是一切

终极简化:~50 行代码,1 个工具,完整的 Agent 能力。

在构建 v1、v2、v3 之后,一个问题浮现:Agent 的本质到底是什么?

v0 通过反向思考来回答——剥离一切,直到只剩下核心。

核心洞察

Unix 哲学:一切皆文件,一切皆可管道。Bash 是这个世界的入口:

你需要Bash 命令
读文件cat, head, grep
写文件echo '...' > file
搜索find, grep, rg
执行python, npm, make
子代理python v0_bash_agent.py "task"

最后一行是关键洞察:通过 bash 调用自身就实现了子代理。不需要 Task 工具,不需要 Agent Registry——只需要递归。

完整代码

#!/usr/bin/env python
from anthropic import Anthropic
import subprocess, sys, os

client = Anthropic(api_key="your-key", base_url="...")
TOOL = [{
    "name": "bash",
    "description": """执行 shell 命令。模式:
- 读取: cat/grep/find/ls
- 写入: echo '...' > file
- 子代理: python v0_bash_agent.py 'task description'""",
    "input_schema": {"type": "object", "properties": {"command": {"type": "string"}}, "required": ["command"]}
}]
SYSTEM = f"CLI agent at {os.getcwd()}. Use bash. Spawn subagent for complex tasks."

def chat(prompt, history=[]):
    history.append({"role": "user", "content": prompt})
    while True:
        r = client.messages.create(model="...", system=SYSTEM, messages=history, tools=TOOL, max_tokens=8000)
        history.append({"role": "assistant", "content": r.content})
        if r.stop_reason != "tool_use":
            return "".join(b.text for b in r.content if hasattr(b, "text"))
        results = []
        for b in r.content:
            if b.type == "tool_use":
                out = subprocess.run(b.input["command"], shell=True, capture_output=True, text=True, timeout=300)
                results.append({"type": "tool_result", "tool_use_id": b.id, "content": out.stdout + out.stderr})
        history.append({"role": "user", "content": results})

if __name__ == "__main__":
    if len(sys.argv) > 1:
        print(chat(sys.argv[1]))  # 子代理模式
    else:
        h = []
        while (q := input(">> ")) not in ("q", ""):
            print(chat(q, h))

这就是整个 Agent。~50 行。

子代理工作原理

主代理
  └─ bash: python v0_bash_agent.py "分析架构"
       └─ 子代理(独立进程,全新历史)
            ├─ bash: find . -name "*.py"
            ├─ bash: cat src/main.py
            └─ 通过 stdout 返回摘要

进程隔离 = 上下文隔离

  • 子进程有自己的 history=[]
  • 父进程捕获 stdout 作为工具结果
  • 递归调用实现无限嵌套

v0 牺牲了什么

特性v0v3
代理类型explore/code/plan
工具过滤白名单
进度显示普通 stdout行内更新
代码复杂度~50 行~450 行

v0 证明了什么

复杂能力从简单规则中涌现:

  1. 一个工具足够 — Bash 是通往一切的入口
  2. 递归 = 层级 — 自我调用实现子代理
  3. 进程 = 隔离 — 操作系统提供上下文分离
  4. 提示词 = 约束 — 指令塑造行为

核心模式从未改变:

while True:
    response = model(messages, tools)
    if response.stop_reason != "tool_use":
        return response.text
    results = execute(response.tool_calls)
    messages.append(results)

其他一切——待办、子代理、权限——都是围绕这个循环的精化。


Bash 就是一切。

← 返回 README

JavaScript 实现

我在官方教程基础上,将 Python 实现转成了 JavaScript 实现。

并将 Anthropic API 换成了更通用的 OpenAI Chat API

Windows 中需要使用 powershell.exe 执行 shell命令,系统提示词需要指明操作系统和 shell 语法要求。

对于基于 STDIO 的 Agent:永远不要向标准输出(stdout)和标准错误(stderr)写入。

可以把日志写到文件:

const logger = fs.createWriteStream('debug.log', {
  flags: 'a',
  encoding: 'utf-8'
})

完整 JavaScript 版实现代码:

#!/usr/bin/env node
const { spawnSync } = require('node:child_process')
const readline = require('node:readline')
const process = require('node:process')
const OpenAI = require('openai')

// 对于基于 STDIO 的服务器:永远不要向标准输出(stdout)和标准错误(stderr)写入。
// ❌ Bad (STDIO)
// console.log("xxx");
// console.error("xxx");

const isWin32 = process.platform === 'win32'

const client = new OpenAI({
  apiKey: 'xxx',
  baseURL: 'http://127.0.0.1:3003'
})

const SHELL_DESCRIPTION = isWin32
  ? `Execute PowerShell command. Patterns:
- Read: Get-Content/Select-String/Get-ChildItem
- Write: Set-Content/Add-Content/Out-File
- Subagent: node agent_v0.js "task description"`
  : `Execute shell command. Patterns:
- Read: cat/grep/find/ls
- Write: echo '...' > file
- Subagent: node agent_v0.js "task description"`

const tools = [
  {
    type: 'function',
    function: {
      name: 'shell',
      description: SHELL_DESCRIPTION,
      parameters: {
        type: 'object',
        properties: {
          command: {
            type: 'string',
            description: isWin32
              ? 'The PowerShell command to execute'
              : 'The shell command to execute'
          }
        },
        required: ['command'],
        additionalProperties: false
      },
      strict: true
    }
  }
]

const SYSTEM = [
  {
    role: 'system',
    content: isWin32
      ? `Windows CLI agent at ${process.cwd()}. You are running on Windows using PowerShell. Use PowerShell syntax. Spawn subagent for complex tasks.`
      : `Linux CLI agent at ${process.cwd()}. You are running on Linux using bash. Use POSIX syntax. Spawn subagent for complex tasks.`
  }
]

async function chat(prompt, history = []) {
  history.push({ role: 'user', content: prompt })

  while (true) {
    // 调用 OpenAI API
    const response = await client.chat.completions.create({
      model: 'xxx',
      messages: SYSTEM.concat(history),
      tools
    })
    const message = response.choices[0].message

    // 将助手回复(包括可能存在的 tool_calls)加入历史
    // OpenAI 要求必须保留原始的 tool_calls 对象以便上下文对齐
    history.push(message)

    // 检查是否有工具调用
    if (!message.tool_calls || message.tool_calls.length === 0) {
      return message.content
    }

    // 处理工具调用
    for (const toolCall of message.tool_calls) {
      if (toolCall.function.name === 'shell') {
        // OpenAI 返回的 arguments 是 JSON 字符串,需要解析
        let args = JSON.parse(toolCall.function.arguments)

        // 执行 shell 命令
        const child = spawnSync(args.command, {
          shell: isWin32 ? 'powershell.exe' : true,
          encoding: 'utf-8',
          timeout: 30000 // 30秒超时
        })

        const output = (child.stdout || '') + (child.stderr || '')

        // 将工具结果加入历史
        // OpenAI 要求 role 为 "tool",且必须包含 tool_call_id
        history.push({
          role: 'tool',
          tool_call_id: toolCall.id,
          content: output
        })
      }
    }

    // 循环继续,将工具结果发回给模型,等待下一次响应
  }
}

async function main() {
  // 处理命令行参数 (process.argv[0] 是 node, [1] 是脚本路径, [2] 开始是参数)
  const args = process.argv.slice(2)

  if (args.length > 0) {
    // 子代理模式 (命令行参数直接运行)
    const response = await chat(args[0])
    console.log(response)
  } else {
    // 交互模式 (REPL)
    const history = []
    const rl = readline.createInterface({
      input: process.stdin,
      output: process.stdout
    })

    const ask = () => {
      rl.question('>> ', async q => {
        if (q === 'q' || q === '') {
          rl.close()
          return
        }
        try {
          const response = await chat(q, history)
          console.log(response)
        } catch (error) {
          console.error('Error:', error.message)
        }
        ask() // 递归调用以保持对话循环
      })
    }

    ask()
  }
}

main()

打开计算器

image.png

完整接口调用过程如下:

// 请求
{
  "model": "xxx",
  "messages": [
    {
      "role": "system",
      "content": "Windows CLI agent at D:\\Learn\\AgentDemo. You are running on Windows using PowerShell. Use PowerShell syntax. Spawn subagent for complex tasks."
    },
    {
      "role": "user",
      "content": "打开计算器"
    }
  ],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "shell",
        "description": "Execute PowerShell command. Patterns:\n- Read: Get-Content/Select-String/Get-ChildItem\n- Write: Set-Content/Add-Content/Out-File\n- Subagent: node agent_v0.js \"task description\"",
        "parameters": {
          "type": "object",
          "properties": {
            "command": {
              "type": "string",
              "description": "The PowerShell command to execute"
            }
          },
          "required": [
            "command"
          ],
          "additionalProperties": false
        },
        "strict": true
      }
    }
  ]
}

{
  "id": "gen-1772421274-IVqRC1h9eXq4aJfl8y0I",
  "provider": "Minimax",
  "model": "minimax/minimax-m2.5",
  "object": "chat.completion",
  "created": 1772421274,
  "choices": [
    {
      "logprobs": null,
      "finish_reason": "tool_calls",
      "native_finish_reason": "tool_calls",
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "",
        "refusal": null,
        "reasoning": "用户想要打开计算器。在Windows系统上,我可以通过PowerShell命令来启动计算器应用程序。",
        "tool_calls": [
          {
            "type": "function",
            "index": 0,
            "id": "call_function_6kmin5fchkw2_1",
            "function": {
              "name": "shell",
              "arguments": "{\"command\": \"Start-Process calc\"}"
            }
          }
        ],
        "reasoning_details": [
          {
            "format": null,
            "index": 0,
            "type": "reasoning.text",
            "text": "用户想要打开计算器。在Windows系统上,我可以通过PowerShell命令来启动计算器应用程序。"
          }
        ]
      }
    }
  ],
  "usage": {
    "prompt_tokens": 266,
    "completion_tokens": 49,
    "total_tokens": 315,
    "cost": 0,
    "is_byok": true,
    "prompt_tokens_details": { "cached_tokens": 0, "audio_tokens": 0 },
    "cost_details": {
      "upstream_inference_cost": 0.0001386,
      "upstream_inference_prompt_cost": 0.0000798,
      "upstream_inference_completions_cost": 0.0000588
    },
    "completion_tokens_details": { "reasoning_tokens": 23, "audio_tokens": 0 }
  },
  "cost": "0"
}

// 请求
{
  "model": "xxx",
  "messages": [
    {
      "role": "system",
      "content": "Windows CLI agent at D:\\Learn\\AgentDemo. You are running on Windows using PowerShell. Use PowerShell syntax. Spawn subagent for complex tasks."
    },
    {
      "role": "user",
      "content": "打开计算器"
    },
    {
      "role": "assistant",
      "content": "",
      "refusal": null,
      "reasoning": "用户想要打开计算器。在Windows系统上,我可以通过PowerShell命令来启动计算器应用程序。",
      "tool_calls": [
        {
          "type": "function",
          "index": 0,
          "id": "call_function_6kmin5fchkw2_1",
          "function": {
            "name": "shell",
            "arguments": "{\"command\": \"Start-Process calc\"}"
          }
        }
      ],
      "reasoning_details": [
        {
          "format": null,
          "index": 0,
          "type": "reasoning.text",
          "text": "用户想要打开计算器。在Windows系统上,我可以通过PowerShell命令来启动计算器应用程序。"
        }
      ]
    },
    {
      "role": "tool",
      "tool_call_id": "call_function_6kmin5fchkw2_1",
      "content": ""
    }
  ],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "shell",
        "description": "Execute PowerShell command. Patterns:\n- Read: Get-Content/Select-String/Get-ChildItem\n- Write: Set-Content/Add-Content/Out-File\n- Subagent: node agent_v0.js \"task description\"",
        "parameters": {
          "type": "object",
          "properties": {
            "command": {
              "type": "string",
              "description": "The PowerShell command to execute"
            }
          },
          "required": [
            "command"
          ],
          "additionalProperties": false
        },
        "strict": true
      }
    }
  ]
}


{
  "id": "gen-1772421278-UkkIUCtGdyqNsNgqV2mI",
  "provider": "Minimax",
  "model": "minimax/minimax-m2.5",
  "object": "chat.completion",
  "created": 1772421278,
  "choices": [
    {
      "logprobs": null,
      "finish_reason": "stop",
      "native_finish_reason": "stop",
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "已打开计算器!✅",
        "refusal": null,
        "reasoning": "命令已成功执行,计算器应该已经打开了。calc 是 Windows 系统自带计算器的命令。",
        "reasoning_details": [
          {
            "format": null,
            "index": 0,
            "type": "reasoning.text",
            "text": "命令已成功执行,计算器应该已经打开了。calc 是 Windows 系统自带计算器的命令。"
          }
        ]
      }
    }
  ],
  "usage": {
    "prompt_tokens": 325,
    "completion_tokens": 29,
    "total_tokens": 354,
    "cost": 0,
    "is_byok": true,
    "prompt_tokens_details": { "cached_tokens": 0, "audio_tokens": 0 },
    "cost_details": {
      "upstream_inference_cost": 0.0001323,
      "upstream_inference_prompt_cost": 0.0000975,
      "upstream_inference_completions_cost": 0.0000348
    },
    "completion_tokens_details": { "reasoning_tokens": 22, "audio_tokens": 0 }
  },
  "cost": "0"
}

同时调用两个Subagent分别执行:src目录下有多少个js文件、print目录下有多少个文件,最后把两个数相加的等式保存到results.txt

image.png

完整接口调用过程如下:

// 请求
{
  "model": "xxx",
  "messages": [
    {
      "role": "system",
      "content": "Windows CLI agent at D:\\Learn\\AgentDemo. You are running on Windows using PowerShell. Use PowerShell syntax. Spawn subagent for complex tasks."
    },
    {
      "role": "user",
      "content": "同时调用两个Subagent分别执行:src目录下有多少个js文件、print目录下有多少个文件,最后把两个数相加的等式保存到results.txt"
    }
  ],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "shell",
        "description": "Execute PowerShell command. Patterns:\n- Read: Get-Content/Select-String/Get-ChildItem\n- Write: Set-Content/Add-Content/Out-File\n- Subagent: node agent_v0.js \"task description\"",
        "parameters": {
          "type": "object",
          "properties": {
            "command": {
              "type": "string",
              "description": "The PowerShell command to execute"
            }
          },
          "required": [
            "command"
          ],
          "additionalProperties": false
        },
        "strict": true
      }
    }
  ]
}

// 响应
{
  "id": "gen-1772421831-bSJQBHWMCJZOOw5qjGeT",
  "provider": "Minimax",
  "model": "minimax/minimax-m2.5",
  "object": "chat.completion",
  "created": 1772421831,
  "choices": [
    {
      "logprobs": null,
      "finish_reason": "tool_calls",
      "native_finish_reason": "tool_calls",
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "我来同时调用两个Subagent来执行这两个任务。\n",
        "refusal": null,
        "reasoning": "用户要求我同时调用两个Subagent分别执行:\n1. src目录下有多少个js文件\n2. print目录下有多少个文件\n\n然后把两个数相加的等式保存到results.txt\n\n我需要使用shell工具来创建两个子代理任务。让我先执行这两个任务。\n\n由于用户要求\"同时调用\",我应该同时发起两个请求。让我使用node agent_v0.js来创建子代理。\n\n不过,我需要先了解一下目录结构,看看src和print目录是否存在。让我先检查一下。",
        "tool_calls": [
          {
            "type": "function",
            "index": 0,
            "id": "call_function_t2db1axss0n6_1",
            "function": {
              "name": "shell",
              "arguments": "{\"command\": \"node agent_v0.js \\\"统计src目录下有多少个js文件,只返回数字\\\"\"}"
            }
          },
          {
            "type": "function",
            "index": 1,
            "id": "call_function_t2db1axss0n6_2",
            "function": {
              "name": "shell",
              "arguments": "{\"command\": \"node agent_v0.js \\\"统计print目录下有多少个文件,只返回数字\\\"\"}"
            }
          }
        ],
        "reasoning_details": [
          {
            "format": null,
            "index": 0,
            "type": "reasoning.text",
            "text": "用户要求我同时调用两个Subagent分别执行:\n1. src目录下有多少个js文件\n2. print目录下有多少个文件\n\n然后把两个数相加的等式保存到results.txt\n\n我需要使用shell工具来创建两个子代理任务。让我先执行这两个任务。\n\n由于用户要求\"同时调用\",我应该同时发起两个请求。让我使用node agent_v0.js来创建子代理。\n\n不过,我需要先了解一下目录结构,看看src和print目录是否存在。让我先检查一下。"
          }
        ]
      }
    }
  ],
  "usage": {
    "prompt_tokens": 295,
    "completion_tokens": 189,
    "total_tokens": 484,
    "cost": 0,
    "is_byok": true,
    "prompt_tokens_details": { "cached_tokens": 0, "audio_tokens": 0 },
    "cost_details": {
      "upstream_inference_cost": 0.0006306,
      "upstream_inference_prompt_cost": 0.000177,
      "upstream_inference_completions_cost": 0.0004536
    },
    "completion_tokens_details": { "reasoning_tokens": 107, "audio_tokens": 0 }
  },
  "cost": "0"
}


// 请求
{
  "model": "xxx",
  "messages": [
    {
      "role": "system",
      "content": "Windows CLI agent at D:\\Learn\\AgentDemo. You are running on Windows using PowerShell. Use PowerShell syntax. Spawn subagent for complex tasks."
    },
    {
      "role": "user",
      "content": "统计src目录下有多少个js文件,只返回数字"
    }
  ],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "shell",
        "description": "Execute PowerShell command. Patterns:\n- Read: Get-Content/Select-String/Get-ChildItem\n- Write: Set-Content/Add-Content/Out-File\n- Subagent: node agent_v0.js \"task description\"",
        "parameters": {
          "type": "object",
          "properties": {
            "command": {
              "type": "string",
              "description": "The PowerShell command to execute"
            }
          },
          "required": [
            "command"
          ],
          "additionalProperties": false
        },
        "strict": true
      }
    }
  ]
}

// 响应
{
  "id": "gen-1772421835-FXzsLN2e0lonTn4lEapb",
  "provider": "Minimax",
  "model": "minimax/minimax-m2.5",
  "object": "chat.completion",
  "created": 1772421835,
  "choices": [
    {
      "logprobs": null,
      "finish_reason": "tool_calls",
      "native_finish_reason": "tool_calls",
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "",
        "refusal": null,
        "reasoning": "用户想要统计 src 目录下有多少个 .js 文件。我需要使用 PowerShell 命令来递归搜索 src 目录下的所有 .js 文件并计数。",
        "tool_calls": [
          {
            "type": "function",
            "index": 0,
            "id": "call_function_ae4hu22vq5xa_1",
            "function": {
              "name": "shell",
              "arguments": "{\"command\": \"(Get-ChildItem -Path src -Recurse -Filter *.js -File).Count\"}"
            }
          }
        ],
        "reasoning_details": [
          {
            "format": null,
            "index": 0,
            "type": "reasoning.text",
            "text": "用户想要统计 src 目录下有多少个 .js 文件。我需要使用 PowerShell 命令来递归搜索 src 目录下的所有 .js 文件并计数。"
          }
        ]
      }
    }
  ],
  "usage": {
    "prompt_tokens": 273,
    "completion_tokens": 74,
    "total_tokens": 347,
    "cost": 0,
    "is_byok": true,
    "prompt_tokens_details": { "cached_tokens": 0, "audio_tokens": 0 },
    "cost_details": {
      "upstream_inference_cost": 0.0003414,
      "upstream_inference_prompt_cost": 0.0001638,
      "upstream_inference_completions_cost": 0.0001776
    },
    "completion_tokens_details": { "reasoning_tokens": 34, "audio_tokens": 0 }
  },
  "cost": "0"
}

// 请求
{
  "model": "xxx",
  "messages": [
    {
      "role": "system",
      "content": "Windows CLI agent at D:\\Learn\\AgentDemo. You are running on Windows using PowerShell. Use PowerShell syntax. Spawn subagent for complex tasks."
    },
    {
      "role": "user",
      "content": "统计src目录下有多少个js文件,只返回数字"
    },
    {
      "role": "assistant",
      "content": "",
      "refusal": null,
      "reasoning": "用户想要统计 src 目录下有多少个 .js 文件。我需要使用 PowerShell 命令来递归搜索 src 目录下的所有 .js 文件并计数。",
      "tool_calls": [
        {
          "type": "function",
          "index": 0,
          "id": "call_function_ae4hu22vq5xa_1",
          "function": {
            "name": "shell",
            "arguments": "{\"command\": \"(Get-ChildItem -Path src -Recurse -Filter *.js -File).Count\"}"
          }
        }
      ],
      "reasoning_details": [
        {
          "format": null,
          "index": 0,
          "type": "reasoning.text",
          "text": "用户想要统计 src 目录下有多少个 .js 文件。我需要使用 PowerShell 命令来递归搜索 src 目录下的所有 .js 文件并计数。"
        }
      ]
    },
    {
      "role": "tool",
      "tool_call_id": "call_function_ae4hu22vq5xa_1",
      "content": "7\r\n"
    }
  ],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "shell",
        "description": "Execute PowerShell command. Patterns:\n- Read: Get-Content/Select-String/Get-ChildItem\n- Write: Set-Content/Add-Content/Out-File\n- Subagent: node agent_v0.js \"task description\"",
        "parameters": {
          "type": "object",
          "properties": {
            "command": {
              "type": "string",
              "description": "The PowerShell command to execute"
            }
          },
          "required": [
            "command"
          ],
          "additionalProperties": false
        },
        "strict": true
      }
    }
  ]
}

// 响应
{
  "id": "gen-1772421838-qBgMO5p08x6PiT9HkosB",
  "provider": "Minimax",
  "model": "minimax/minimax-m2.5",
  "object": "chat.completion",
  "created": 1772421838,
  "choices": [
    {
      "logprobs": null,
      "finish_reason": "stop",
      "native_finish_reason": "stop",
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "7",
        "refusal": null,
        "reasoning": "命令执行成功,返回了数字 7,表示 src 目录下有 7 个 js 文件。",
        "reasoning_details": [
          {
            "format": null,
            "index": 0,
            "type": "reasoning.text",
            "text": "命令执行成功,返回了数字 7,表示 src 目录下有 7 个 js 文件。"
          }
        ]
      }
    }
  ],
  "usage": {
    "prompt_tokens": 365,
    "completion_tokens": 24,
    "total_tokens": 389,
    "cost": 0,
    "is_byok": true,
    "prompt_tokens_details": { "cached_tokens": 0, "audio_tokens": 0 },
    "cost_details": {
      "upstream_inference_cost": 0.0002766,
      "upstream_inference_prompt_cost": 0.000219,
      "upstream_inference_completions_cost": 0.0000576
    },
    "completion_tokens_details": { "reasoning_tokens": 22, "audio_tokens": 0 }
  },
  "cost": "0"
}

// 省略一些

// 请求
{
  "model": "xxx",
  "messages": [
    {
      "role": "system",
      "content": "Windows CLI agent at D:\\Learn\\AgentDemo. You are running on Windows using PowerShell. Use PowerShell syntax. Spawn subagent for complex tasks."
    },
    {
      "role": "user",
      "content": "同时调用两个Subagent分别执行:src目录下有多少个js文件、print目录下有多少个文件,最后把两个数相加的等式保存到results.txt"
    },
    {
      "role": "assistant",
      "content": "我来同时调用两个Subagent来执行这两个任务。\n",
      "refusal": null,
      "reasoning": "用户要求我同时调用两个Subagent分别执行:\n1. src目录下有多少个js文件\n2. print目录下有多少个文件\n\n然后把两个数相加的等式保存到results.txt\n\n我需要使用shell工
具来创建两个子代理任务。让我先执行这两个任务。\n\n由于用户要求\"同时调用\",我应该同时发起两个请求。让我使用node agent_v0.js来创建子代理。\n\n不过,我需要先了解一下目录结构,看看src和print目录是否存在。让我先检查一下。",
      "tool_calls": [
        {
          "type": "function",
          "index": 0,
          "id": "call_function_t2db1axss0n6_1",
          "function": {
            "name": "shell",
            "arguments": "{\"command\": \"node agent_v0.js \\\"统计src目录下有多少个js文件,只返回数字\\\"\"}"
          }
        },
        {
          "type": "function",
          "index": 1,
          "id": "call_function_t2db1axss0n6_2",
          "function": {
            "name": "shell",
            "arguments": "{\"command\": \"node agent_v0.js \\\"统计print目录下有多少个文件,只返回数字\\\"\"}"
          }
        }
      ],
      "reasoning_details": [
        {
          "format": null,
          "index": 0,
          "type": "reasoning.text",
          "text": "用户要求我同时调用两个Subagent分别执行:\n1. src目录下有多少个js文件\n2. print目录下有多少个文件\n\n然后把两个数相加的等式保存到results.txt\n\n我需要使用shell工 
具来创建两个子代理任务。让我先执行这两个任务。\n\n由于用户要求\"同时调用\",我应该同时发起两个请求。让我使用node agent_v0.js来创建子代理。\n\n不过,我需要先了解一下目录结构,看看src和print目录是否存在。让我先检查一下。"
        }
      ]
    },
    {
      "role": "tool",
      "tool_call_id": "call_function_t2db1axss0n6_1",
      "content": "7\n"
    },
    {
      "role": "tool",
      "tool_call_id": "call_function_t2db1axss0n6_2",
      "content": "3\n"
    }
  ],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "shell",
        "description": "Execute PowerShell command. Patterns:\n- Read: Get-Content/Select-String/Get-ChildItem\n- Write: Set-Content/Add-Content/Out-File\n- Subagent: node agent_v0.js \"task description\"",
        "parameters": {
          "type": "object",
          "properties": {
            "command": {
              "type": "string",
              "description": "The PowerShell command to execute"
            }
          },
          "required": [
            "command"
          ],
          "additionalProperties": false
        },
        "strict": true
      }
    }
  ]
}

// 响应
{
  "id": "gen-1772421847-e7e89Vw9uIvk7QzBlITG",
  "provider": "Minimax",
  "model": "minimax/minimax-m2.5",
  "object": "chat.completion",
  "created": 1772421847,
  "choices": [
    {
      "logprobs": null,
      "finish_reason": "tool_calls",
      "native_finish_reason": "tool_calls",
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "现在把两个数相加的等式保存到results.txt:\n",
        "refusal": null,
        "reasoning": "两个Subagent分别返回了:\n- src目录下有7个js文件\n- print目录下有3个文件\n\n现在我需要把这两个数相加的等式保存到results.txt文件中。\n\n7 + 3 = 10\n\n我需要把这个等式写入results.txt文件。",
        "tool_calls": [
          {
            "type": "function",
            "index": 0,
            "id": "call_function_21x1cdtkfgf2_1",
            "function": {
              "name": "shell",
              "arguments": "{\"command\": \"Set-Content -Path results.txt -Value \\\"7 + 3 = 10\\\"\"}"
            }
          }
        ],
        "reasoning_details": [
          {
            "format": null,
            "index": 0,
            "type": "reasoning.text",
            "text": "两个Subagent分别返回了:\n- src目录下有7个js文件\n- print目录下有3个文件\n\n现在我需要把这两个数相加的等式保存到results.txt文件中。\n\n7 + 3 = 10\n\n我需要把这个等式写入results.txt文件。"
          }
        ]
      }
    }
  ],
  "usage": {
    "prompt_tokens": 503,
    "completion_tokens": 113,
    "total_tokens": 616,
    "cost": 0,
    "is_byok": true,
    "prompt_tokens_details": { "cached_tokens": 0, "audio_tokens": 0 },
    "cost_details": {
      "upstream_inference_cost": 0.000573,
      "upstream_inference_prompt_cost": 0.0003018,
      "upstream_inference_completions_cost": 0.0002712
    },
    "completion_tokens_details": { "reasoning_tokens": 61, "audio_tokens": 0 }
  },
  "cost": "0"
}


// 请求
{
  "model": "xxx",
  "messages": [
    {
      "role": "system",
      "content": "Windows CLI agent at D:\\Learn\\AgentDemo. You are running on Windows using PowerShell. Use PowerShell syntax. Spawn subagent for complex tasks."
    },
    {
      "role": "user",
      "content": "同时调用两个Subagent分别执行:src目录下有多少个js文件、print目录下有多少个文件,最后把两个数相加的等式保存到results.txt"
    },
    {
      "role": "assistant",
      "content": "我来同时调用两个Subagent来执行这两个任务。\n",
      "refusal": null,
      "reasoning": "用户要求我同时调用两个Subagent分别执行:\n1. src目录下有多少个js文件\n2. print目录下有多少个文件\n\n然后把两个数相加的等式保存到results.txt\n\n我需要使用shell工
具来创建两个子代理任务。让我先执行这两个任务。\n\n由于用户要求\"同时调用\",我应该同时发起两个请求。让我使用node agent_v0.js来创建子代理。\n\n不过,我需要先了解一下目录结构,看看src和print目录是否存在。让我先检查一下。",
      "tool_calls": [
        {
          "type": "function",
          "index": 0,
          "id": "call_function_t2db1axss0n6_1",
          "function": {
            "name": "shell",
            "arguments": "{\"command\": \"node agent_v0.js \\\"统计src目录下有多少个js文件,只返回数字\\\"\"}"
          }
        },
        {
          "type": "function",
          "index": 1,
          "id": "call_function_t2db1axss0n6_2",
          "function": {
            "name": "shell",
            "arguments": "{\"command\": \"node agent_v0.js \\\"统计print目录下有多少个文件,只返回数字\\\"\"}"
          }
        }
      ],
      "reasoning_details": [
        {
          "format": null,
          "index": 0,
          "type": "reasoning.text",
          "text": "用户要求我同时调用两个Subagent分别执行:\n1. src目录下有多少个js文件\n2. print目录下有多少个文件\n\n然后把两个数相加的等式保存到results.txt\n\n我需要使用shell工 
具来创建两个子代理任务。让我先执行这两个任务。\n\n由于用户要求\"同时调用\",我应该同时发起两个请求。让我使用node agent_v0.js来创建子代理。\n\n不过,我需要先了解一下目录结构,看看src和print目录是否存在。让我先检查一下。"
        }
      ]
    },
    {
      "role": "tool",
      "tool_call_id": "call_function_t2db1axss0n6_1",
      "content": "7\n"
    },
    {
      "role": "tool",
      "tool_call_id": "call_function_t2db1axss0n6_2",
      "content": "3\n"
    },
    {
      "role": "assistant",
      "content": "现在把两个数相加的等式保存到results.txt:\n",
      "refusal": null,
      "reasoning": "两个Subagent分别返回了:\n- src目录下有7个js文件\n- print目录下有3个文件\n\n现在我需要把这两个数相加的等式保存到results.txt文件中。\n\n7 + 3 = 10\n\n我需要把这 
个等式写入results.txt文件。",
      "tool_calls": [
        {
          "type": "function",
          "index": 0,
          "id": "call_function_21x1cdtkfgf2_1",
          "function": {
            "name": "shell",
            "arguments": "{\"command\": \"Set-Content -Path results.txt -Value \\\"7 + 3 = 10\\\"\"}"
          }
        }
      ],
      "reasoning_details": [
        {
          "format": null,
          "index": 0,
          "type": "reasoning.text",
          "text": "两个Subagent分别返回了:\n- src目录下有7个js文件\n- print目录下有3个文件\n\n现在我需要把这两个数相加的等式保存到results.txt文件中。\n\n7 + 3 = 10\n\n我需要把这个
等式写入results.txt文件。"
        }
      ]
    },
    {
      "role": "tool",
      "tool_call_id": "call_function_21x1cdtkfgf2_1",
      "content": ""
    }
  ],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "shell",
        "description": "Execute PowerShell command. Patterns:\n- Read: Get-Content/Select-String/Get-ChildItem\n- Write: Set-Content/Add-Content/Out-File\n- Subagent: node agent_v0.js \"task description\"",
        "parameters": {
          "type": "object",
          "properties": {
            "command": {
              "type": "string",
              "description": "The PowerShell command to execute"
            }
          },
          "required": [
            "command"
          ],
          "additionalProperties": false
        },
        "strict": true
      }
    }
  ]
}

// 响应
{
  "id": "gen-1772421850-LzLCKKOlUuqRuHIJFr3x",
  "provider": "Minimax",
  "model": "minimax/minimax-m2.5",
  "object": "chat.completion",
  "created": 1772421850,
  "choices": [
    {
      "logprobs": null,
      "finish_reason": "tool_calls",
      "native_finish_reason": "tool_calls",
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "",
        "refusal": null,
        "reasoning": "完成了。让我验证一下文件是否正确创建。",
        "tool_calls": [
          {
            "type": "function",
            "index": 0,
            "id": "call_function_9m892yserzta_1",
            "function": {
              "name": "shell",
              "arguments": "{\"command\": \"Get-Content results.txt\"}"
            }
          }
        ],
        "reasoning_details": [
          {
            "format": null,
            "index": 0,
            "type": "reasoning.text",
            "text": "完成了。让我验证一下文件是否正确创建。"
          }
        ]
      }
    }
  ],
  "usage": {
    "prompt_tokens": 626,
    "completion_tokens": 40,
    "total_tokens": 666,
    "cost": 0,
    "is_byok": true,
    "prompt_tokens_details": { "cached_tokens": 0, "audio_tokens": 0 },
    "cost_details": {
      "upstream_inference_cost": 0.0004716,
      "upstream_inference_prompt_cost": 0.0003756,
      "upstream_inference_completions_cost": 0.000096
    },
    "completion_tokens_details": { "reasoning_tokens": 13, "audio_tokens": 0 }
  },
  "cost": "0"
}

// 请求
{
  "model": "xxx",
  "messages": [
    {
      "role": "system",
      "content": "Windows CLI agent at D:\\Learn\\AgentDemo. You are running on Windows using PowerShell. Use PowerShell syntax. Spawn subagent for complex tasks."
    },
    {
      "role": "user",
      "content": "同时调用两个Subagent分别执行:src目录下有多少个js文件、print目录下有多少个文件,最后把两个数相加的等式保存到results.txt"
    },
    {
      "role": "assistant",
      "content": "我来同时调用两个Subagent来执行这两个任务。\n",
      "refusal": null,
      "reasoning": "用户要求我同时调用两个Subagent分别执行:\n1. src目录下有多少个js文件\n2. print目录下有多少个文件\n\n然后把两个数相加的等式保存到results.txt\n\n我需要使用shell工
具来创建两个子代理任务。让我先执行这两个任务。\n\n由于用户要求\"同时调用\",我应该同时发起两个请求。让我使用node agent_v0.js来创建子代理。\n\n不过,我需要先了解一下目录结构,看看src和print目录是否存在。让我先检查一下。",
      "tool_calls": [
        {
          "type": "function",
          "index": 0,
          "id": "call_function_t2db1axss0n6_1",
          "function": {
            "name": "shell",
            "arguments": "{\"command\": \"node agent_v0.js \\\"统计src目录下有多少个js文件,只返回数字\\\"\"}"
          }
        },
        {
          "type": "function",
          "index": 1,
          "id": "call_function_t2db1axss0n6_2",
          "function": {
            "name": "shell",
            "arguments": "{\"command\": \"node agent_v0.js \\\"统计print目录下有多少个文件,只返回数字\\\"\"}"
          }
        }
      ],
      "reasoning_details": [
        {
          "format": null,
          "index": 0,
          "type": "reasoning.text",
          "text": "用户要求我同时调用两个Subagent分别执行:\n1. src目录下有多少个js文件\n2. print目录下有多少个文件\n\n然后把两个数相加的等式保存到results.txt\n\n我需要使用shell工 
具来创建两个子代理任务。让我先执行这两个任务。\n\n由于用户要求\"同时调用\",我应该同时发起两个请求。让我使用node agent_v0.js来创建子代理。\n\n不过,我需要先了解一下目录结构,看看src和print目录是否存在。让我先检查一下。"
        }
      ]
    },
    {
      "role": "tool",
      "tool_call_id": "call_function_t2db1axss0n6_1",
      "content": "7\n"
    },
    {
      "role": "tool",
      "tool_call_id": "call_function_t2db1axss0n6_2",
      "content": "3\n"
    },
    {
      "role": "assistant",
      "content": "现在把两个数相加的等式保存到results.txt:\n",
      "refusal": null,
      "reasoning": "两个Subagent分别返回了:\n- src目录下有7个js文件\n- print目录下有3个文件\n\n现在我需要把这两个数相加的等式保存到results.txt文件中。\n\n7 + 3 = 10\n\n我需要把这 
个等式写入results.txt文件。",
      "tool_calls": [
        {
          "type": "function",
          "index": 0,
          "id": "call_function_21x1cdtkfgf2_1",
          "function": {
            "name": "shell",
            "arguments": "{\"command\": \"Set-Content -Path results.txt -Value \\\"7 + 3 = 10\\\"\"}"
          }
        }
      ],
      "reasoning_details": [
        {
          "format": null,
          "index": 0,
          "type": "reasoning.text",
          "text": "两个Subagent分别返回了:\n- src目录下有7个js文件\n- print目录下有3个文件\n\n现在我需要把这两个数相加的等式保存到results.txt文件中。\n\n7 + 3 = 10\n\n我需要把这个
等式写入results.txt文件。"
        }
      ]
    },
    {
      "role": "tool",
      "tool_call_id": "call_function_21x1cdtkfgf2_1",
      "content": ""
    },
    {
      "role": "assistant",
      "content": "",
      "refusal": null,
      "reasoning": "完成了。让我验证一下文件是否正确创建。",
      "tool_calls": [
        {
          "type": "function",
          "index": 0,
          "id": "call_function_9m892yserzta_1",
          "function": {
            "name": "shell",
            "arguments": "{\"command\": \"Get-Content results.txt\"}"
          }
        }
      ],
      "reasoning_details": [
        {
          "format": null,
          "index": 0,
          "type": "reasoning.text",
          "text": "完成了。让我验证一下文件是否正确创建。"
        }
      ]
    },
    {
      "role": "tool",
      "tool_call_id": "call_function_9m892yserzta_1",
      "content": "7 + 3 = 10\r\n"
    }
  ],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "shell",
        "description": "Execute PowerShell command. Patterns:\n- Read: Get-Content/Select-String/Get-ChildItem\n- Write: Set-Content/Add-Content/Out-File\n- Subagent: node agent_v0.js \"task description\"",
        "parameters": {
          "type": "object",
          "properties": {
            "command": {
              "type": "string",
              "description": "The PowerShell command to execute"
            }
          },
          "required": [
            "command"
          ],
          "additionalProperties": false
        },
        "strict": true
      }
    }
  ]
}

// 响应
{
  "id": "gen-1772421852-ZzYzaHvmxIfIwrFqt9Yc",
  "provider": "Minimax",
  "model": "minimax/minimax-m2.5",
  "object": "chat.completion",
  "created": 1772421852,
  "choices": [
    {
      "logprobs": null,
      "finish_reason": "stop",
      "native_finish_reason": "stop",
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "完成!结果如下:\n\n- **src目录**:7个js文件\n- **print目录**:3个文件\n- **相加结果**:7 + 3 = 10\n\n已将等式 `7 + 3 = 10` 保存到 `results.txt` 文件中。",
        "refusal": null,
        "reasoning": "任务完成了。我成功完成了以下操作:\n1. 调用第一个Subagent统计src目录下的js文件数量:7个\n2. 调用第二个Subagent统计print目录下的文件数量:3个\n3. 将等式\"7 + 3 = 10\"保存到results.txt文件中",
        "reasoning_details": [
          {
            "format": null,
            "index": 0,
            "type": "reasoning.text",
            "text": "任务完成了。我成功完成了以下操作:\n1. 调用第一个Subagent统计src目录下的js文件数量:7个\n2. 调用第二个Subagent统计print目录下的文件数量:3个\n3. 将等式\"7 + 3 = 10\"保存到results.txt文件中"
          }
        ]
      }
    }
  ],
  "usage": {
    "prompt_tokens": 690,
    "completion_tokens": 123,
    "total_tokens": 813,
    "cost": 0,
    "is_byok": true,
    "prompt_tokens_details": { "cached_tokens": 0, "audio_tokens": 0 },
    "cost_details": {
      "upstream_inference_cost": 0.0003546,
      "upstream_inference_prompt_cost": 0.000207,
      "upstream_inference_completions_cost": 0.0001476
    },
    "completion_tokens_details": { "reasoning_tokens": 64, "audio_tokens": 0 }
  },
  "cost": "0"
}

Langchain.js

借助 Langchain 实现,工具调用循环更健壮。

#!/usr/bin/env node
import { spawnSync } from 'node:child_process'
import readline from 'node:readline'
import process from 'node:process'
import fs from 'node:fs'
import { createAgent, tool } from 'langchain'
import { MemorySaver } from '@langchain/langgraph'
import { ChatOpenAI } from '@langchain/openai'
import * as z from 'zod'

// 对于基于 STDIO 的服务器:永远不要向标准输出(stdout)和标准错误(stderr)写入。
// ❌ Bad (STDIO)
// console.log("xxx");
// console.error("xxx");

const model = new ChatOpenAI({
  model: 'xxx',
  apiKey: 'xxx',
  streaming: true,
  configuration: {
    baseURL: 'http://127.0.0.1:3003'
  }
})

const checkpointer = new MemorySaver()

const isWin32 = process.platform === 'win32'

const SHELL_DESCRIPTION = isWin32
  ? `Execute PowerShell command. Patterns:
- Read: Get-Content/Select-String/Get-ChildItem
- Write: Set-Content/Add-Content/Out-File
- Subagent: node agent_v0.js "task description"`
  : `Execute shell command. Patterns:
- Read: cat/grep/find/ls
- Write: echo '...' > file
- Subagent: node agent_v0.js "task description"`

const shell = tool(
  async ({ command }) => {
    // 执行 shell 命令
    const child = spawnSync(command, {
      shell: isWin32 ? 'powershell.exe' : true,
      encoding: 'utf-8',
      timeout: 30000 // 30秒超时
    })
    const output = (child.stdout || '') + (child.stderr || '')
    return output
  },
  {
    name: 'shell',
    description: SHELL_DESCRIPTION,
    schema: z.object({
      command: z
        .string()
        .describe(
          isWin32
            ? 'The PowerShell command to execute'
            : 'The shell command to execute'
        )
    })
  }
)

const SYSTEM = isWin32
  ? `Windows CLI agent at ${process.cwd()}. You are running on Windows using PowerShell. Use PowerShell syntax. Spawn subagent for complex tasks.`
  : `Linux CLI agent at ${process.cwd()}. You are running on Linux using bash. Use POSIX syntax. Spawn subagent for complex tasks.`

const logger = fs.createWriteStream('debug.log', {
  flags: 'a',
  encoding: 'utf-8'
})

const agent = createAgent({
  model,
  systemPrompt: SYSTEM,
  checkpointer,
  tools: [shell]
})

async function chat(prompt) {
  const stream = await agent.stream(
    { messages: [{ role: 'user', content: prompt }] },
    {
      streamMode: 'values',
      configurable: { thread_id: '1' }, // `thread_id` is a unique identifier for a given conversation.
      context: { user_id: '1' }
    }
  )
  let result = ''
  for await (const chunk of stream) {
    // Each chunk contains the full state at that point
    const latestMessage = chunk.messages.at(-1)
    logger.write(`latestMessage: ${JSON.stringify(latestMessage, null, 2)}\n`)
    result = latestMessage?.content || ''
  }
  return result
}

async function main() {
  // 处理命令行参数 (process.argv[0] 是 node, [1] 是脚本路径, [2] 开始是参数)
  const args = process.argv.slice(2)

  if (args.length > 0) {
    // 子代理模式 (命令行参数直接运行)
    const response = await chat(args[0])
    console.log(response)
  } else {
    // 交互模式 (REPL)
    const history = []
    const rl = readline.createInterface({
      input: process.stdin,
      output: process.stdout
    })

    const ask = () => {
      rl.question('>> ', async q => {
        if (q === 'q' || q === '') {
          rl.close()
          return
        }
        try {
          const response = await chat(q, history)
          console.log(response)
        } catch (error) {
          console.error('Error:', error.message)
        }
        ask() // 递归调用以保持对话循环
      })
    }

    ask()
  }
}

main()

image.png

日志输出:

latestMessage: {
  "lc": 1,
  "type": "constructor",
  "id": [
    "langchain_core",
    "messages",
    "HumanMessage"
  ],
  "kwargs": {
    "content": "打开计算器",
    "additional_kwargs": {},
    "response_metadata": {},
    "id": "4f7a6a51-0b4b-4571-b617-01de59f15e5d"
  }
}
latestMessage: {
  "lc": 1,
  "type": "constructor",
  "id": [
    "langchain_core",
    "messages",
    "AIMessageChunk"
  ],
  "kwargs": {
    "content": "",
    "additional_kwargs": {
      "tool_calls": [
        {
          "id": "call_function_y7qpqjlxejh4_1",
          "type": "function",
          "function": {
            "name": "shell",
            "arguments": "{\"command\": \"calc\"}"
          },
          "index": 0
        }
      ]
    },
    "response_metadata": {
      "estimatedTokenUsage": {
        "promptTokens": 66,
        "completionTokens": 0,
        "totalTokens": 66
      },
      "prompt": 0,
      "completion": 0,
      "finish_reason": "tool_calls",
      "model_name": "minimax/minimax-m2.5",
      "model_provider": "openai",
      "usage": {
        "prompt_tokens": 285,
        "completion_tokens": 45,
        "total_tokens": 330,
        "cost": 0,
        "is_byok": true,
        "prompt_tokens_details": {
          "cached_tokens": 0,
          "audio_tokens": 0
        },
        "cost_details": {
          "upstream_inference_cost": 0.0001395,
          "upstream_inference_prompt_cost": 0.0000855,
          "upstream_inference_completions_cost": 0.000054
        },
        "completion_tokens_details": {
          "reasoning_tokens": 22,
          "audio_tokens": 0
        }
      }
    },
    "tool_call_chunks": [
      {
        "name": "shell",
        "args": "{\"command\": \"calc\"}",
        "id": "call_function_y7qpqjlxejh4_1",
        "index": 0,
        "type": "tool_call_chunk"
      }
    ],
    "id": "gen-1772444786-DgqEXMkOwToJZrrBhQrv",
    "usage_metadata": {
      "input_tokens": 285,
      "output_tokens": 45,
      "total_tokens": 330,
      "input_token_details": {
        "audio": 0,
        "cache_read": 0
      },
      "output_token_details": {
        "audio": 0,
        "reasoning": 22
      }
    },
    "tool_calls": [
      {
        "name": "shell",
        "args": {
          "command": "calc"
        },
        "id": "call_function_y7qpqjlxejh4_1",
        "type": "tool_call"
      }
    ],
    "invalid_tool_calls": [],
    "name": "model"
  }
}
latestMessage: {
  "lc": 1,
  "type": "constructor",
  "id": [
    "langchain_core",
    "messages",
    "ToolMessage"
  ],
  "kwargs": {
    "status": "success",
    "content": "",
    "tool_call_id": "call_function_y7qpqjlxejh4_1",
    "name": "shell",
    "metadata": {},
    "additional_kwargs": {},
    "response_metadata": {},
    "id": "6b855721-0e36-4211-88f3-7bdcea7ad120"
  }
}
latestMessage: {
  "lc": 1,
  "type": "constructor",
  "id": [
    "langchain_core",
    "messages",
    "AIMessageChunk"
  ],
  "kwargs": {
    "content": "计算器已打开!🎉",
    "additional_kwargs": {},
    "response_metadata": {
      "estimatedTokenUsage": {
        "promptTokens": 79,
        "completionTokens": 21,
        "totalTokens": 100
      },
      "prompt": 0,
      "completion": 0,
      "finish_reason": "stop",
      "model_name": "minimax/minimax-m2.5",
      "model_provider": "openai",
      "usage": {
        "prompt_tokens": 317,
        "completion_tokens": 52,
        "total_tokens": 369,
        "cost": 0,
        "is_byok": true,
        "prompt_tokens_details": {
          "cached_tokens": 0,
          "audio_tokens": 0
        },
        "cost_details": {
          "upstream_inference_cost": 0.0001575,
          "upstream_inference_prompt_cost": 0.0000951,
          "upstream_inference_completions_cost": 0.0000624
        },
        "completion_tokens_details": {
          "reasoning_tokens": 44,
          "audio_tokens": 0
        }
      }
    },
    "tool_call_chunks": [],
    "id": "gen-1772444804-uPL2kjMLdAiNrtvwUTcj",
    "usage_metadata": {
      "input_tokens": 317,
      "output_tokens": 52,
      "total_tokens": 369,
      "input_token_details": {
        "audio": 0,
        "cache_read": 0
      },
      "output_token_details": {
        "audio": 0,
        "reasoning": 44
      }
    },
    "tool_calls": [],
    "invalid_tool_calls": [],
    "name": "model"
  }
}

接口调用:

// 请求
{
  "model": "xxx",
  "stream": true,
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "shell",
        "description": "Execute PowerShell command. Patterns:\n- Read: Get-Content/Select-String/Get-ChildItem\n- Write: Set-Content/Add-Content/Out-File\n- Subagent: node agent_v0.js \"task description\"",
        "parameters": {
          "$schema": "https://json-schema.org/draft/2020-12/schema",
          "type": "object",
          "properties": {
            "command": {
              "description": "The PowerShell command to execute",
              "type": "string"
            }
          },
          "required": [
            "command"
          ],
          "additionalProperties": false
        }
      }
    }
  ],
  "stream_options": {
    "include_usage": true
  },
  "messages": [
    {
      "role": "system",
      "content": [
        {
          "type": "text",
          "text": "Windows CLI agent at D:\\Learn\\AgentDemo. You are running on Windows using PowerShell. Use PowerShell syntax. Spawn subagent for complex tasks."
        }
      ]
    },
    {
      "role": "user",
      "content": "打开计算器"
    }
  ]
}

// 流式响应

data: {"id":"gen-1772444786-DgqEXMkOwToJZrrBhQrv","provider":"Minimax","model":"minimax/minimax-m2.5","object":"chat.completion.chunk","created":1772444786,"choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"用户想要","reasoning_details":[{"type":"reasoning.text","text":"用户想要","index":0,"format":null}]},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}

data: {"id":"gen-1772444786-DgqEXMkOwToJZrrBhQrv","provider":"Minimax","model":"minimax/minimax-m2.5","object":"chat.completion.chunk","created":1772444786,"choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"打开计算器。在Windows上,我可以使用PowerShell命令来启动计算器应用程序。","reasoning_details":[{"type":"reasoning.text","text":"打开计算器。在Windows上,我可以使用PowerShell命令来启动计算器应用程序。","index":0,"format":null}]},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}

data: {"id":"gen-1772444786-DgqEXMkOwToJZrrBhQrv","provider":"Minimax","model":"minimax/minimax-m2.5","object":"chat.completion.chunk","created":1772444786,"choices":[{"index":0,"delta":{"role":"assistant","content":null,"tool_calls":[{"id":"call_function_y7qpqjlxejh4_1","type":"function","function":{"name":"shell","arguments":"{\"command\": "},"index":0}]},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}

data: {"id":"gen-1772444786-DgqEXMkOwToJZrrBhQrv","provider":"Minimax","model":"minimax/minimax-m2.5","object":"chat.completion.chunk","created":1772444786,"choices":[{"index":0,"delta":{"role":"assistant","content":null,"tool_calls":[{"function":{"arguments":"\"calc\"}"},"index":0,"type":"function"}]},"finish_reason":"tool_calls","native_finish_reason":"tool_calls","logprobs":null}]}

data: {"id":"gen-1772444786-DgqEXMkOwToJZrrBhQrv","provider":"Minimax","model":"minimax/minimax-m2.5","object":"chat.completion.chunk","created":1772444786,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":285,"completion_tokens":45,"total_tokens":330,"cost":0,"is_byok":true,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"cost_details":{"upstream_inference_cost":0.0001395,"upstream_inference_prompt_cost":0.0000855,"upstream_inference_completions_cost":0.000054},"completion_tokens_details":{"reasoning_tokens":22,"audio_tokens":0}}}

data: [DONE]

data: {"choices":[],"cost":"0"}

// 请求
{
  "model": "xxx",
  "stream": true,
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "shell",
        "description": "Execute PowerShell command. Patterns:\n- Read: Get-Content/Select-String/Get-ChildItem\n- Write: Set-Content/Add-Content/Out-File\n- Subagent: node agent_v0.js \"task description\"",
        "parameters": {
          "$schema": "https://json-schema.org/draft/2020-12/schema",
          "type": "object",
          "properties": {
            "command": {
              "description": "The PowerShell command to execute",
              "type": "string"
            }
          },
          "required": [
            "command"
          ],
          "additionalProperties": false
        }
      }
    }
  ],
  "stream_options": {
    "include_usage": true
  },
  "messages": [
    {
      "role": "system",
      "content": [
        {
          "type": "text",
          "text": "Windows CLI agent at D:\\Learn\\AgentDemo. You are running on Windows using PowerShell. Use PowerShell syntax. Spawn subagent for complex tasks."
        }
      ]
    },
    {
      "role": "user",
      "content": "打开计算器"
    },
    {
      "role": "assistant",
      "content": "",
      "name": "model",
      "tool_calls": [
        {
          "id": "call_function_y7qpqjlxejh4_1",
          "type": "function",
          "function": {
            "name": "shell",
            "arguments": "{\"command\":\"calc\"}"
          }
        }
      ]
    },
    {
      "role": "tool",
      "content": "",
      "name": "shell",
      "tool_call_id": "call_function_y7qpqjlxejh4_1"
    }
  ]
}

// 流式响应

data: {"id":"gen-1772444804-uPL2kjMLdAiNrtvwUTcj","provider":"Minimax","model":"minimax/minimax-m2.5","object":"chat.completion.chunk","created":1772444804,"choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"The user","reasoning_details":[{"type":"reasoning.text","text":"The user","index":0,"format":null}]},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}

data: {"id":"gen-1772444804-uPL2kjMLdAiNrtvwUTcj","provider":"Minimax","model":"minimax/minimax-m2.5","object":"chat.completion.chunk","created":1772444804,"choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" wants me to open the calculator. I've already executed the calc command, which should open the Windows calculator application. The command executed successfully without any","reasoning_details":[{"type":"reasoning.text","text":" wants me to open the calculator. I've already executed the calc command, which should open the Windows calculator application. The command executed successfully without any","index":0,"format":null}]},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}

data: {"id":"gen-1772444804-uPL2kjMLdAiNrtvwUTcj","provider":"Minimax","model":"minimax/minimax-m2.5","object":"chat.completion.chunk","created":1772444804,"choices":[{"index":0,"delta":{"role":"assistant","content":"计算器已打开!🎉","reasoning":" error output, which means the calculator should have opened.","reasoning_details":[{"type":"reasoning.text","text":" error output, which means the calculator should have opened.","index":0,"format":null}]},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}]}

data: {"id":"gen-1772444804-uPL2kjMLdAiNrtvwUTcj","provider":"Minimax","model":"minimax/minimax-m2.5","object":"chat.completion.chunk","created":1772444804,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":317,"completion_tokens":52,"total_tokens":369,"cost":0,"is_byok":true,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"cost_details":{"upstream_inference_cost":0.0001575,"upstream_inference_prompt_cost":0.0000951,"upstream_inference_completions_cost":0.0000624},"completion_tokens_details":{"reasoning_tokens":44,"audio_tokens":0}}}

data: [DONE]

data: {"choices":[],"cost":"0"}