半年前我决定从零开始打造一款AI Agent CLI——一个能像Claude Code、Codex CLI、Gemini CLI那样在终端里读代码、执行命令、修改文件的工具。

最初我只写出了一个能演示核心循环运作的最小Demo,仅50行代码,就能在终端里和用户对话、按需调用工具读取文件。但这个Demo只能用来理解Agent的核心逻辑,要让它真正跑在生产环境中,还需要搭建一整套外围工程框架:上下文压缩、权限模型、流式输出、错误恢复等等。本文就来拆解从「能跑的Demo」到「能托付任务的生产级工具」之间,到底需要补齐哪些核心能力。

一、先跑通50行最小AI Agent

直接上核心代码,这段TypeScript基于Vercel AI SDK和DeepSeek模型实现,已经具备对话和文件读取的基础能力:

// hello-agent.ts
import { deepseek } from '@ai-sdk/deepseek'
import { streamText, stepCountIs, tool } from 'ai'
import { z } from 'zod'
import fs from 'node:fs/promises'
import readline from 'node:readline'

const readFile = tool({
  description: '读取一个文本文件,返回完整内容',
  inputSchema: z.object({
    path: z.string().describe('要读取的文件路径'),
  }),
  execute: async ({ path }) => {
    return await fs.readFile(path, 'utf-8')
  },
})

async function main() {
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout })
  const ask = (q: string) => new Promise<string>((r) => rl.question(q, r))
  const messages: Array<{ role: 'user' | 'assistant'; content: any }> = []

  for (;;) {
    const input = (await ask('\n你: ')).trim()
    if (!input || input === 'exit') break
    messages.push({ role: 'user', content: input })

    const result = streamText({
      model: deepseek('deepseek-chat'),
      messages,
      tools: { readFile },
      stopWhen: stepCountIs(10),
    })

    process.stdout.write('助手: ')
    for await (const chunk of result.fullStream) {
      if (chunk.type === 'text-delta') process.stdout.write(chunk.text)
      else if (chunk.type === 'tool-call') process.stdout.write(`\n  [调用 ${chunk.toolName}(${JSON.stringify(chunk.input)})]`)
      else if (chunk.type === 'tool-result') process.stdout.write(`\n  [返回 ${String(chunk.output).length} 字节]\n助手: `)
    }

    const { messages: newMessages } = await result.response
    messages.push(...(newMessages as any))
  }

  rl.close()
}

main().catch(console.error)

运行后就能实现基础的文件查询对话,比如输入「帮我看看package.json里有哪些依赖」,Agent会自动调用readFile工具读取文件并返回结果。

这里最关键的一点是:代码中没有任何硬编码的逻辑规定「用户问文件就读取」,是否调用工具、调用几次、何时用自然语言回答,全部由模型自主决定。Agent循环的本质就是while循环+工具调用协议,这也是所有主流AI CLI的核心内核。

二、Demo与生产级产品的核心差距

50行的Demo只能用来理解概念,无法直接用于生产环境。我们可以通过6个典型场景,清晰看到两者之间的巨大鸿沟:

  1. 权限缺失风险:Demo中工具调用无任何确认环节,模型一旦发起删除、修改等危险操作会直接执行,可能导致文件丢失。
  2. 中断机制失效:用户按下Ctrl+C后,API请求会停止,但工具发起的Shell子进程仍会在后台运行,持续占用资源。
  3. 上下文溢出问题:多轮对话后历史消息和工具结果会不断累积,很快超出模型上下文窗口限制,导致请求报错。
  4. 死循环Token浪费:模型可能陷入反复重试同一失败动作的死循环,造成不必要的Token费用消耗。
  5. 工具能力单一:仅支持文件读取,无法满足代码搜索、文件修改、命令执行、网络查询等实际开发需求。
  6. 会话无持久化:退出程序后对话历史全部丢失,无法跨进程恢复会话,也没有长期记忆能力。

这些问题本质上都不是大模型能力的问题,而是工程实现的问题。Demo缺的不是更聪明的模型,而是能让模型在真实环境中稳定、安全、高效运行的外围工程体系。

三、AI工程的三个核心层级

大模型只是AI Agent的「发动机」,要让它完成实际任务,需要套上三层工程体系,这三层也对应了近几年AI工程领域的发展脉络:

层级 工程师介入位置 主要工作
提示词工程 字符串 编写系统提示词、工具描述、思维链引导
上下文工程 数据 决定哪些内容进入上下文、如何压缩/截断/排序
驾驭工程 代码 搭建Agent循环、工具系统、安全护栏、用户交互

提示词工程:从主战场到基础能力

2022-2023年是提示词工程的黄金期,Chain-of-Thought、ReAct、Tree of Thoughts等技巧大幅提升了模型的推理和工具使用能力。随着大模型内置了这些推理逻辑,提示词工程逐渐从核心战场退居基础层,但工具描述的精准度仍然直接影响模型的工具调用效果。

上下文工程:2024年独立的核心领域

2025年6月,Shopify CEO Tobi Lütke和AI专家Andrej Karpathy的推文让「上下文工程」成为行业共识。当上下文窗口扩展到百万Token后,人们发现「放进去更多」不等于「模型能读到更多」——模型对长上下文的注意力呈U型曲线,中段内容极易被忽略。

上下文工程的核心就是解决「让模型看到什么」的问题,包括信息过滤、内容截断、历史压缩、Prompt缓存优化等,目标是让上下文在长会话中不溢出、缓存持续命中、延迟保持稳定。

驾驭工程:2026年的核心赛道

就在今年2月,HashiCorp联合创始人Mitchell Hashimoto正式提出「驾驭工程(Harness Engineering)」的概念,核心公式是Agent = Model + Harness。所有让大模型在生产环境中完成任务的外围工程,包括Agent循环、工具系统、安全护栏、错误恢复、用户交互等,都属于这一层。

提示词工程做单点质量,上下文工程做信息密度,驾驭工程做整体可用性。我们的50行Demo已经实现了提示词和上下文工程的最小形态,缺的几乎全是驾驭工程的能力。

四、AI应用的价值正在向外层转移

过去三年,AI领域的大部分资源都集中在模型层,但从2024年开始,模型能力的边际收益明显递减。GPT-4到GPT-5、Claude 3.5到Claude 4的提升,已经不再是早期那种「换一代模型重做整个产品」的跨越式进步,主流模型的基线能力已经能满足大多数应用场景的需求。

与此同时,应用层的差距越来越明显。同样调用Claude API,专业的AI编程Agent和简单的聊天框体验天差地别,区别不在模型,而在外面的工程层。Anthropic推出Claude Code、OpenAI推出Codex CLI、Google推出Gemini CLI,本质上都是在模型之上补全驾驭工程的短板。

对开发者来说,驾驭工程是当前最值得投入精力的方向。提示词和上下文工程已经有了相对成熟的方法论,但驾驭工程还没有标准答案,Agent循环设计、工具粒度划分、安全护栏实现等方面的差异,正是产品之间拉开差距的关键。

五、驾驭工程的核心模块拆解

驾驭工程包含多个独立的工程领域,每个领域都有自己的设计取舍和最佳实践。

Agent Loop引擎

生产级的Agent循环会从Demo中的一行streamText,扩展为「主循环→单轮处理→工具执行」的三层结构,核心解决流式输出分发、工具调用配对、错误分类处理、中断信号传递等问题。

错误处理是其中的重点,需要将错误分为四类分别处理:静默重试类(限流、网络抖动)、用户提示类(鉴权失败、余额不足)、上下文调整类(上下文超限)、状态修复类(孤立的工具调用)。

工具系统:模型的「手脚」

工具系统负责执行所有涉及磁盘、网络、Shell的操作,核心设计难点包括:

  • 粒度划分:采用「细粒度工具为主+Shell工具兜底」的混合模式,兼顾安全性和灵活性
  • 错误返回:统一错误格式,包含错误码、简短说明和关键上下文,既让模型能理解,又不浪费Token
  • 结果截断:对grep、Shell等可能返回大量内容的工具,采用保留头尾、中间省略的截断策略
  • 中断传递:将AbortSignal从用户按键一路传递到实际子进程,确保Ctrl+C能彻底终止所有操作

子Agent:上下文资源的高效利用

子Agent是跨驾驭工程和上下文工程的重要设计,核心思路是将探索性子任务交给独立上下文的子Agent执行,只将最终结论回传给主对话。这样既能避免探索过程中的大量工具调用和文件内容挤占主上下文,又能让不同角色的子Agent专精于特定任务。

终端UI:最容易被低估的模块

AI CLI的终端UI需要同时支持滚动对话历史、固定输入框、流式打字、Markdown渲染、确认对话框等多种交互形态。中文环境下的宽字符列宽测算、局部重绘锚点冲突、跨终端兼容性等问题,是多数实现中最容易踩坑的地方。

Prompt缓存:单会话最大的成本杠杆

Prompt缓存通过复用模型处理重复前缀时生成的KV矩阵,能将输入Token成本降低70%-97%。但缓存命中要求前缀字节级完全一致,且不同厂商的接入协议和最小缓存粒度差异很大,需要在请求发送层统一屏蔽这些差异。

知识与记忆:跨会话的上下文延续

生产级Agent需要支持显式知识和隐式记忆两套机制:

  • 显式知识:遵循AGENTS.md社区规范,支持全局、项目、子目录三层配置合并
  • 隐式记忆:后台自动提取用户偏好、项目背景、协作习惯等信息,下次启动时自动注入

生产化护栏

三道核心护栏确保Agent稳定运行:

  • 权限模型:采用「默认(读放行写确认)→计划(只读)→信任(自动放行)」三档设计
  • 上下文压缩:实现轻量清理、主动压缩、紧急压缩、手动压缩四级策略
  • 循环防护:通过工具调用指纹检测重复操作,采用软阈值提示+硬阈值中断的双阈值设计

六、整体工程量估算

从50行Demo到生产级AI Agent CLI,核心代码量大约在2万行TypeScript量级。一位有经验的工程师带领3-5人的小团队,几个月就能做出第一版可用的产品。

工作量分布并不均匀:Agent循环本体约1000行,工具系统约3000-4000行,终端UI单独占2000-3000行,是最容易被低估的模块。剩下的上下文压缩、权限模型、循环防护、知识系统等模块各自相对独立,但都需要在主循环上挂载明确的对接点。

七、动手实现建议

如果你也想自己打造一款AI Agent CLI,可以按照以下步骤逐步推进:

  1. 先跑通最小Demo:亲手运行本文的50行代码,理解Agent循环的核心逻辑
  2. 聚焦单个问题深入:从你最关心的问题切入,比如权限控制、中断机制或循环防护
  3. 参考开源实现:Aider、OpenHands等成熟开源项目提供了很好的参考,建议带着具体问题读源码,而不是从头逐行阅读

在实际开发过程中,对接多家大模型API往往会带来接口不统一、缓存管理复杂、限流重试繁琐等问题,这里推荐使用TreeRouter这款轻量高效的API中转站。它能为你的AI Agent CLI提供统一的模型调用接口,自动兼容OpenAI、Gemini等主流厂商的API协议,还能精细化统计各模型的Token用量与成本,大幅降低AI Agent CLI的后端对接复杂度,让你更专注于驾驭工程与业务逻辑的实现。