从零实现 GeekAgent —— Day1 REPL 地基

💡 原文中文,约8200字,阅读约需20分钟。
📝

内容提要

本文介绍从零实现GeekAgent的第一天,目标是搭建REPL地基,实现流式多轮对话。项目使用TypeScript和Node.js,核心代码约157行,包含chat.ts、config.ts、color.ts和index.ts四个文件。通过history数组保存对话记忆,使用AsyncGenerator实现流式输出,并支持/reset和/exit命令。文章强调不依赖框架,保持代码简单易懂,为后续添加工具调用等功能打基础。

🔎

延伸解读

为什么选择 REPL 作为 Agent 地基

REPL(读入-求值-打印-循环)天然契合人机对话的“一来一回”模式。作者选择用 Node 自带的 readline 实现 REPL,而非引入 commander 等框架,虽然多写了约 100 行代码,但换来的是每一行都清晰可读。这种“零框架”思路降低了理解门槛,也为后续在循环中扩展工具调用等功能打下了基础。

多轮记忆的实现原理

模型本身是无状态的,所谓“记忆”其实是把历史对话作为 messages 数组全量重发给模型。作者将 history 直接设计为 OpenAI 兼容的 messages 格式,零转换,这样后续添加系统提示、工具调用等只需往同一数组追加不同 role 的条目。这种设计让多轮对话的实现变得简单直接,也体现了“非侵入式新增”的工程原则。

流式输出的体验价值

流式输出让模型回答“边想边说”,避免了长时间等待的“转圈”体验。实现上利用 AsyncGenerator 和 yield,每收到一个增量就立即打印。这种机制不仅提升了交互感,也为未来处理长回答或实时反馈提供了基础。作者强调,流式输出是 Agent 区别于简单 curl 调用的关键体验之一。

Q&A

REPL是什么?为什么Agent的地基要选REPL?

REPL是Read-Eval-Print-Loop的缩写,即“读入-求值-打印-循环”。因为人和模型对话的本质就是一来一回的循环,所以Agent的地基选REPL来跑通反复聊天的循环。

GeekAgent Day1的目标是什么?验收标准有哪些?

Day1的目标是搭建REPL地基,实现流式多轮对话。验收标准包括:一条命令启动进入青色You提示符;提问后逐字流式输出回答;多轮记忆(如记住名字);支持/reset清空记忆和/exit退出。

GeekAgent项目为什么不用curl直接调用模型?

因为curl只能一问一答,不自动记忆历史,默认不流式输出,也没有循环交互,且输出无颜色区分。而Agent需要能反复调、记得住、边出边显、看着清楚,所以需要自己写代码实现这些功能。

GeekAgent如何实现多轮记忆?

通过history数组保存对话历史,每次请求将整个history作为messages传给模型,模型回答后把回答追加到history中。这样模型就能基于历史上下文进行回复。

GeekAgent如何实现流式输出?

使用AsyncGenerator和yield,在streamReply方法中逐块接收模型返回的增量内容,并立即yield出去,调用方通过for await循环逐字打印,实现边生成边显示的效果。

GeekAgent的终端颜色是如何管理的?

所有颜色定义集中在color.ts文件中,通过转义序列实现,如青色表示用户输入,绿色表示模型回复。提供paint、out、err函数用于着色输出,非TTY时自动关闭颜色。

GeekAgent Day1支持哪些命令?

支持/help显示帮助,/reset清空对话记忆,/exit退出程序。

GeekAgent Day1明确没有实现哪些功能?下一步计划是什么?

Day1没有实现工具调用、文件读写和会话持久化。下一步计划是Day2实现工具调用,例如给模型配一个查时间的工具,让模型能动手干活。

🏷️

标签

➡️

继续阅读