bricks/docs/cn/llm_dialog.md
2025-10-12 17:59:59 +08:00

12 KiB
Raw Blame History

bricks.js 技术文档LlmDialog 模块

版本1.0
模块名称LlmDialog, LlmMsgBox, UserMsgBox, 工具函数 escapeSpecialChars
依赖框架bricks.js 前端组件库(基于类的 UI 架构)


📚 概述

该模块提供了一套用于构建与 LLM大语言模型交互对话界面的组件系统支持多模型并行响应、流式/同步响应模式、Markdown 渲染以及消息内容转义。主要包含以下核心类:

  • bricks.escapeSpecialChars:字符串特殊字符转义工具。
  • bricks.UserMsgBox:用户消息展示组件。
  • bricks.LlmMsgBoxLLM 回应消息展示及请求处理组件。
  • bricks.LlmDialog:主对话容器,管理整个对话流程。

此外,通过 bricks.Factory.register 注册了 LlmDialog 以便动态创建。


🔧 工具函数

bricks.escapeSpecialChars(s)

对输入字符串中的特殊字符进行反斜杠转义,常用于防止 JSON 注入或确保文本安全输出。

参数

参数 类型 描述
s string 待转义字符串

返回值

  • 类型string
  • 转义后的字符串,适用于嵌入 JSON 或 HTML 环境。

支持转义的字符

字符 原始表示 转义后表示 说明
\ \ \\ 反斜杠
" " \" 双引号
\n 换行 \n 换行符
\r 回车 \r 回车符
\t 制表符 \t Tab
\f 换页 \f Form feed
\v 垂直制表 \v Vertical tab
\0 空字符 \0 Null byte

⚠️ 注意:单引号 ' 的转义代码被注释,当前未启用。

示例

bricks.escapeSpecialChars('Hello "world"\n'); 
// 输出: 'Hello \\"world\\"\\n'

💬 用户消息组件:UserMsgBox

继承自 bricks.HBox,用于显示用户发送的消息。

继承关系

class UserMsgBox extends bricks.HBox

构造函数:constructor(opts)

参数 opts

属性 类型 必需 默认值 描述
icon string imgs/chat-user.svg 用户头像 SVG 图标 URL
prompt string - 用户输入的消息内容
msg_css string 'user_msg' 应用到消息体的 CSS 类名

内部结构

  1. 创建一个 SVG 头像图标(使用 bricks.Svg)。
  2. 使用 MdWidget 显示 Markdown 格式消息。
  3. 添加左侧空白图标占位符(BlankIcon),保持布局对齐。
  4. 消息排列顺序:[BlankIcon] ← [消息内容] ← [用户头像]

示例实例化

new bricks.UserMsgBox({
  prompt: "你好,请介绍一下你自己。",
  icon: "/icons/user.svg",
  msg_css: "custom-user-style"
});

🤖 LLM 消息组件:LlmMsgBox

继承自 bricks.HBox,用于展示 LLM 的回复,并支持流式和同步两种响应方式。

继承关系

class LlmMsgBox extends bricks.HBox

构造函数:constructor(opts)

参数 opts

属性 类型 必需 默认值 描述
model string - 使用的模型名称(如 gpt-3.5-turbo
mapi string - API 类型标识(可用于后端路由判断)
url string - 请求后端接口地址
icon string imgs/user.png LLM 头像图标 URL
msg_css string 'llm_msg' 消息区域应用的 CSS 类
response_mode string 'stream' 响应模式:'stream', 'sync', 'async'
user_msg object {role:'user', content:"${prompt}"} 用户消息模板,支持 ${prompt} 插值
llm_msg object {role:'assistant', content:"${content}"} LLM 消息模板,支持 ${content} 插值

内部初始化逻辑

  • 创建头像图标SVG
  • 初始化 MdWidget 显示消息内容
  • 加载 BaseRunning 动画组件(在响应中显示加载状态)
  • 初始化消息历史数组 this.messages = []

消息排列顺序

[LLM头像] → [运行动画] → [消息内容] → [空白占位符]


方法列表

responsed()

标记响应已开始,停止加载动画,移除运行指示器。

this.run.stop_timepass();
this.remove_widget(this.run);

user_msg_format()

生成用户消息对象格式。

  • 若设置了 this.user_msg,则返回其值;
  • 否则返回默认模板:{role: 'user', content: "${prompt}"}

实际内容将在调用时通过 bricks.apply_data() 替换 ${prompt}

llm_msg_format()

生成 LLM 消息对象格式。

  • 若设置了 this.llm_msg,返回其值;
  • 否则返回:{role: 'assistant', content: "${content}"}

chunk_response(l)

处理流式响应中的每一个数据块chunk

参数
  • l: JSON 字符串片段(通常来自 ReadableStream
行为
  1. 解析 JSON 数据。
  2. 若无 content 字段或为空,忽略。
  3. 累加内容至当前消息。
  4. 更新 MdWidget 内容。
  5. 触发 updated 事件。

chunk_ended()

流式响应结束后,将最终内容保存为结构化消息并推入 messages 数组。

  • 调用 escapeSpecialChars 对内容转义
  • 使用 apply_data 填充模板
  • 推入 this.messages

async set_prompt(prompt)

发起对 LLM 的请求。

参数
  • prompt: 用户输入文本(自动转义)
流程
  1. 将用户消息按模板格式化并加入 messages
  2. 准备请求参数:
    {
      messages: this.messages,
      mapi: this.mapi,
      model: this.model
    }
    
  3. 根据 response_mode 执行不同请求策略:
模式 行为说明
stream 使用 HttpResponseStream 发起 POST 请求,逐块接收并渲染
sync 使用 HttpJson 同步获取完整响应,一次性渲染结果
其他 不做任何操作(预留扩展)
示例调用
await llmMsgBox.set_prompt("请写一首关于春天的诗");

🧩 主对话框组件:LlmDialog

继承自 bricks.VBox,是完整的聊天对话界面容器,支持多模型同时响应。

继承关系

class LlmDialog extends bricks.VBox

构造函数:constructor(opts)

参数 opts

属性 类型 必需 默认值 描述
models array - 模型配置数组,每个元素定义一个 LLM 模型
response_mode string 'stream' 全局响应模式:'stream', 'sync', 'async'
user_msg_css string 'user_msg' 用户消息使用的 CSS 类
user_icon string - 用户头像图标路径
title_ccs string 'llm_title' 标题栏 CSS 类(拼写疑似错误,应为 title_css
height string '100%' 容器高度

models 数组项结构

{
  model: "gpt-3.5-turbo",
  mapi: "openai",
  url: "/api/openai/chat",
  icon: "/icons/gpt.svg",
  css: "gpt-response",
  user_msg: { role: "user", content: "${prompt}" },
  llm_msg: { role: "assistant", content: "${content}" }
}

方法列表

show_models_info()

遍历所有模型,调用 show_model_info(model) 在标题栏显示模型信息。

show_model_info(model)

在顶部标题区添加一个 HBox包含模型图标和名称。

  • 使用 Svg 显示图标
  • 使用 Text 显示模型名
  • 存储引用到 this.model_info_ws[model.model]

add_model(model)

动态添加新模型配置,并立即显示在标题栏。

delete_model(model)

根据 model.model 名称删除模型及其视图。

async set_prompt(prompt)

主入口方法:发送用户消息并触发所有模型响应。

步骤
  1. 转义用户输入。
  2. 创建并添加 UserMsgBox 到滚动面板。
  3. 调用 llm_request(prompt) 并等待完成。
  4. 自动滚动到底部。

async llm_request(prompt)

为每个注册的模型创建一个 LlmMsgBox,并异步启动请求。

  • 使用 schedule_once(fn, 0.1) 延迟执行以避免阻塞 UI
  • 所有模型并行响应

事件机制

llm_answer 事件

当某个模型完成响应后,可通过监听此事件获取回答内容。

当前代码中未显式触发 llm_answer 事件,需补充如下代码才能生效:

// 在 chunk_ended 或 sync 响应结束处添加:
this.fire('llm_answer', { content: txt });

建议增强事件通知能力。


🏗️ 工厂注册

bricks.Factory.register('LlmDialog', bricks.LlmDialog);

允许通过字符串标识动态创建组件:

var dialog = bricks.Factory.create('LlmDialog', options);

使用示例

var dialog = new bricks.LlmDialog({
  height: '600px',
  user_icon: '/icons/me.svg',
  title_ccs: 'chat-title',
  response_mode: 'stream',
  models: [
    {
      model: 'gpt-3.5-turbo',
      mapi: 'openai',
      url: '/api/chat',
      icon: '/icons/gpt.svg',
      css: 'gpt-msg',
      user_msg: { role: 'user', content: '${prompt}' },
      llm_msg: { role: 'assistant', content: '${content}' }
    },
    {
      model: 'claude-2',
      mapi: 'anthropic',
      url: '/api/anthropic',
      icon: '/icons/claude.svg',
      css: 'claude-msg'
    }
  ]
});

document.body.appendChild(dialog.dom_element);

// 发送消息
dialog.set_prompt("解释什么是机器学习");

📝 注意事项与改进建议

项目 说明
🔐 安全性 escapeSpecialChars 有助于防止注入,但建议结合 DOMPurify 或其他 sanitizer 进一步防护 XSS
🧩 单引号转义 被注释掉,若需兼容 SQL 或属性字符串场景,建议启用
🎯 事件缺失 llm_answer 事件未实际触发,建议在 chunk_ended() 中补全
🖼️ 图标资源 依赖 bricks_resource() 函数解析静态资源路径,需确保其存在
异步控制 schedule_once(..., 0.1) 是一种 Hack可考虑改为 queueMicrotaskPromise.resolve().then()
📏 布局兼容 使用 FlexboxHBox/VBox确保父级容器设置正确尺寸

📚 总结

本模块提供了完整的前端 LLM 聊天对话解决方案,具备以下特性:

多模型支持
流式 & 同步响应
Markdown 渲染
自动滚动与加载动画
可扩展模板机制

适合集成进低代码平台、AI 助手界面、多模型对比测试工具等场景。


文档版本1.0
最后更新2025年4月5日