V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
爱意满满的作品展示区。
acbox
V2EX  ›  分享创造

ChatTutor - 一个基于 DSL 的可视化可交互 AI 教师

  •  
  •   acbox · 11 小时 15 分钟前 · 318 次点击

    原文标题“关于 ChatTutor ,我们做了什么”,发布在 ChatTutor 的文档上,请参考 https://docs.chattutor.app/blog/2025-11-20.html

    Hi, 这里是 Acbox ,ChatTutor 的作者,以下是我的各种平台账号,可以通过这些账号获得最新的动态

    最近,我开源了我的项目 ChatTutor, 在 15 天内获得了 600+ stars (截止写稿日已有 641 个 stars ),并在开源圈和 AI 圈收获了一些热度。这篇博客我将会系统性的介绍 ChatTutor ,包括

    1. 什么是 ChatTutor, 他和一些传统的 ChatBot 有什么不同,他和类似 VideoTutor, Code2Video 之类的产品又有什么不同
    2. 关于 Multi-Agent - Teacher 与 Painter
    3. 关于 DSL - 绘图引擎如何驱动? Agent 如何用响应式变量与用户交互?

    什么是 ChatTutor

    ChatTutor 是一个可以使用白板的老师 Agent ,通过工具调用的形式将数学图形,笔记注释,思维导图绘制在像是幻灯片一样的多页白板上

    demo

    我们希望模仿真实的老师上课时的样子,通过画图->讲解->距离,来让学生逐步掌握知识。期间,学生可以打断,并向老师提出问题,老师可以对上一步的白班作出修改或新建页面来解释学生的疑问

    他和 VideoTutor, Code2Video 这类产品有什么不同

    这类产品有一个共同点:都是基于 Manim 进行渲染的。Manim 是 Youtube 博主@3blue1brown基于 Python 开发的一个数学动画引擎,通过 Python 代码来生成一个精美的科普视频。

    VideoTutor 和 Code2Video 通过复杂的工作流,让 LLM 去生成 Python 代码,并最终渲染成视频。

    ChatTutor 实现了一个 DSL 语法,大量模仿了现代前端框架的设计,并实现了一些组件库,关于 DSL, 请参考[这个小节](#关于 dsl---响应式)

    VideoTutor 和 Code2Video 的最终产物都是视频,用户无法与其交互,也无法基于视频里的图形做二次修改。ChatTutor 所渲染的图形都是可交互的,且全部渲染在前端,不需要考虑视频编译的时间,且可以通过与用户的交互产生反应。

    Multi-Agent: Teacher 模型与 Painter 模型

    我们使用了 Multi-Agent 架构来拆分他们的任务,其中:

    • Teacher: 用户所在右侧看到的输出
    • Painter: 负责绘图的 LLM, 可以输出 DSL 语法

    Teacher 可以通过工具调用的形式输入自然语言,并通过 Painter 输出 DSL 语法

    graph TB
      T{Teacher Agent} ---> P{Painter Agent}
      T ---> M(Mermaid)
      T ---> N(Note)
      T ---> C(Code)
    

    目前的 Painter 使用提示词方案,未来有考虑模型训练,也考虑单独把 Painter 拆成一个 api 服务,让别的应用可以使用 Painter 并将图形渲染到自己的网页

    关于 DSL - 响应式

    我们使用了@vue/reactivity作为 DSL 的响应式基础,并且大量模仿了现代前端框架的设计

    我们同时也写了很多数学组件和动画,未来将会增加物理,电路,化学等学科的图形支持

    就比如,三角形 ABC ,Painter 输出的 DSL Document 看起来会像是这样的:

    Teacher 给 Painter 的提示词:Draw a simple triangle, A = (0, 0), B = (3, 4), C = (1, 2)

    ---
    refs:
      x_A: '0'
    ---
    <plane :range="[-1, 5]" :domain="[-1, 4]">
      <polygon type="line" :points="[[x_A, 0], [3, 4], [1, 2], [x_A, 0]]" color="primary"/>
      
      <dot :x="x_A" :y="0" color="primary" label="A" />
      <dot :x="3" :y="4" color="primary" label="B" />
      <dot :x="1" :y="2" color="primary" label="C" />
    </plane>
    

    文档包含一个 yaml 头,有一个 refs 的定义,即响应式变量,这个 x_A 最终会被渲染在前端并暴露给用户。用户和 Teacher 都可以操作这个变量。当 x_A 被更新时,A 点的坐标也会被改变

    同时,Painter 支持一个键-值类型的参数,可以手动指定 <变量名>-<变量描述>,然后 Painter 就会把你指定的变量名暴露出来

    我们来看一个更具体的例子:

    Input:

    Draw a unit circle (radius 1) centered at the origin. Draw the x and y axes with labels.
    Draw a radius from the origin making an angle theta with the positive x-axis, where theta is a reactive variable starting at π/4. At the end of this radius, mark a point P. From point P, draw a vertical line down to the x-axis to form a right triangle.
    Label the horizontal distance as cos(theta) and the vertical distance as sin(theta).
    Draw and label the angle theta at the origin. Also show the coordinates of point P as (cos θ, sin θ).
    Use different colors: circle in gray, radius in blue, the right triangle sides in green, and point P in red.`
    

    Exposes: {"theta": "角度 theta (弧度)"}

    ---
    refs:
      theta: 'Math.PI / 4'
    ---
    <plane :range="[-1.5, 1.5]" :domain="[-1.5, 1.5]" axis grid>
      <!-- Unit circle in gray -->
      <parameter 
        :value="(t) => [Math.cos(t), Math.sin(t)]" 
        :domain="[0, 2 * Math.PI]" 
        color="gray"
      />
      
      <!-- Point P at (cos(theta), sin(theta)) in red -->
      <dot 
        :x="Math.cos(theta)" 
        :y="Math.sin(theta)" 
        color="red" 
        label="P"
        labelColor="red"
      />
      
      <!-- Radius from origin to P in blue -->
      <line 
        :from="[0, 0]" 
        :to="[Math.cos(theta), Math.sin(theta)]" 
        color="blue"
      />
      
      <!-- Vertical line from P down to x-axis (green) -->
      <line 
        :from="[Math.cos(theta), Math.sin(theta)]" 
        :to="[Math.cos(theta), 0]" 
        color="green"
      />
      
      <!-- Horizontal line from origin to projection point (green) -->
      <line 
        :from="[0, 0]" 
        :to="[Math.cos(theta), 0]" 
        color="green"
      />
      
      <!-- Angle theta at origin -->
      <angle 
        :start="[1, 0]" 
        :end="[Math.cos(theta), Math.sin(theta)]" 
        :origin="[0, 0]" 
        color="blue"
        label="θ"
      />
      
      <!-- Label for cos(theta) on x-axis -->
      <label 
        :x="Math.cos(theta) / 2" 
        :y="-0.15" 
        content="\cos(\theta)" 
        color="green"
      />
      
      <!-- Label for sin(theta) on y-axis -->
      <label 
        :x="Math.cos(theta) + 0.2" 
        :y="Math.sin(theta) / 2" 
        content="\sin(\theta)" 
        color="green"
      />
      
      <!-- Coordinates of point P -->
      <label 
        :x="Math.cos(theta) + 0.3" 
        :y="Math.sin(theta) + 0.2" 
        content="(\cos\theta, \sin\theta)" 
        color="red"
      />
    </plane>
    

    demo

    当 Teacher 让 Painter 做完这一切后,如图,Teacher 调用其他工具创建了一个滑动条,当用户改变滑动条的值时,角度就会改变

    我们正在计划准备给 Teacher 更多工具允许他自己操控这些组件

    结尾

    这就是这个博客的全部内容了,希望大家如果感兴趣可以来体验一下,并在 GitHub 上点一个 Star

    GitHub: https://github.com/sheepbox8646/ChatTutor 在线体验(需要填写 apikey ):https://chattutor.app

    目前尚无回复
    关于   ·   帮助文档   ·   自助推广系统   ·   博客   ·   API   ·   FAQ   ·   Solana   ·   5464 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 21ms · UTC 06:03 · PVG 14:03 · LAX 22:03 · JFK 01:03
    ♥ Do have faith in what you're doing.