This commit is contained in:
176
taolun.md
176
taolun.md
@@ -206,3 +206,179 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
3. 换行控制:
|
3. 换行控制:
|
||||||
- "思考完成." 后需要两个换行符(一个换行 + 一个空行)
|
- "思考完成." 后需要两个换行符(一个换行 + 一个空行)
|
||||||
- 流式输出完成后也需要空行分隔
|
- 流式输出完成后也需要空行分隔
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 13. 重绘残留问题与新流程
|
||||||
|
|
||||||
|
#### 问题描述
|
||||||
|
|
||||||
|
之前的流程:
|
||||||
|
1. 流式实时打印 token(边收边打)
|
||||||
|
2. 完成后 Markdown 重绘
|
||||||
|
3. 问题:重绘有残留
|
||||||
|
|
||||||
|
#### 解决方案:等待完整响应后输出
|
||||||
|
|
||||||
|
改进后的流程:
|
||||||
|
1. AI 返回完整数据 ← 等待时间
|
||||||
|
2. Markdown 转译
|
||||||
|
3. 模拟流式输出(从配置读取速度)
|
||||||
|
|
||||||
|
效果更好,无残留问题。
|
||||||
|
|
||||||
|
#### 配置化
|
||||||
|
|
||||||
|
使用 `project.config.yml` 统一管理配置:
|
||||||
|
```yaml
|
||||||
|
streaming:
|
||||||
|
line_delay_ms: 1000 # 每行输出后的延迟(毫秒)
|
||||||
|
last_line_delay_ms: 600 # 最后一行延迟(毫秒)
|
||||||
|
|
||||||
|
markdown:
|
||||||
|
glamour_style: dark
|
||||||
|
wrap_width: 0 # 自动获取终端宽度
|
||||||
|
|
||||||
|
ui:
|
||||||
|
logo: "🦐"
|
||||||
|
user_prefix: "👀 " # 用户输入前缀
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 14. 按行延迟输出的实现
|
||||||
|
|
||||||
|
#### 核心逻辑
|
||||||
|
|
||||||
|
```go
|
||||||
|
func outputLineByLine(text string) {
|
||||||
|
lines := strings.Split(text, "\n")
|
||||||
|
totalLines := len(lines)
|
||||||
|
|
||||||
|
cfg := internal.GetProjectConfig()
|
||||||
|
lineDelay := time.Duration(cfg.Streaming.LineDelayMs) * time.Millisecond
|
||||||
|
lastLineDelay := time.Duration(cfg.Streaming.LastLineDelayMs) * time.Millisecond
|
||||||
|
|
||||||
|
for i, line := range lines {
|
||||||
|
if line == "" {
|
||||||
|
fmt.Println()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fmt.Println(line)
|
||||||
|
|
||||||
|
if i < totalLines-1 {
|
||||||
|
time.Sleep(lineDelay)
|
||||||
|
} else {
|
||||||
|
time.Sleep(lastLineDelay)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
特点:
|
||||||
|
- 空行直接跳过
|
||||||
|
- 每行输出后延迟可配置
|
||||||
|
- 最后一行延迟可单独配置
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 15. 工具调用结果显示问题
|
||||||
|
|
||||||
|
#### 问题
|
||||||
|
|
||||||
|
使用 `ChatStream` 时,工具调用结果不显示。
|
||||||
|
|
||||||
|
#### 原因分析
|
||||||
|
|
||||||
|
1. 工具调用结果不在流式响应中返回,而是通过 `bus.PublishOutbound()` 单独发送
|
||||||
|
2. `ChatStream` 的 `onChunk` 回调只处理文本内容,不处理工具调用
|
||||||
|
3. 工具调用在 `runTurn` 循环中执行,结果通过消息总线发送
|
||||||
|
|
||||||
|
#### 解决方案
|
||||||
|
|
||||||
|
回退使用 `ProcessDirect`,因为它会正确处理:
|
||||||
|
- 工具调用流程
|
||||||
|
- 工具结果显示
|
||||||
|
- Markdown 渲染和按行输出
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 16. 状态栏优化
|
||||||
|
|
||||||
|
#### 改动内容
|
||||||
|
|
||||||
|
- 图标:`▣`
|
||||||
|
- 图标颜色:`#f0c75e`
|
||||||
|
- 文字颜色:`#2b2e32`
|
||||||
|
- 内容:只显示耗时,如 `▣ 耗时: 2.3s`
|
||||||
|
|
||||||
|
#### 之前 vs 之后
|
||||||
|
|
||||||
|
- 之前:`▣ Tokens: 120 · 耗时: 2.3s · 总Tokens: 350`
|
||||||
|
- 之后:`▣ 耗时: 2.3s`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 17. 项目配置文件详解
|
||||||
|
|
||||||
|
#### project.config.yml 结构
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# hxclaw 项目配置文件
|
||||||
|
|
||||||
|
# 模拟流式输出配置
|
||||||
|
streaming:
|
||||||
|
line_delay_ms: 1000 # 每行输出后的延迟(毫秒)
|
||||||
|
last_line_delay_ms: 600 # 最后一行延迟(毫秒)
|
||||||
|
|
||||||
|
# Markdown 渲染配置
|
||||||
|
markdown:
|
||||||
|
glamour_style: dark # 渲染主题:dark, light, dracula, tokyo-night 等
|
||||||
|
wrap_width: 0 # 自动换行宽度(0=自动获取终端宽度)
|
||||||
|
|
||||||
|
# UI 配置
|
||||||
|
ui:
|
||||||
|
logo: "🦐" # Logo
|
||||||
|
user_prefix: "👀 " # 用户输入前缀
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 配置加载优先级
|
||||||
|
|
||||||
|
1. 环境变量 `HXCLAW_CONFIG` 指定路径
|
||||||
|
2. 项目根目录 `project.config.yml`
|
||||||
|
|
||||||
|
#### 代码实现
|
||||||
|
|
||||||
|
```go
|
||||||
|
// internal/config.go
|
||||||
|
type ProjectConfig struct {
|
||||||
|
Streaming StreamingConfig `yaml:"streaming"`
|
||||||
|
Markdown MarkdownConfig `yaml:"markdown"`
|
||||||
|
UI UIConfig `yaml:"ui"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func getConfigPath() string {
|
||||||
|
if path := os.Getenv("HXCLAW_CONFIG"); path != "" {
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
return filepath.Join(".", "project.config.yml")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 18. 行业经验参考
|
||||||
|
|
||||||
|
#### CLI 动画最佳实践
|
||||||
|
|
||||||
|
- 帧率:75ms/帧(约 13fps)- GitHub Copilot CLI
|
||||||
|
- Spinner 动画:70-120ms - ora 库
|
||||||
|
- AI 流式输出:30-80ms/字符或行
|
||||||
|
- 总动画时长:控制在 3 秒内 - Copilot CLI 原则
|
||||||
|
|
||||||
|
#### 关键结论
|
||||||
|
|
||||||
|
- 人眼需要约 30-50ms 才能感知单次视觉变化
|
||||||
|
- 空白字符不应逐个输出,应批量处理
|
||||||
|
- 终端宽度 100% 时 Markdown 渲染会显著增加行数和字符数
|
||||||
Reference in New Issue
Block a user