终端UI:让AI说话有颜色

——CogitoAgent开发实战(第5篇)

📖 本文是专栏的第五篇。前四篇我们让AI学会了思考、学会了动手、学会了管理文件、学会了联网。但有一个问题始终没解决:AI说的话,用户怎么“看”?一个黑底白字的终端,如何区分“AI在思考”和“AI在回答”?如何让工具调用不喧宾夺主?这一篇,我们深入终端UI模块,看看如何让命令行里的AI“活”起来。

在这里插入图片描述


📌 从一个问题开始

想象一下这个场景:

你坐在电脑前,看着终端窗口。AI正在运行。

你看到一段文字在屏幕上滚动:

让我看看src目录下有什么。[TOOL] ls("src") [/TOOL][工具结果]: agent/ api/ config.js

这段文字里混着:

  • AI的思考
  • AI的正式回答
  • 工具调用指令
  • 工具执行结果

你能分清哪句是AI在想、哪句是AI在说、哪句是程序自动生成的?

如果分不清,那这个AI就“不好用”。

终端UI的核心问题:如何用有限的字符界面,让用户直观理解AI的“心智状态”?

这一篇,我们看CogitoAgent是怎么解决这个问题的。


一、终端的“语言”:ANSI转义码

1.1 问题:终端为什么默认只有黑白?

终端(Terminal)的本质是一个字符显示设备。它只能显示字符,没有图形界面。

在ANSI转义码出现之前,终端只能显示一种颜色(通常是绿色或白色)的字符。

但终端协议其实支持“指令”——特殊字符序列可以控制终端的行为:

  • 改变文字颜色
  • 移动光标位置
  • 清屏
  • 加粗、下划线

这些指令就是ANSI转义码

1.2 ANSI转义码的格式

ANSI转义码的格式是:\x1b[参数m

  • \x1b 是转义字符(ASCII 27)
  • [ 是控制序列引导符
  • 参数 是数字代码,用分号分隔
  • m 是“选择图形再现”命令

示例

\x1b[31m  红色文字
\x1b[32m  绿色文字
\x1b[1m   加粗
\x1b[0m   重置所有样式

1.3 终端UI模块中的颜色定义

// src/io/terminal.js
const COLORS = {
  reset: '\x1b[0m',
  bold: '\x1b[1m',
  dim: '\x1b[2m',
  gray: '\x1b[90m',
  red: '\x1b[91m',
  green: '\x1b[92m',
  darkGreen: '\x1b[32m',
  yellow: '\x1b[93m',
  blue: '\x1b[94m',
  magenta: '\x1b[95m',
  cyan: '\x1b[96m',
  white: '\x1b[97m',
  bgBlack: '\x1b[40m',
  bgBlue: '\x1b[44m',
  bgCyan: '\x1b[46m',
};

这些颜色代码的命名是有规律的:

颜色 前景色(文字) 背景色
黑色 30 40
红色 31 41
绿色 32 42
黄色 33 43
蓝色 34 44
品红 35 45
青色 36 46
白色 37 47

90-97 是亮色(bright)版本,比30-37更鲜艳。

1.4 让文字“带颜色”的封装

直接写 \x1b[31m红色文字\x1b[0m 非常繁琐,所以 terminal.js 封装了几个核心函数:

function print(text, color = null) {
  if (color && COLORS[color]) {
    process.stdout.write(COLORS[color] + text + COLORS.reset);
  } else {
    process.stdout.write(text);
  }
}

function println(text, color = null) {
  print(text, color);
  process.stdout.write('\n');
}

使用示例

println('这是一条错误信息', 'red');
println('这是一条提示信息', 'yellow');
println('这是一条调试信息', 'gray');

原理println('错误', 'red') 实际输出的是 \x1b[31m错误\x1b[0m\n。终端收到 \x1b[31m 后,把后续文字显示为红色,直到收到 \x1b[0m 重置。


二、分区展示:思考区、内容区、工具区

2.1 问题:AI的回复分成三种“内容”

大模型返回的内容,实际上可以分成三种类型:

类型 内容 用户想看吗? 应该怎么显示?
思考过程 reasoning_content 想看(知道AI在想什么) 低调,不干扰主内容
正式回复 content 必须看 醒目,是核心内容
工具调用 [TOOL]...[/TOOL] 可看可不看 缩进,灰色,不喧宾夺主

三种内容混在一起输出,用户无法区分。所以需要分区展示

在这里插入图片描述

2.2 状态标签的设计

terminal.js 使用两个布尔标志来控制分区:

let reasoningTagPrinted = false;   // 思考区的“门头”是否已打印
let contentTagPrinted = false;     // 内容区的“门头”是否已打印

核心逻辑:每种内容的“门头”(比如 ┌─ 思考过程)只在第一次收到该类型内容时打印一次,后续内容直接追加,直到切换到另一种类型时才“关门”。

2.3 思考区的实现

function printReasoning(text) {
  // 只有第一次收到思考内容时才打印门头
  if (!reasoningTagPrinted) {
    print('\n');
    println('┌─ 思考过程 ─────────────────────────────', 'darkGreen');
    reasoningTagPrinted = true;
  }
  print(text, 'darkGreen');
}

function closeReasoning() {
  // 当思考内容结束时,打印底部边框
  if (reasoningTagPrinted) {
    print('\n');
    println('└──────────────────────────────────────────', 'darkGreen');
    reasoningTagPrinted = false;
  }
}

效果

┌─ 思考过程 ─────────────────────────────
用户让我查看src目录,我需要先ls一下
然后分析里面有什么关键文件
└──────────────────────────────────────────

思考过程用深绿色(darkGreen)显示,视觉上比正文暗一些,传递“这是AI内部思考,不是最终答案”的信号。

2.4 内容区的实现

function printContent(text) {
  // 如果之前有思考区,先“关门”
  if (!contentTagPrinted) {
    if (reasoningTagPrinted) {
      print('\n');
      println('└──────────────────────────────────────────', 'dim');
      resetReasoningTag();
    }
    print('\n');
    println('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', 'cyan');
    println('           ▼ 回复内容 ▼', 'bold');
    println('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', 'cyan');
    contentTagPrinted = true;
  }
  print(text);
}

效果

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
           ▼ 回复内容 ▼
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
我来看看src目录下有什么...

正文区域用青色分隔线包围,中间有一个醒目的 ▼ 回复内容 ▼ 标签。用户一眼就能识别:“这是AI要跟我说的话”。

2.5 工具调用区的实现

function printToolBlock(content, title = '工具调用') {
  print('\n');
  println(`  ┌─── ${title} ────────────────────────`, 'dim');
  const lines = content.split('\n');
  for (const line of lines) {
    println(`${line}`, 'dim');
  }
  println('  └────────────────────────────────────────', 'dim');
}

效果

  ┌─── 工具调用 ────────────────────────
  │ [TOOL] ls("src") [/TOOL]
  └────────────────────────────────────────

  ┌─── 工具结果 ────────────────────────
  │   [目录]
  │     agent/
  │     api/
  │   [文件]
  │     config.js
  └────────────────────────────────────────

工具调用区用灰色(dim)显示,并且整体缩进。视觉上它“靠后站”,告诉用户:“这是中间过程,不是最终答案。”

在这里插入图片描述

2.6 三种分区的视觉层次

思考区      → 深绿色,带边框,视觉上“暗”
内容区      → 正常颜色,带醒目分隔线,视觉上“亮”
工具调用区  → 灰色,缩进,视觉上“后退”

三种分区的视觉权重:内容区 > 思考区 > 工具调用区

用户的视线会自然地被内容区吸引,思考区和工具调用区作为“背景信息”存在。


三、流式输出的“实时感”

3.1 流式输出 vs 一次性输出

大模型有两种输出方式:

一次性输出:等AI生成完所有内容,一次性显示。

(等待5-10秒)... 突然显示一大段文字

用户在这5-10秒里不知道AI在干嘛,体验很差。

流式输出:AI每生成一个token就立即显示。

用户发送消息
↓ 0.1秒后显示第一个字
↓ 0.2秒后显示第二个字
↓ ... 像打字机一样逐字出现

用户看到文字在“生长”,知道AI在工作,体验好。

3.2 CogitoAgent的流式实现

// src/api/client.js
async function* streamChat(messages) {
  const response = await c.chat.completions.create({
    messages,
    model: m,
    stream: true,  // 关键:开启流式
    // ...
  });

  for await (const chunk of response) {
    const delta = chunk.choices[0].delta;
    yield {
      content: delta.content || null,
      reasoning: delta.reasoning_content || null
    };
  }
}

关键点

  • stream: true 告诉API以流式返回
  • for await 循环逐块接收
  • 每个chunk包含 content(正文)或 reasoning_content(思考)
  • 两个字段分别对应两种分区

3.3 思考过程的“实时展示”

// src/agent/Agent.js
for await (const chunk of streamChat(messages)) {
  if (chunk.reasoning) {
    printReasoning(chunk.reasoning);  // 实时打印思考内容
  }
  if (chunk.content) {
    fullResponse += chunk.content;   // 累积正文
  }
}

用户在AI“思考”的同时就能看到思考过程,而不是干等。

3.4 思考区“关门”的时机

thinkCycle 函数在流式输出结束后调用 closeReasoning()

// 收尾:关闭思考区标签
closeReasoning();
resetContentTag();

如果AI在思考过程中没有输出任何正式回答,思考区就会保持打开状态,然后在流结束时关闭。如果AI既有思考又有回答,思考区会在内容区开始打印时自动关闭(printContent 中会检查并关闭思考区)。


四、状态标签(Tag)与提示

4.1 状态标签的用途

在终端UI中,状态标签用来突出显示关键信息点

function printTag(text, bgColor = 'bgBlue', textColor = 'white') {
  const bg = COLORS[bgColor] || COLORS.bgBlack;
  const tc = COLORS[textColor] || COLORS.white;
  return `${bg}${tc} ${text} ${COLORS.reset}`;
}

使用

println('  活动范围: ' + printTag(getBasePath(), 'bgBlue'));

效果活动范围: [ D:\my-project ](蓝色背景,白色文字,像一块标签)

状态标签让关键信息在界面中“跳出来”,用户扫一眼就能看到。

4.2 启动时的状态展示

// src/agent/Agent.js
printBanner();
printDivider('─', 'cyan');
println('  活动范围: ' + printTag(tools.getBasePath(), 'bgBlue') + 
        '  思考间隔: ' + printTag(`${thoughtInterval / 1000}`, 'bgCyan'));
printDivider('─', 'cyan');
println('  按 ' + printTag('Enter', 'bgBlue') + ' 打断思考,输入 ' + 
        printTag('exit', 'bgBlue') + ' 退出\n', 'gray');

效果

██████╗  ██████╗  ██████╗ ██╗████████╗ ██████╗      █████╗  ██████╗ ███████╗...
            CogitoAgent
╔══════════════════════════════════════════════════════════════╗
║  持续思考的智能体 - 探索文件 · 联网搜索 · 自主学习           ║
╚══════════════════════════════════════════════════════════════╝

────────────────────────────────────────────────────────────────
  活动范围: [ D:\my-project ]  思考间隔: [ 3秒 ]
────────────────────────────────────────────────────────────────
  按 [ Enter ] 打断思考,输入 [ exit ] 退出

用户启动程序后,立刻知道:

  1. AI能访问哪些文件(活动范围)
  2. AI多久思考一次(思考间隔)
  3. 如何与AI交互(Enter打断、exit退出)

4.3 危险操作的确认提示

// Agent.js - executeTool
if (isConfirmEnabled() && isDangerousOperation(toolName)) {
  println('');
  printDivider('!', 'yellow');
  println(`  ⚠️  危险操作请求: ${printTag(toolName, 'bgYellow')}`, 'yellow');
  println(`  参数: ${args.join(', ')}`, 'yellow');
  println(`  是否执行此操作? 输入 ${printTag('y', 'bgGreen')} 确认, ${printTag('n', 'bgRed')} 拒绝`, 'yellow');
  printDivider('!', 'yellow');
  println('');
  // 等待用户确认...
}

效果

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  ⚠️  危险操作请求: [ executeCode ]
  参数: rm -rf /, python
  是否执行此操作? 输入 [ y ] 确认, [ n ] 拒绝
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

黄色分隔线 + 警告图标 + 高亮标签,让用户不可能错过这个确认提示。

4.4 分隔线函数

function printDivider(char = '─', color = 'gray') {
  const width = process.stdout.columns || 80;
  const colorCode = COLORS[color] || COLORS.reset;
  console.log(colorCode + char.repeat(width) + COLORS.reset);
}

设计细节

  • 自适应终端宽度(process.stdout.columns
  • 可自定义分隔符(=!等)
  • 可自定义颜色

五、用户输入与交互

5.1 readline:Node.js的命令行交互基础

Node.js 的 readline 模块提供了命令行交互能力:

import readline from 'readline';

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});

rl.on('line', (input) => {
  // 用户按Enter时触发
  handleUserInput(input.trim());
});

关键点

  • readline事件驱动的:用户输入一行,触发 line 事件
  • 不会阻塞主线程,AI可以在等待输入的同时继续思考
  • rl.prompt() 可以显示提示符(但CogitoAgent选择不显示,保持界面干净)

5.2 用户输入处理流程

// src/agent/Agent.js
function handleUserInput(input) {
  // 1. 退出命令
  if (input.toLowerCase() === 'exit') {
    exit();
    return;
  }

  // 2. 特殊命令(以 / 开头)
  if (input.startsWith('/')) {
    if (handleCommand(input)) return;
  }

  // 3. 危险操作确认(等待确认状态)
  if (state.current === STATE.AWAITING_CONFIRMATION) {
    if (input === 'y') {
      resolveConfirmation(true);
    } else if (input === 'n') {
      resolveConfirmation(false);
    }
    return;
  }

  // 4. 正常消息输入
  if (state.current === STATE.THINKING) {
    // 用户打断AI思考
    shouldStop = true;
    clearTimeout(thinkingTimer);
    state.current = STATE.AWAITING_INPUT;
  } else if (state.current === STATE.AWAITING_INPUT) {
    if (input) {
      addUserMessage(input);
      state.current = STATE.THINKING;
      scheduleNextCycle();
    }
  }
}

5.3 “打断思考”的用户体验

当用户按 Enter 时,AI正在思考:

(AI正在流式输出思考内容)
用户:按 Enter
终端: [中断] 思考已停止,请输入消息...
用户:帮我看看src目录

关键设计

  1. shouldStop = truethinkCycle 在下一个chunk处退出
  2. clearTimeout(thinkingTimer) 取消已调度的下一次思考
  3. 状态切换到 AWAITING_INPUT,AI停止自主活动
  4. 用户输入消息后,状态切回 THINKING,AI恢复思考

5.4 退出清理机制

// src/io/terminal.js
async function exit() {
  console.log('\n正在清理资源...');

  if (cleanupCallback) {
    try {
      await cleanupCallback();
    } catch (e) {
      console.error('清理失败:', e.message);
    }
  }

  if (rl) {
    rl.close();
  }

  setTimeout(() => {
    process.exit(0);
  }, 100);
}

退出前执行清理回调(如关闭数据库连接、停止定时任务等),确保资源正确释放。


六、欢迎页面的设计

6.1 启动 Banner

printBanner 函数生成了一个 ASCII Art 标题:

function printBanner() {
  const banner = `
${COLORS.cyan}${COLORS.bold}
██████╗  ██████╗  ██████╗ ██╗████████╗ ██████╗      █████╗  ██████╗ ███████╗...
${COLORS.reset}
${COLORS.cyan}${COLORS.bold}            CogitoAgent${COLORS.reset}
${COLORS.bold}╔══════════════════════════════════════════════════════════════╗
║  持续思考的智能体 - 探索文件 · 联网搜索 · 自主学习           ║
╚══════════════════════════════════════════════════════════════╝${COLORS.reset}
`;
  console.log(banner);
}

视觉效果

  • 彩色大标题(青色 + 加粗)
  • 产品名称居中
  • 一个带边框的标语框

ASCII Art 是通过一个在线转换工具将文字转成字符画后粘贴到代码中的。虽然不是动态生成的,但效果稳定。

6.2 欢迎页面:设置向导的“第一印象”

在最新版本中,setup.js 也加入了艺术化设计:

function printSetupBanner() {
  const banner = `
${COLORS.cyan}${COLORS.bold}
██████╗  ██████╗  ██████╗ ██╗████████╗ ██████╗      █████╗  ██████╗ ███████╗...
${COLORS.reset}
${COLORS.cyan}${COLORS.bold}            CogitoAgent${COLORS.reset}
${COLORS.bold}╔══════════════════════════════════════════════════════════════╗
║  ${COLORS.magenta}🚀 设置向导${COLORS.reset}${COLORS.bold} - 让我来帮你完成初始配置                        ║
╚══════════════════════════════════════════════════════════════╝${COLORS.reset}
`;
  println(banner);
}

设置向导与主程序使用统一的设计语言,用户从首次配置到日常使用,界面风格一致。

6.3 步骤引导的艺术

function printStepTitle(stepNum, title) {
  println('');
  printDivider('─', 'cyan');
  println(COLORS.cyan + COLORS.bold + `  【第${stepNum}步】` + 
          COLORS.white + title + COLORS.reset);
  printDivider('─', 'cyan');
}

效果

────────────────────────────────────────────
  【第1步】输入 API Base URL
────────────────────────────────────────────
  💡 例如: https://api.openai.com/v1 或 https://api.moark.com/v1

  请输入: 

步骤标题 + 提示信息 + 输入提示,用户清楚地知道“我在哪一步”、“我该输入什么”。

6.4 完成画面

function printCompleteBanner() {
  println('');
  println(COLORS.green + COLORS.bold + '╔══════════════════════════════════════════════════════════════╗' + COLORS.reset);
  println(COLORS.green + '║' + COLORS.reset + '                                                              ' + COLORS.green + '║' + COLORS.reset);
  println(COLORS.green + '║' + COLORS.reset + '     ' + COLORS.bold + COLORS.white + '🎉 设置完成!' + COLORS.reset + '                                      ' + COLORS.green + '║' + COLORS.reset);
  println(COLORS.green + '║' + COLORS.reset + '                                                              ' + COLORS.green + '║' + COLORS.reset);
  println(COLORS.green + '║' + COLORS.reset + '     ' + COLORS.cyan + '重新运行程序即可开始使用 CogitoAgent' + COLORS.reset + '              ' + COLORS.green + '║' + COLORS.reset);
  println(COLORS.green + '║' + COLORS.reset + '                                                              ' + COLORS.green + '║' + COLORS.reset);
  println(COLORS.green + COLORS.bold + '╚══════════════════════════════════════════════════════════════╝' + COLORS.reset);
  println('');
}

效果

╔══════════════════════════════════════════════════════════════╗
║                                                              ║
║     🎉 设置完成!                                            ║
║                                                              ║
║     重新运行程序即可开始使用 CogitoAgent                     ║
║                                                              ║
╚══════════════════════════════════════════════════════════════╝

这个“完成画面”用绿色边框包围,带有一个庆祝表情符号,传递“成功”的情绪信号。


七、设计原则总结

7.1 视觉层次原则

终端UI的设计遵循了明确的视觉层次:

层次 内容 视觉处理
最高 危险操作确认 黄色分隔线 + 警告图标 + 高亮标签
AI正式回复 青色分隔线 + 居中标签
AI思考过程 深绿色 + 边框
工具调用/结果 灰色 + 缩进
最低 系统提示 灰色普通文字

7.2 信息密度控制原则

终端界面的信息密度需要控制:

设计决策 目的
思考区“折叠” 思考内容不干扰正文阅读
工具调用区缩进 中间过程不喧宾夺主
分隔线自适应宽度 在不同终端尺寸下保持一致
颜色限制 只用6-8种颜色,不乱

7.3 反馈即时性原则

场景 反馈方式 延迟
AI开始思考 打印 ┌─ 思考过程 < 100ms
AI输出正文 打印 ▼ 回复内容 + 逐字输出 实时
工具执行 打印灰色小框 执行后立即
危险操作 黄色确认框 + 等待输入 立即
用户打断 [中断] 思考已停止 立即

用户的每个操作都能得到即时视觉反馈,不会产生“我在按按钮,但不知道有没有生效”的困惑。


八、完整的交互流程演示

让我们把以上所有机制串联起来,看一个完整的交互流程:

用户启动程序

██████╗  ██████╗  ██████╗ ██╗████████╗ ██████╗ ...
            CogitoAgent
╔══════════════════════════════════════════════════════════════╗
║  持续思考的智能体 - 探索文件 · 联网搜索 · 自主学习           ║
╚══════════════════════════════════════════════════════════════╝

────────────────────────────────────────────────────────────────
  活动范围: [ D:\my-project ]  思考间隔: [ 3秒 ]
────────────────────────────────────────────────────────────────
  按 [ Enter ] 打断思考,输入 [ exit ] 退出

AI开始自主思考

┌─ 思考过程 ─────────────────────────────
我刚刚启动,需要先了解工作区结构。让我看看根目录下有什么。
└──────────────────────────────────────────

  ┌─── 工具调用 ────────────────────────
  │ [TOOL] ls(".") [/TOOL]
  └────────────────────────────────────────

  ┌─── 工具结果 ────────────────────────
  │   [目录]
  │     src/
  │     docs/
  │   [文件]
  │     README.md
  │     package.json
  └────────────────────────────────────────

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
           ▼ 回复内容 ▼
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
我查看了工作区根目录,发现了一个 src/ 文件夹、docs/ 文件夹、
README.md 和 package.json。让我再深入看看 src/ 里有什么。
[WAIT]
[等待] 我先不说了,等你说~

用户按Enter打断,输入指令

(用户按 Enter)
[中断] 思考已停止,请输入消息...

(用户输入 "帮我看看src目录")
[消息] 帮我看看src目录

AI继续思考

┌─ 思考过程 ─────────────────────────────
用户想查看 src 目录,我来 ls 一下。
└──────────────────────────────────────────

  ┌─── 工具调用 ────────────────────────
  │ [TOOL] ls("src") [/TOOL]
  └────────────────────────────────────────

  ┌─── 工具结果 ────────────────────────
  │   [目录]
  │     agent/
  │     api/
  │   [文件]
  │     config.js
  │     setup.js
  └────────────────────────────────────────

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
           ▼ 回复内容 ▼
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
src/ 目录下有三个子目录:agent/、api/,以及两个配置文件。你想深入了解哪个部分?
[WAIT]
[等待] 我先不说了,等你说~

用户输入 exit

exit
正在清理资源...

九、设计启发

9.1 终端UI的三个层次

CogitoAgent 的终端UI设计可以抽象为三个层次:

层次 内容 实现方式
内容层 AI的思考、回答、工具调用 分区展示 + 颜色标记
交互层 用户输入、打断、确认 readline + 状态机
装饰层 Banner、分隔线、标签 ASCII字符 + ANSI颜色

9.2 为什么终端UI仍然重要?

在图形界面普及的今天,终端UI似乎“过时”了。但 CogitoAgent 选择终端界面,有它的道理:

  1. 跨平台:终端在所有操作系统上都能工作
  2. 轻量:不需要渲染HTML、CSS,启动快
  3. 专注:没有浏览器弹窗、通知等干扰
  4. 可控:开发者对每一行输出都有完全控制权

更重要的是:终端UI的设计思路可以迁移到任何界面

思考区、内容区、工具区的分区逻辑,可以变成图形界面中的三个面板;颜色标记可以变成图标和字号;状态标签可以变成徽章和状态灯。

9.3 启发:让“中间状态”可视化

很多AI应用只展示最终答案,不展示中间过程。但 CogitoAgent 选择展示思考过程和工具调用。

为什么?

因为用户需要信任AI。如果AI只给结果不给过程,用户会怀疑“它是不是瞎编的”。展示思考过程和工具调用,让用户看到AI的“推理链条”,增强信任感。

这是一个重要的产品设计原则:在AI应用中,展示过程比展示结果更重要。


十、小结

设计要点 实现方式 解决的问题
分区展示 printReasoning/printContent/printToolBlock 区分思考/回答/工具
流式输出 for await + 实时打印 避免用户等待
颜色标记 ANSI转义码 + 颜色函数 传递语义信息
状态标签 printTag 突出关键信息
自适应分隔线 process.stdout.columns 适配不同终端
退出清理 onCleanup回调 释放资源
危险确认 黄色分隔线 + 等待输入 防止误操作
Banner ASCII Art 品牌识别

下一篇预告:记忆系统

我们将深入 memory.js,看看:

  • 记忆如何持久化存储
  • 标签分类和相关性评分
  • 记忆搜索的模糊匹配算法
  • 如何让AI“记住”和“回忆”

如果这篇文章对你有帮助,欢迎 ⭐Star 支持一下开源项目!

👉 https://gitee.com/cnt-code/cogito-agent 👈

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐