配套小册《从零打造一个 AI Agent CLI(Build Your Own Agentic CLI)》第 1 章示例。
50 行跑通一个最小 AI agent。
代码本身只有 50 行,但展示了 agent 最核心的形态:模型 + 工具 + 多轮对话循环。装好依赖、配好 DEEPSEEK_API_KEY 就能在终端里和它聊天,让它读你本地的文件、回答问题。
- 🚀 50 行代码可运行:装依赖即可,无任何配置魔法
- 🛠️ 支持工具调用:内置一个
readFile工具,模型可以主动读你的文件 - 🔄 多轮对话:维护对话历史,模型记得之前聊过什么
- 📡 流式输出:模型生成的文本即时打印在终端,不需要等整段完成
git clone https://github.com/woai3c/hello-agent.git
cd hello-agent
npm install需要 Node.js ≥ 20.19。
需要一个 DeepSeek API Key——国内开发者首选,注册即送 token,价格便宜,访问无障碍。在 platform.deepseek.com 注册后,在「API Keys」页面创建一个 key(格式 sk-...)。三种配法任选其一:
方式 A:永久写到用户环境变量(推荐)
# macOS / Linux (bash / zsh)
echo 'export DEEPSEEK_API_KEY=sk-...' >> ~/.zshrc && source ~/.zshrc
# Windows PowerShell(用户级,永久)
[Environment]::SetEnvironmentVariable('DEEPSEEK_API_KEY','sk-...','User')方式 B:当前 shell 临时设置
# macOS / Linux
export DEEPSEEK_API_KEY=sk-...
# Windows PowerShell
$env:DEEPSEEK_API_KEY = "sk-..."方式 C:.env 文件
cp .env.example .env
# 编辑 .env 填入你的 keynpm start
# 等同于:npx tsx hello-agent.ts你: 帮我看看 package.json 里有哪些依赖
助手:
[调用 readFile({"path":"package.json"})]
[返回 487 字节]
助手: 你的 package.json 里有以下依赖:
- ai
- @ai-sdk/deepseek
- zod
...
你: 这个项目的 main 字段是什么?
助手: 你的 package.json 里没有显式声明 `main` 字段——npm 会默认 fallback 到 `index.js`。
你: exit
模型会自己决定要不要调 readFile、调几次、什么时候开始回答——这就是 agent 的核心循环。
| 代码片段 | 做的事 |
|---|---|
tool({ description, inputSchema, execute }) |
定义一个工具,告诉模型这工具叫什么、参数是啥、执行函数怎么跑 |
messages: [{role, content}, ...] |
维护对话历史,每轮把用户输入和模型回复追加进去 |
streamText({ model, messages, tools, stopWhen }) |
把对话历史 + 工具集发给模型,让 SDK 帮你跑多轮 tool-call → tool-result 循环 |
stopWhen: stepCountIs(10) |
最多 10 轮工具调用就收手,避免 doom-loop |
for await (const chunk of result.fullStream) |
流式消费——每个 chunk 是文本片段、工具调用、或工具结果 |
result.response.messages |
拿到 SDK 累积的所有新消息(文本 + tool-call + tool-result),追加进对话历史 |
整个程序就是一个 while 循环:用户输入 → 加进 messages → streamText → 流式打印 → 模型 + 工具调用都跑完 → 继续。这就是 agent loop 最朴素的形态。
下面这张表把"最小版做不了的事"和小册里讲清楚的章节一一对应——这也是这本小册接下来要补齐的"差距":
| 缺什么 | 后果 | 哪一章讲清楚 |
|---|---|---|
| 没有终端 UI | 只能裸 readline;多行输入、上下移动、@ 文件补全都没有 | 第四部分(Ch.23-28 终端 UI) |
| 没有权限确认 | 如果加上 shell 工具,模型想跑命令直接就跑——没有"这操作我同意一下"这一步 | Ch.29 三级权限模型 |
| 没有错误恢复 | 网络抖一下、模型返回 malformed tool input、长输出撑爆 context——任何一处崩,整个对话就死了 | Ch.11 错误恢复、Ch.17 工具结果处理 |
| 只支持一家供应商 | 改用 OpenAI / Anthropic / Gemini 都要改代码;各家的 cache_control / thinking / reasoning_effort 字段差异要单独适配 | Ch.09 多供应商支持 |
| 只有一个工具 | 改文件、跑 shell、grep、列目录、抓网页这些都没有 | 第三部分(Ch.12-22 工具系统) |
| 不会上下文压缩 | 多轮聊下来 messages 越积越长,几十轮就把 200K 上下文窗口塞满 | Ch.31 上下文压缩 |
| 没有 prompt caching | 每一轮系统提示词、对话历史都全量重算 token | Ch.33 Prompt caching |
| 没有 loop guard | 模型万一陷入死循环,唯一的 brake 是 stepCountIs(10) 这个粗粒度上限 |
Ch.32 Loop guard |
| 没有思考模式 / 多模态附件 / 子 agent / Plan Mode / 知识系统 / 会话恢复 | 高级模型的能力无法启用;复杂任务无法委派给子 agent;上一次会话的进度下次启动后无法恢复 | Ch.19-22(子 agent / todoWrite / Plan Mode)、Ch.34-36(思考模式 / 多模态 / 知识与会话系统) |
完整、生产级的实现见配套项目 X-Code CLI——小册会以它为主线,把上面这些短板一项项填上。
MIT
