目录


项目背景与参考 Content-[00:00]

目前市面上存在多种编程辅助工具,如 OpenAI 的 Codex、Toppy 的 Cloud Code,以及国内的 Kimi、MiniMax 等编程终端。虽然功能相似,但实际使用体验差距较大,主要源于基座模型能力的差异以及代码系统设计的不同。

本系列教程参考了 GitHub 上的开源项目 Learn Claude Code(由 shanshail Lab 开发),该项目核心依赖仅为 Anthropic 的 SDK,其余部分均用纯 Python 编写,代码简洁且系统设计经过深思熟虑。


基础模型调用 (One Call) Content-[00:55]

最原始的模型调用流程是:用户输入提示词 -> 调用 Model API -> 模型返回结果。

环境配置

需要配置三个关键参数:

  1. BASE_URL:API 基础地址。
  2. API_KEY:认证密钥。
  3. MODEL_NAME:模型名称(如 qwen-coder-plus)。

代码实现

使用 SDK 初始化客户端并调用 client.messages.create

  • 指定 model 名称。
  • 构建 messages 列表,包含角色(user)和内容(提示词)。
  • 设置 max_tokens(如 200)。

响应结构解析

模型返回的 JSON 数据中需关注以下字段:

  • role: 通常为 assistant
  • stop_reason: 如 end_turn 表示对话结束。
  • content: 列表形式,包含 type(如 text)和具体的文本内容 text


单轮调用的局限性 Content-[03:00]

通过案例测试发现,直接询问模型“统计 flow.md 文件有多少字符”,模型无法直接访问本地文件或执行命令,只能返回文本建议(如建议使用 wc 命令)。

这是因为单次调用(One Call)模式下,模型仅能生成文本,没有后续动作能力,无法感知本地环境状态。


手动实现命令执行 Content-[04:15]

为了让模型具备执行能力,可以采用一种“粗暴”的方法:

  1. 提示词约束:要求模型只返回 Linux 命令。
  2. 命令提取:在代码中解析模型返回的文本,提取出命令字符串(去除 Markdown 格式标记)。
  3. 子进程执行:使用 Python 的 subprocess 模块执行提取出的命令。

流程

  • 获取模型返回的 text
  • 通过字符串分割(如按 \n 或 Markdown 代码块标记)提取命令。
  • 调用 subprocess.run(cmd, ...) 执行。
  • 捕获 stdout 输出结果。

虽然这种方法能让模型执行简单命令,但对于多步骤任务(如:找到最大文件 -> 统计函数数 -> 写入注释),手动提取和串联逻辑非常复杂,且模型无法根据上一步的执行结果动态调整下一步操作。


Agentic Loop 核心概念 Content-[07:47]

为了解决多步骤任务,引入了 Agentic Loop(代理循环)。模型需要在循环中不断进行 观察 (Observe) -> 决策 (Decide) -> 执行 (Execute),而不是一次性给出所有命令。

循环流程图

  1. Chat Prompt: 用户输入初始指令。
  2. Call Model API: 发送请求(包含历史消息和可用工具)。
  3. Check Response:
    • 如果是文本 (text):直接返回给用户,结束循环。
    • 如果是工具调用 (tool_use):提取工具参数。
  4. Execute Tool: 本地执行工具(如运行 Bash 命令)。
  5. Append Result: 将执行结果作为新的消息(tool_result)加入历史记录。
  6. Loop: 再次调用 Model API,直到模型认为任务完成(stop_reasonend_turn)。


工具调用 (Tool Use) 规范 Content-[09:50]

为了让模型知道可以调用哪些工具,需要在 API 请求的 tools 参数中定义工具规范。

Bash Tool 定义示例

tools = [{
    "name": "bash",
    "description": "Run a bash command in the terminal.",
    "input_schema": {
        "type": "object",
        "properties": {
            "command": {"type": "string", "description": "The bash command to execute."}
        },
        "required": ["command"]
    }
}]
  • name: 工具名称。
  • description: 工具功能描述,指导模型何时使用。
  • input_schema: 定义调用工具时所需的参数格式(JSON Schema)。


系统提示词 (System Prompt) Content-[10:50]

除了工具定义,还需要通过 system 参数设定系统提示词,明确 Agent 的角色和行为准则:

  • 角色定义:你是一个 CLI Agent,使用 Bash 命令解决问题。
  • 规则
    • 优先使用提供的工具。
    • 在执行破坏性操作前需确认。
    • 保持上下文清晰,避免污染对话。
    • 子进程运行在隔离环境中,仅返回最终摘要。


完整 Agent 循环实现 Content-[12:00]

核心代码逻辑

  1. 初始化历史history = [{"role": "user", "content": prompt}]
  2. While True 循环
    • 调用 API:传入 messages=history, tools=tools, system=SYSTEM_PROMPT
    • 保存响应:将模型的输出(assistant message)追加到 history
    • 判断结束:检查 response.stop_reason。如果是 end_turn,则退出循环。
    • 处理工具调用
      • 遍历 response.content,查找 type == "tool_use" 的块。
      • 提取 command 参数。
      • 使用 subprocess 执行命令,获取输出 output
      • 构建 tool_result 消息块(包含 tool_use_id 和执行结果 content)。
      • tool_resultuser 角色追加到 history,供下一轮模型参考。

关键点

  • 消息管理:必须将每一轮的交互(用户提问、模型思考、工具调用、工具结果)都保存在 history 中,否则模型会丢失上下文。
  • Tool Result 格式:返回给模型的工具结果需遵循特定格式(type: "tool_result", tool_use_id, content),以便模型理解这是对上一步工具调用的反馈。


测试与验证 Content-[19:25]

案例 1:统计文件字符数

  • 指令:“统计 flow.md 有多少个字符”。
  • 过程
    1. 模型调用 bash 工具,命令 wc -c < flow.md
    2. 系统执行命令,返回结果 1093
    3. 模型接收结果,整理回复:“flow.md 文件包含 1093 个字符”。
  • 结果:成功自动执行并反馈。

案例 2:统计 Python 文件数量

  • 指令:“统计当前目录下有几个 python 文件”。
  • 过程
    1. 模型调用 bash 工具,命令 find . -name "*.py" | wc -l
    2. 系统执行返回 6
    3. 模型回复:“当前目录有 6 个 python 文件”。
  • 结果:验证了 Agent 具备多步思考和执行能力。


AI 总结

本视频详细演示了如何从零开始构建一个基于 LLM 的 Bash Agent。核心在于从简单的“单次问答”进化为具备 Agentic Loop 的智能体。通过定义 Tool Use 规范(特别是 Bash 工具)和维护完整的 Message History,模型能够自主决定何时调用命令行工具,并根据执行结果进行下一步决策。这种架构是构建类似 Claude Code 等高级编程助手的基础,实现了从“被动回答”到“主动执行”的跨越。