让 Agent 开口说话:用 Chalk 实现可视化终端

一个 Agent 如果只是默默干活、最后丢个结果出来------你永远不知道它中间在想什么、做了几步、有没有卡住。


一、先看效果

同样一个任务"创建 React 项目",没做可视化之前:

css 复制代码
$ node src/main.js

(终端空白 30 秒...)

任务完成,项目已创建在 react-todo-app

做了可视化之后:

bash 复制代码
$ node src/main.js "创建一个 todo 应用"

🚀 Agent 启动
📝 任务: 创建一个 todo 应用

━━━ 第 1/15 轮 (累计 0.0s) ━━━

📋 模型请求调用 2 个工具:
  → execute_command
      command: pnpm create vite react-todo-app --template react-ts

  ⚡ execute_command (3200ms)
  ✔ execute_command → 命令执行成功

━━━ 第 2/15 轮 (累计 5.2s) ━━━

📋 模型请求调用 1 个工具:
  → write_file
      filePath: react-todo-app/src/App.tsx

  ⚡ write_file (45ms)
  ✔ write_file → 3847 字符

━━━ 第 3/15 轮 (累计 8.1s) ━━━

🤖 Agent 最终回复:
TodoList 应用已创建完成,功能包含添加、删除、筛选和本地存储。

✅ Agent 执行完成!

同样的功能,后者让你看清楚 Agent 的每一步决策。

这篇文章讲的就是怎么做到这一点。


二、Chalk 是什么

一个给终端文字上色的库,只有一件事:把 console.log 变成彩色的。

js 复制代码
import chalk from 'chalk'

console.log(chalk.green('成功'));          // 绿色文字
console.log(chalk.red.bold('错误'));       // 红色加粗
console.log(chalk.blue('Agent 回复'));     // 蓝色
console.log(chalk.gray('辅助信息'));       // 灰色(不抢眼)

2.1 Chalk v5 的 ESM 变化

v5 是 ESM-only,只能用 import

js 复制代码
// ✅ v5 正确写法
import chalk from 'chalk';
chalk.green('hello');

// ❌ 常见错误 --- 从旧版本教程抄来的
const chalk = require('chalk');          // v5 不支持 require
import { Chalk } from 'chalk';           // Chalk 是类,不是你要用的

2.2 常用颜色与使用场景

js 复制代码
chalk.green('✔ 成功')         // 工具执行成功
chalk.red('✖ 失败')           // 错误信息
chalk.yellow('⚠ 警告')        // 达到最大迭代次数
chalk.cyan('→ 工具调用')      // Agent 计划做什么
chalk.magenta.bold('分隔线')   // 轮次分隔
chalk.blue('模型回复')         // Agent 的最终输出
chalk.gray('辅助信息')         // 文件路径、时长、ID
chalk.white('命令内容')        // 具体要执行的命令

三、从散弹到统一:Logger 模式的设计

3.1 第一版:各自为政

最早我在四个工具文件里各自写 console.log:

js 复制代码
// readFileTool.js
console.log(`[工具调用] read_file: (${filePath}) 成功读取${content.length}字节`);

// writeFileTool.js
console.log(`[工具调用] write_file: (${filePath}) 创建成功写入${content.length}字节`);

// execCommandTool.js
console.log(`[工具调用] execute_command(${command}) 成功执行`);

三个问题:

  1. 格式不统一 :有的带 [工具调用] 前缀,有的没有;有的显示字节数,有的不显示
  2. 没有颜色:全是白字,关键信息淹没在日志里
  3. 职责混乱:工具既要执行逻辑又要管展示

3.2 第二版:加 Chalk,但没统一

改成彩色了,但日志逻辑仍然散落在各个文件:

js 复制代码
// 每个工具文件都 import chalk from 'chalk',然后各自 console.log

改一个颜色规范要动四个文件。新增工具还得记住用什么格式。

3.3 最终版:Logger 集中管理

创建 src/utils/logger.js,所有可视化逻辑集中在一处:

js 复制代码
import chalk from 'chalk';

export const logger = {
    phase(msg) {
        console.log(chalk.magenta.bold(`\n━━━ ${msg} ━━━`));
    },

    toolPlan(toolCalls) {
        console.log(chalk.cyan.bold(`\n📋 模型请求调用 ${toolCalls.length} 个工具:`));
        for (const tc of toolCalls) {
            console.log(chalk.cyan(`  → ${tc.name}`));
            if (tc.args) {
                for (const [key, value] of Object.entries(tc.args)) {
                    console.log(chalk.gray(`      ${key}: ${value}`));
                }
            }
        }
    },

    toolSuccess(name, duration, summary) {
        console.log(chalk.green(`  ✔ ${name}`) +
            chalk.gray(` (${duration}ms)`) +
            (summary ? chalk.green(` → ${summary}`) : ''));
    },

    toolFail(name, duration, reason) {
        console.log(chalk.red(`  ✖ ${name}`) +
            chalk.gray(` (${duration}ms)`) +
            chalk.red(` → ${reason}`));
    },

    agentReply(content) {
        console.log(chalk.blue.bold('\n🤖 Agent 最终回复:'));
        console.log(chalk.blue(content));
    },

    // ... 更多方法
};

现在工具文件里一行 console.log 都没有------纯函数,只返回结果字符串。所有可视化由 ReactAgent 调用 logger 完成。


四、可视化与执行分离

4.1 改造前的工具

js 复制代码
// 旧版 writeFileTool ------ 自己打日志
async ({ filePath, content }) => {
    try {
        await fs.mkdir(dir, { recursive: true });
        await fs.writeFile(filePath, content, 'utf8');
        console.log(chalk.green(`✔ write_file ${filePath} (${content.length} 字节)`));
        return `成功写入${filePath}`;
    } catch (err) {
        console.log(chalk.red(`✖ write_file ${filePath} 失败: ${err.message}`));
        return `写入失败: ${err.message}`;
    }
}

4.2 改造后的工具

js 复制代码
// 新版 writeFileTool ------ 纯函数,只返回结果
async ({ filePath, content }) => {
    try {
        const dir = path.dirname(filePath);
        await fs.mkdir(dir, { recursive: true });
        await fs.writeFile(filePath, content, 'utf8');
        return `成功写入${filePath} (${content.length} 字节)`;
    } catch (err) {
        return `写入文件 ${filePath} 失败: ${err.message}`;
    }
}

4.3 Agent 层统一调用 logger

js 复制代码
// ReactAgent.js ------ 统一管理可视化
for (const toolCall of response.tool_calls) {
    logger.toolStart(toolCall.name, toolCall.args);   // 开始执行

    const toolStart = Date.now();
    let toolResult;
    try {
        toolResult = await tool.invoke(toolCall.args);
    } catch (err) {
        toolResult = `工具执行出错: ${err.message}`;
    }

    const duration = Date.now() - toolStart;
    logger.toolSuccess(toolCall.name, duration, this._summarizeResult(toolCall.name, toolResult));
}

4.4 好处

旧方案 新方案
工具文件 含 chalk + console.log 纯函数,只 return
颜色规范 散落各处,容易不一致 logger.js 一处定义
新增工具 要记住日志格式 写工具逻辑即可,logger 自动处理
修改展示 改 N 个文件 只改 logger.js
测试 日志干扰测试 工具是纯函数,好测

五、让信息有层次

好的可视化不是"所有东西都亮",而是关键信息跳出来,辅助信息退到背景里

5.1 颜色语义体系

复制代码
🟢 green    --- 成功(工具执行完毕、Agent 完成)
🔴 red      --- 失败(错误、异常)
🔵 blue     --- Agent 回复(模型的最终输出)
🟣 magenta  --- 阶段标记(轮次分隔线)
🟡 cyan     --- 计划/意图(模型打算调用哪些工具)
🟡 yellow   --- 警告(达到上限、命令正在执行)
⚪ gray     --- 元数据(文件路径、耗时、ID)

5.2 控制信息密度

长字符串自动截断:

js 复制代码
// logger.js 中的处理
const display = typeof value === 'string' && value.length > 80
    ? value.slice(0, 80) + '...'
    : value;

文件内容可能有几千行,不能在日志里全打印。只显示摘要(多少字符 / 多少项 / 命令退出码)。

5.3 计时信息

每轮迭代和每个工具调用都有计时:

scss 复制代码
━━━ 第 3/15 轮 (累计 8.1s) ━━━    ← 总耗时
  ✔ execute_command (3200ms)      ← 单步耗时
  ✔ write_file (45ms)

这让用户能直观感受到:哪些步骤慢、慢在哪里。


六、总结

这篇文章讲了三个层次的事:

第一层 --- 工具 :Chalk v5 是 ESM-only,import chalk from 'chalk' 即可,支持链式调用 .red.bold

第二层 --- 模式logger.js 集中管理模式,工具文件纯净化,Agent 层统一调度。

第三层 --- 思想 :可视化不是为了花哨,是为了可观测性。Agent 是一个黑盒------它想什么、做什么、是否卡住,用户完全不知道。好的日志输出让黑盒变得透明。


三篇文章构成了一个完整的学习路径:

主题 核心问题
第一篇 Agent 设计 Agent 为什么能工作?(ReAct 循环)
第二篇 内置模块 Agent 怎么干活?(fs / path / spawn / readline)
第三篇 可视化 Agent 干了什么?(chalk / logger 模式)

仓库地址min-cursor

相关推荐
不好听6132 小时前
AI Agent 的四肢:Node.js 内置模块实战指南
agent
学渣超2 小时前
微服务日志智能诊断系统(七) 日志 RAG 引擎——蒸馏、索引与精准检索
java·后端·agent
掉鱼的猫2 小时前
代码审查 Agent Harness 实战:AI 自动 Code Review
java·llm·agent
学渣超2 小时前
微服务日志智能诊断系统(六) Fast Path vs Slow Path——双路径日志诊断策略
java·后端·agent
apprentice3 小时前
跳出余弦相似度陷阱:RAG检索本质是筛选
agent·ai编程
GrowthGPT3 小时前
平台自报的 ROAS 在骗你
agent
先吃饱再说3 小时前
手写一个 mini-cursor:LangChain Agent 开发完全实战
langchain·llm·agent
chanalbert3 小时前
Agent Skill 工程化指南(三):运行与生效 — 运行时的全链路机制
llm·agent
武子康3 小时前
调查研究-222 PagedAttention 详解:vLLM 如何像操作系统一样管理 KV Cache
人工智能·llm·agent