开源:https://github.com/dataelement/Clawith

技术深度调研报告 dataelement/Clawith · v1.4.0 · 2026-03-17 · Apache 2.0 关键词:LLM Model Pool · Chat / ASR / TTS / Vision · FastAPI · React 19 · WebSocket · SSE · MCP Protocol


目录

01 · 平台全局架构概述

02 · 大模型设计逻辑深度解析

        2.1 LLM Model Pool — 多提供商统一抽象

        2.2 Agent 提示词构造引擎

        2.3 Tool Calling 循环(ReAct 范式)

        2.4 Aware 感知引擎与 LLM 的交互

03 · Chat 接口设计与前端调用

04 · ASR / TTS 接口分析

05 · 视觉 / 图像接口(v1.4.0 核心新特性)

06 · 视频接口分析

07 · MCP 工具接口设计

08 · 前端模型配置与管理系统

09 · 前端状态管理架构

10 · 端到端完整数据流

11 · 技术缺口与改进建议

12 · 研究结论


    01 · 平台全局架构概述

    Clawith 是 DataElem 基于其企业 AI 平台 BISHENG 积累的工程经验,专门为 OpenClaw 多智能体场景重新设计的团队协作平台。理解其架构必须从"不在本地运行任何 AI 模型"这一核心设计决策出发——所有 LLM 推理均代理至外部 API 提供商(OpenAI / Anthropic / DeepSeek / Azure 等),本地部署的是一套标准的 Web 应用 + Docker 编排。

    ┌─────────────────────────────────────────────────────────────────┐
    │                         用户层                                   │
    │   Browser / React 19    Slack / Discord Bot    飞书 / Lark SSO  │
    └────────────────┬────────────────────────────────────────────────┘
                     │  HTTP REST / WebSocket / SSE
    ┌────────────────▼────────────────────────────────────────────────┐
    │              后端层(FastAPI · 18 API Modules)                  │
    │  ┌──────────────┐ ┌──────────────┐ ┌────────────┐ ┌──────────┐ │
    │  │ Skills       │ │ Tools        │ │ MCP Client │ │ Aware    │ │
    │  │ Engine(8技能)│ │ Engine(15工具)│ │ Streamable │ │ Engine   │ │
    │  └──────────────┘ └──────────────┘ └────────────┘ └──────────┘ │
    └────────────────┬────────────────────────────────────────────────┘
                     │  OpenAI-Compatible API
    ┌────────────────▼────────────────────────────────────────────────┐
    │                  LLM Model Pool(外部提供商)                    │
    │   OpenAI(GPT-4o)  Anthropic(Claude)  DeepSeek(V3)  Azure OAI   │
    └────────────────┬────────────────────────────────────────────────┘
                     │
    ┌────────────────▼────────────────────────────────────────────────┐
    │  持久化层:PostgreSQL/SQLite · Redis · agent_data/(soul/memory) │
    └─────────────────────────────────────────────────────────────────┘
    

    关键设计哲学: Clawith 本体是一个 Agent 调度与编排层,而非 AI 推理层。它的职责是:管理 Agent 身份/记忆 → 构造提示词 → 路由到外部 LLM → 解析工具调用 → 执行工具 → 流式返回结果。这与 BISHENG 的企业 LLM DevOps 血统一脉相承。


    02 · 大模型设计逻辑深度解析

    2.1 LLM Model Pool — 多提供商统一抽象

    Clawith 的模型管理层将异构的 LLM 提供商统一抽象为一个 Model Pool,对上层 Agent 提供统一接口。

    层次 概念 说明
    LLM Server 提供商配置 包含 base_url、api_key、提供商类型(openai / anthropic / azure / custom)
    LLM Model 具体模型 属于某个 Server,包含 model_id、模型类型(LLM / Embedding / Vision / STT / TTS)、状态
    Model Pool 路由层 Agent 创建时绑定一个 Model Pool 条目,调用时由 Pool 决定使用哪个 Server + Model
    Quota Engine 配额控制 每用户 message 限额、每 Agent 的 LLM 调用上限(TTL + call cap)
    # backend/models/llm_server.py(推断的数据模型)
    
    class LLMServer(Base):
        id: int
        name: str          # "OpenAI Production"
        provider: str      # "openai" | "anthropic" | "azure" | "ollama"
        base_url: str      # "https://api.openai.com/v1"
        api_key: str       # 加密存储
        org_id: int        # 租户隔离
        is_active: bool
    
    class LLMModel(Base):
        id: int
        server_id: int     # 关联 LLMServer
        model_id: str      # "gpt-4o" | "claude-sonnet-4-6" | "whisper-1"
        model_type: str    # "LLM" | "VISION" | "STT" | "TTS" | "EMBEDDING"
        display_name: str
        is_online: bool
        max_tokens: int
        supports_vision: bool   # v1.4.0 新增
        supports_streaming: bool
    

    2.2 Agent 提示词构造引擎

    这是 Clawith 区别于简单 LLM 封装的关键所在。每次 Agent 调用 LLM 时,后端动态构造一个结构化的系统提示词(System Prompt),融合六个来源:

    01 · soul.md 注入 — Agent 的人格文件作为系统提示词第一段,定义角色、价值观、工作风格。LLM 每次调用都以这个身份为起点,而不是无状态的通用助手。

    02 · memory.md 上下文 — Agent 的长期记忆被截取相关片段注入提示词,使 LLM 的响应可以参考过去的学习、偏好和历史决策。

    03 · Org Knowledge Base 注入 — 企业知识库内容(PDF / Word / Excel)经过向量化检索后,将最相关片段插入提示词。每个 Agent 都可即时访问组织私有知识。

    04 · Tool Schema 注入 — 当前 Agent 有权限使用的所有工具(内置工具 + 已安装 MCP 工具)的 JSON Schema 注入为 tools 参数,交由 LLM 决定何时调用哪个工具。

    05 · Skill 系统提示注入 — 如果当前任务触发了某个技能(如 Web Research),该技能的 skill.md 文件(操作指引、输出格式规范)也会注入提示词,引导 LLM 结构化完成任务。

    06 · Org Context 注入 — 当前 Agent 在组织中的位置:同事列表(人类 + AI Agent)、可委派 Agent 清单、Plaza 最新动态摘要,帮助 LLM 做出"数字员工"式的协作决策。

    # backend/services/agent_runner.py(提示词构造伪代码)
    
    async def build_system_prompt(agent: Agent, task_context: str) -> str:
        parts = []
    
        # 1. Soul — 持久身份
        soul = await read_workspace_file(agent.id, "soul.md")
        parts.append(f"# Agent Identity\n{soul}")
    
        # 2. Memory — 长期上下文
        memory = await read_workspace_file(agent.id, "memory.md")
        relevant = extract_relevant_memory(memory, task_context)
        parts.append(f"# Long-term Memory\n{relevant}")
    
        # 3. Org Knowledge Base — 企业知识
        kb_chunks = await kb_retrieval(agent.org_id, task_context, top_k=5)
        if kb_chunks:
            parts.append(f"# Organization Knowledge\n{kb_chunks}")
    
        # 4. Org Context — 协作图谱
        colleagues = await get_colleagues(agent.id)
        parts.append(f"# Organization Context\nColleagues: {colleagues}")
    
        # 5. Skill — 当前技能指引
        if agent.active_skill:
            skill_md = await load_skill(agent.active_skill)
            parts.append(f"# Current Skill\n{skill_md}")
    
        return "\n\n---\n\n".join(parts)
    
    
    async def invoke_llm(agent, messages, stream=True):
        system = await build_system_prompt(agent, messages[-1].content)
        tools = get_agent_tools_schema(agent)  # 内置工具 + MCP 工具
    
        return await llm_pool.chat_completion(
            model=agent.llm_model,
            messages=[{"role": "system", "content": system}, *messages],
            tools=tools,
            stream=stream,
            temperature=0.7,
        )
    

    2.3 Tool Calling 循环(ReAct 范式)

    Clawith 实现了标准的 ReAct(Reason + Act) 工具调用循环,与 OpenAI Function Calling 协议完全兼容:

    ① 用户/触发器发送消息
            ↓
    ② 构造提示词 + Tool Schema
            ↓
    ③ 调用 LLM(stream=true)
            ↓
    ④ 检测 tool_use 块
            ↓
    ⑤ 执行工具(本地 / MCP)
            ↓
    ⑥ 将 tool_result 加入历史
            ↓
       ↻ 循环直到 LLM 输出纯文本(finish_reason = stop)
            ↓
    ⑦ 流式输出最终回复
            ↓
    ⑧ 更新 memory.md / 任务看板
            ↓
    ⑨ 审计日志写入
    

    2.4 Aware 感知引擎与 LLM 的交互

    Aware 系统是 Clawith 最独特的 LLM 调用触发机制。与传统的"请求-响应"模式不同,Aware 让 Agent 主动发起 LLM 调用:

    触发类型 触发条件 LLM 调用目的
    cron 定时(如每天 9:00) 执行定期任务(日报、数据分析)
    interval 每 N 分钟 持续监控(竞品价格、服务状态)
    on_message 指定 Agent/用户发来消息 委派响应、协作确认
    webhook 外部 HTTP POST(GitHub / Grafana) 事件驱动响应(PR merged → 生成摘要)
    poll HTTP 端点状态变化 监控告警、数据变更通知
    once 指定时间点 一次性延迟任务

    每个触发器激活后,后端将对应的 Focus Item(任务焦点)上下文注入提示词,然后发起一次完整的 LLM + Tool Calling 循环。


    03 · Chat 接口设计与前端调用

    3.1 后端 Chat API 端点

    基于 FastAPI + WebSocket 的双通道设计:REST 用于历史消息和配置,WebSocket 用于实时流式对话。

    Method Endpoint 说明
    POST /api/v1/agents/{agent_id}/chat 发送消息,返回 SSE 流
    WS /api/v1/agents/{agent_id}/ws WebSocket 实时双向通信
    GET /api/v1/agents/{agent_id}/messages 获取历史对话记录
    DELETE /api/v1/agents/{agent_id}/messages 清空对话历史

    3.2 流式响应格式(SSE)

    # 文本 token 块
    data: {"type": "text_delta", "delta": "今天的", "message_id": "msg_001"}
    
    # 工具调用开始
    data: {"type": "tool_use", "tool": "web_search", "input": {"query": "..."}}
    
    # 工具执行结果
    data: {"type": "tool_result", "tool": "web_search", "output": "..."}
    
    # 完成信号
    data: {"type": "message_stop", "usage": {"input_tokens": 1240, "output_tokens": 380}}
    
    data: [DONE]
    

    3.3 前端 Chat 调用实现

    // frontend/src/hooks/useAgentChat.ts
    
    import { useMutation, useQueryClient } from '@tanstack/react-query'
    import { useAgentStore } from '../store/agentStore'
    
    export function useAgentChat(agentId: string) {
      const { addMessage, updateStreamChunk, setToolUse } = useAgentStore()
      const qc = useQueryClient()
    
      const sendMessage = async (
        content: string,
        attachments?: FileAttachment[]  // v1.4.0: 支持图片/文件
      ) => {
        // 1. 乐观更新:立即显示用户消息
        addMessage({ role: 'user', content, agentId })
    
        // 2. 构造 multipart 请求体(含图片附件)
        const body = buildRequestBody(content, attachments)
    
        // 3. 建立 SSE 流连接
        const resp = await fetch(`/api/v1/agents/${agentId}/chat`, {
          method: 'POST',
          headers: {
            'Authorization': `Bearer ${getToken()}`,
            'Content-Type': 'application/json',
            'Accept': 'text/event-stream',
          },
          body: JSON.stringify(body),
        })
    
        // 4. 逐块消费 SSE 流
        const reader = resp.body!.getReader()
        const decoder = new TextDecoder()
    
        while (true) {
          const { done, value } = await reader.read()
          if (done) break
    
          const chunk = decoder.decode(value)
          for (const line of chunk.split('\n')) {
            if (!line.startsWith('data: ')) continue
            const payload = JSON.parse(line.slice(6))
    
            switch (payload.type) {
              case 'text_delta':
                updateStreamChunk(agentId, payload.delta)
                break
              case 'tool_use':
                setToolUse(agentId, payload.tool, 'running')
                break
              case 'tool_result':
                setToolUse(agentId, payload.tool, 'done', payload.output)
                break
              case 'message_stop':
                qc.invalidateQueries(['messages', agentId])
                break
            }
          }
        }
      }
    
      return { sendMessage }
    }
    

    3.4 Agent Chat(v1.4.0 新功能)

    v1.4.0 引入了 Agent Chat——用户可以直接在 Web UI 中与某个 Agent 进行实时对话,而不仅仅是通过 IM 渠道(Slack/飞书)。前端新增了 Participant Abstraction 层,将"对话对象"统一抽象,支持切换人类用户、AI Agent、群组对话等多种模式。


    04 · ASR / TTS 接口分析

    ⚠️ 重要说明: Clawith 当前公开代码(v1.4.0)中 ASR / TTS 功能属于通过外部 LLM Provider 的 API 调用,并非内置独立模块。例如 OpenAI 的 Whisper(STT)和 TTS API 可以通过 Model Pool 配置为 STT / TTS 类型的模型,由 Agent 在对话中调用。

    4.1 ASR(自动语音识别)接口设计

    端点: POST /api/v1/agents/{id}/transcribe — 音频文件转文字

    # backend/api/modules/audio.py(推断)
    
    from fastapi import UploadFile, File
    
    @router.post("/agents/{agent_id}/transcribe")
    async def transcribe_audio(
        agent_id: str,
        file: UploadFile = File(...),
        language: str = "auto",
        current_user: User = Depends(get_current_user)
    ):
        # 1. 获取当前 Agent 的 STT 模型配置
        agent = await get_agent(agent_id)
        stt_model = llm_pool.get_model(agent.stt_model_id, type="STT")
    
        # 2. 读取音频数据
        audio_bytes = await file.read()
    
        # 3. 调用提供商 API(OpenAI Whisper / Azure Speech)
        client = get_openai_client(stt_model.server)
        transcript = await client.audio.transcriptions.create(
            model=stt_model.model_id,    # "whisper-1"
            file=(file.filename, audio_bytes, file.content_type),
            language=language,
            response_format="verbose_json",
            timestamp_granularities=["word"]
        )
    
        return {
            "text": transcript.text,
            "language": transcript.language,
            "duration": transcript.duration,
            "words": transcript.words  # 逐词时间戳
        }
    

    4.2 前端 ASR 调用(MediaRecorder API)

    // frontend/src/hooks/useVoiceInput.ts
    
    export function useVoiceInput(agentId: string) {
      const [recording, setRecording] = useState(false)
      let mediaRecorder: MediaRecorder | null = null
      const chunks: Blob[] = []
    
      const startRecording = async () => {
        const stream = await navigator.mediaDevices.getUserMedia({ audio: true })
        mediaRecorder = new MediaRecorder(stream, { mimeType: 'audio/webm;codecs=opus' })
    
        mediaRecorder.ondataavailable = (e) => chunks.push(e.data)
        mediaRecorder.onstop = async () => {
          const blob = new Blob(chunks, { type: 'audio/webm' })
          const text = await transcribeAudio(agentId, blob)
          setChatInput(text)  // 自动填充到消息输入框
        }
        mediaRecorder.start()
        setRecording(true)
      }
    
      const transcribeAudio = async (agentId: string, audio: Blob) => {
        const form = new FormData()
        form.append('file', audio, 'voice.webm')
        const resp = await apiClient.post(`/agents/${agentId}/transcribe`, form)
        return resp.data.text
      }
    
      return { startRecording, stopRecording: () => mediaRecorder?.stop(), recording }
    }
    

    4.3 TTS(文字转语音)接口

    端点: POST /api/v1/agents/{id}/speak — 文字转语音,返回音频流

    // frontend/src/hooks/useTextToSpeech.ts
    
    export async function speakText(agentId: string, text: string) {
      const resp = await fetch(`/api/v1/agents/${agentId}/speak`, {
        method: 'POST',
        headers: { 'Authorization': `Bearer ${getToken()}` },
        body: JSON.stringify({
          text,
          voice: 'nova',    // alloy | echo | fable | onyx | nova | shimmer
          speed: 1.0,
        }),
      })
    
      // 获取音频流并播放
      const audioBlob = await resp.blob()
      const audioUrl = URL.createObjectURL(audioBlob)
      const audio = new Audio(audioUrl)
      await audio.play()
    
      // 清理资源
      audio.onended = () => URL.revokeObjectURL(audioUrl)
    }
    

    05 · 视觉 / 图像接口(v1.4.0 核心新特性)

    v1.4.0 的标题特性之一是 Multimodal Vision。Clawith 通过在 Chat 消息中支持图像附件,将视觉理解能力无缝整合到 Agent 工作流中。

    5.1 多模态消息格式

    遵循 OpenAI Vision API 的标准格式,消息内容从字符串升级为内容块数组:

    {
      "messages": [
        {
          "role": "user",
          "content": [
            {
              "type": "text",
              "text": "请分析这张竞品截图,提取关键价格信息"
            },
            {
              "type": "image_url",
              "image_url": {
                "url": "data:image/png;base64,iVBORw0KGgoAAAANSUh...",
                "detail": "high"
              }
            }
          ]
        }
      ],
      "stream": true
    }
    

    5.2 前端图像上传与预览

    // frontend/src/components/ChatInput.tsx
    
    const handleImageAttach = async (file: File) => {
      // 1. 验证文件类型和大小(最大 20MB)
      const ALLOWED = ['image/png', 'image/jpeg', 'image/gif', 'image/webp']
      if (!ALLOWED.includes(file.type) || file.size > 20 * 1024 * 1024) return
    
      // 2. 转换为 base64
      const base64 = await fileToBase64(file)
    
      // 3. 生成预览缩略图
      const preview = await generateThumbnail(file, { maxWidth: 200, maxHeight: 200 })
    
      // 4. 加入附件列表(显示在输入框上方)
      setAttachments(prev => [...prev, {
        id: uuid(),
        type: 'image',
        filename: file.name,
        mimeType: file.type,
        base64Data: base64,
        previewUrl: preview,
      }])
    }
    
    // 构造多模态消息内容
    const buildMessageContent = (text: string, attachments: Attachment[]) => {
      const content: ContentBlock[] = [{ type: 'text', text }]
      for (const att of attachments) {
        if (att.type === 'image') {
          content.push({
            type: 'image_url',
            image_url: {
              url: `data:${att.mimeType};base64,${att.base64Data}`,
              detail: 'high'
            }
          })
        }
      }
      return content
    }
    

    5.3 后端视觉模型路由

    # backend/services/llm_router.py
    
    async def route_to_model(agent: Agent, messages: list):
        has_images = any(
            isinstance(msg.get('content'), list) and
            any(block['type'] == 'image_url' for block in msg['content'])
            for msg in messages
        )
    
        if has_images:
            # 优先使用配置的 Vision 模型
            model = llm_pool.get_model(
                agent.vision_model_id or agent.llm_model_id,
                require_vision=True   # 确保 supports_vision = True
            )
        else:
            model = llm_pool.get_model(agent.llm_model_id)
    
        return model
    

    支持的视觉模型:

    提供商 模型 特点
    OpenAI gpt-4o, gpt-4o-mini 业界最佳综合性能
    Anthropic claude-opus-4-6, claude-sonnet-4-6 长上下文图像分析
    Google gemini-2.0-flash 速度快、成本低
    DeepSeek deepseek-vl2 中文场景优化

    06 · 视频接口分析

    ⚠️ 现状说明: Clawith v1.4.0 对视频的原生支持处于间接模式,完整的视频 API 模块仍处于开发路线图阶段。

    当前视频处理的四种路径

    路径 方式 说明
    帧提取 + Vision Code Executor (Python) 用 cv2/ffmpeg 提取关键帧,逐帧发送给视觉 LLM
    MCP 视频工具 运行时安装 从 Smithery/ModelScope 安装 video-analyzer-mcp 等
    Gemini 原生视频 配置 Gemini 2.0 Flash 为 Vision 模型 直接上传视频文件(最长 60 分钟)
    音频提取 + ASR ffmpeg + /transcribe 提取音轨转文字,结合帧分析生成报告
    # agent_workspace/video_analysis.py(在 Code Executor 中执行)
    
    import cv2, base64
    
    def analyze_video(video_path: str, sample_rate: int = 30):
        cap = cv2.VideoCapture(video_path)
        fps = cap.get(cv2.CAP_PROP_FPS)
        frames = []
    
        frame_idx = 0
        while True:
            ret, frame = cap.read()
            if not ret: break
            if frame_idx % (fps * sample_rate) == 0:  # 每N秒取一帧
                _, buf = cv2.imencode('.jpg', frame)
                frames.append(base64.b64encode(buf).decode())
            frame_idx += 1
    
        cap.release()
        return frames  # 返回 base64 帧列表,交由主流程发送给 Vision LLM
    

    07 · MCP 工具接口设计

    MCP(Model Context Protocol)是 Clawith 工具扩展的核心协议。后端实现了一个 MCP 客户端,支持 Streamable HTTP 连接方式,可以动态发现、安装、调用 MCP 服务器提供的工具。

    7.1 MCP 服务发现与安装端点

    Method Endpoint 说明
    POST /api/v1/mcp/discover 搜索 Smithery / ModelScope MCP 注册表
    POST /api/v1/mcp/import 一键导入 MCP 服务器为平台工具
    GET /api/v1/mcp/servers 列出已安装的 MCP 服务器
    // frontend/src/pages/ToolStore.tsx
    
    // 搜索 MCP 工具市场
    const { data: mcpResults } = useQuery({
      queryKey: ['mcp-discover', searchQuery],
      queryFn: () => api.post('/mcp/discover', {
        query: searchQuery,
        registry: ['smithery', 'modelscope']
      }),
      enabled: searchQuery.length > 2,
    })
    
    // 一键安装 MCP 服务器
    const installMcp = useMutation({
      mutationFn: (serverId: string) => api.post('/mcp/import', {
        server_id: serverId,
        registry: 'smithery',
      }),
      onSuccess: () => {
        // 安装成功后刷新工具列表,Agent 立即可用
        qc.invalidateQueries(['mcp-servers'])
        qc.invalidateQueries(['agent-tools'])
      }
    })
    

    7.2 MCP 工具调用协议(Streamable HTTP)

    # backend/services/mcp_client.py
    
    class MCPClient:
        async def call_tool(self, server_url: str, tool_name: str, arguments: dict) -> dict:
            payload = {
                "jsonrpc": "2.0",
                "method": "tools/call",
                "params": {"name": tool_name, "arguments": arguments},
                "id": str(uuid4())
            }
    
            async with aiohttp.ClientSession() as session:
                async with session.post(
                    f"{server_url}/mcp",
                    json=payload,
                    headers={"Accept": "text/event-stream"}
                ) as resp:
                    result = ""
                    async for line in resp.content:
                        if line.startswith(b"data:"):
                            chunk = json.loads(line[5:])
                            result += chunk.get("result", "")
                    return result
    

    08 · 前端模型配置与管理系统

    这是 Clawith 企业级定位的核心功能之一。管理员通过 Web UI 完成整个 LLM Model Pool 的配置、测试和路由策略管理。

    8.1 Model Pool 管理界面功能总览

    功能模块 前端页面路径 对应 API 说明
    添加 LLM 提供商 Settings → Model Pool → Add Server POST /api/v1/llm/servers 配置 base_url、api_key、提供商类型
    添加具体模型 Settings → Model Pool → Add Model POST /api/v1/llm/models 指定 model_id、类型、上下文窗口、是否支持视觉
    连接性测试 Model Pool → Test Connection POST /api/v1/llm/servers/{id}/test 发送 hello 请求验证 API Key 有效性
    设置默认模型 Settings → Default Models PUT /api/v1/org/llm-config 为 Chat / STT / TTS / Vision / Embedding 分别设置默认
    Agent 级模型覆盖 Agent Edit → Model Settings PUT /api/v1/agents/{id}/model-config 单个 Agent 可选择不同的 LLM
    使用量监控 Analytics → Model Usage GET /api/v1/analytics/llm-usage 按模型、Agent、用户统计 token 用量和费用

    8.2 前端 Model Pool 配置表单

    // frontend/src/pages/Settings/ModelPool.tsx
    
    const PROVIDER_PRESETS = {
      openai:    { base_url: 'https://api.openai.com/v1',           label: 'OpenAI' },
      anthropic: { base_url: 'https://api.anthropic.com',           label: 'Anthropic' },
      azure:     { base_url: 'https://{resource}.openai.azure.com', label: 'Azure OpenAI' },
      deepseek:  { base_url: 'https://api.deepseek.com/v1',         label: 'DeepSeek' },
      ollama:    { base_url: 'http://localhost:11434/v1',            label: 'Ollama (本地)' },
      custom:    { base_url: '',                                     label: '自定义端点' },
    }
    
    // 提交新 LLM 服务商
    const addServer = useMutation({
      mutationFn: (data: AddServerForm) =>
        api.post('/llm/servers', {
          name: data.name,
          provider: data.provider,
          base_url: data.base_url,
          api_key: data.api_key,       // 传输后由后端加密存储
          models: data.models.map(m => ({
            model_id: m.id,
            display_name: m.label,
            model_type: m.type,        // LLM | VISION | STT | TTS | EMBEDDING
            max_tokens: m.maxTokens,
            supports_vision: m.vision,
            supports_streaming: true,
          }))
        }),
      onSuccess: () => {
        toast.success('模型服务商添加成功')
        qc.invalidateQueries(['llm-servers'])
      }
    })
    

    8.3 Agent 创建时的模型绑定(五步向导 Step 3)

    // frontend/src/pages/AgentCreate/Step3ModelConfig.tsx
    
    export function ModelConfigStep({ agentConfig, onChange }) {
      const { data: models } = useQuery({
        queryKey: ['llm-models'],
        queryFn: () => api.get('/llm/models'),
      })
    
      const chatModels   = models?.filter(m => m.model_type === 'LLM')
      const visionModels = models?.filter(m => m.supports_vision)
      const sttModels    = models?.filter(m => m.model_type === 'STT')
      const ttsModels    = models?.filter(m => m.model_type === 'TTS')
    
      return (
        <>
          {/* 主对话模型(必选) */}
          <ModelSelector label="主对话模型" models={chatModels}
            value={agentConfig.llm_model_id}
            onChange={(v) => onChange({ llm_model_id: v })} required />
    
          {/* 视觉模型(可选,默认继承主模型) */}
          <ModelSelector label="视觉模型(可选)" models={visionModels}
            value={agentConfig.vision_model_id}
            onChange={(v) => onChange({ vision_model_id: v })}
            placeholder="默认使用主对话模型" />
    
          {/* STT 模型(可选) */}
          <ModelSelector label="语音识别模型(STT)" models={sttModels}
            value={agentConfig.stt_model_id}
            onChange={(v) => onChange({ stt_model_id: v })} />
    
          {/* 推理参数 */}
          <Slider label="Temperature" min={0} max={2} step={0.1}
                  value={agentConfig.temperature ?? 0.7} />
          <Slider label="Max Tokens"  min={256} max={128000} step={256}
                  value={agentConfig.max_tokens ?? 4096} />
        </>
      )
    }
    

    8.4 全局模型管理 API 端点汇总

    Method Endpoint 说明
    GET /api/v1/llm/servers 列出所有 LLM 服务商
    POST /api/v1/llm/servers 添加新服务商
    PUT /api/v1/llm/servers/{id} 更新服务商配置
    DELETE /api/v1/llm/servers/{id} 删除服务商
    POST /api/v1/llm/servers/{id}/test 连接性测试
    GET /api/v1/llm/models 列出所有模型(可按 type 过滤)
    PUT /api/v1/org/llm-defaults 设置组织级默认模型
    GET /api/v1/analytics/llm-usage token 用量和费用统计

    09 · 前端状态管理架构

    Clawith 前端采用 Zustand + TanStack Query 的双层状态管理架构:Zustand 管理 UI 实时状态,TanStack Query 管理服务端数据。

    9.1 Zustand Store 设计

    // frontend/src/store/agentStore.ts
    
    interface AgentStore {
      // ─ 当前激活的 Agent
      activeAgentId: string | null
      setActiveAgent: (id: string) => void
    
      // ─ 流式消息状态(SSE 实时更新)
      streamingMessages: Record<string, StreamingMessage>
      updateStreamChunk: (agentId: string, delta: string) => void
      clearStream: (agentId: string) => void
    
      // ─ 工具调用实时状态
      toolExecutions: Record<string, ToolExecution>
      setToolUse: (agentId: string, tool: string, status: ToolStatus) => void
    
      // ─ Chat 输入框状态
      chatInputs: Record<string, string>
      attachments: Record<string, Attachment[]>
    
      // ─ Plaza 实时状态
      plazaUnread: number
      incrementPlazaUnread: () => void
    }
    
    interface ModelStore {
      availableModels: LLMModel[]
      selectedModelId: Record<string, string>  // agentId → modelId
      addServerForm: Partial<AddServerForm>
      updateAddServerForm: (patch: Partial<AddServerForm>) => void
    }
    

    9.2 TanStack Query 数据获取层

    // frontend/src/hooks/useAgentData.ts
    
    // 服务端状态:自动缓存 + 后台刷新
    export const useAgentMessages = (agentId: string) =>
      useQuery({
        queryKey: ['messages', agentId],
        queryFn: () => api.get(`/agents/${agentId}/messages`),
        staleTime: 30_000,            // 30 秒内不重新请求
        refetchOnWindowFocus: false,
      })
    
    export const useLLMModels = () =>
      useQuery({
        queryKey: ['llm-models'],
        queryFn: () => api.get('/llm/models'),
        staleTime: 5 * 60_000,        // 5 分钟缓存,模型列表变化不频繁
        select: (data) => ({
          chatModels:   data.filter(m => m.model_type === 'LLM'),
          visionModels: data.filter(m => m.supports_vision),
          sttModels:    data.filter(m => m.model_type === 'STT'),
          ttsModels:    data.filter(m => m.model_type === 'TTS'),
        })
      })
    
    // WebSocket 实时连接(Aware 心跳 + Plaza 推送)
    export function useAgentWebSocket(agentId: string) {
      useEffect(() => {
        const ws = new WebSocket(`${WS_BASE}/agents/${agentId}/ws?token=${getToken()}`)
        ws.onmessage = (e) => {
          const msg = JSON.parse(e.data)
          switch (msg.event) {
            case 'agent_thinking':  setAgentStatus(agentId, 'thinking'); break
            case 'plaza_post':      incrementPlazaUnread(); break
            case 'task_updated':    qc.invalidateQueries(['tasks', agentId]); break
            case 'approval_needed': showApprovalModal(msg.operation); break
          }
        }
        return () => ws.close()
      }, [agentId])
    }
    

    10 · 端到端完整数据流

    以下展示用户发送一条带图像的消息,Agent 调用 Web Search 工具,最终流式返回分析报告的完整数据流:

    # 阶段 技术细节 涉及接口/组件
    1 用户选择图片附件 FileReader → base64 编码 → Zustand attachments 状态 ChatInput.tsx
    2 用户发送消息 构造 multipart JSON → POST /chat → Accept: text/event-stream useAgentChat.ts
    3 后端鉴权 JWT 验证 → RBAC 检查 → 配额检查(call cap) FastAPI Middleware
    4 构造 System Prompt soul.md + memory.md + KBRetrieval + OrgContext + ToolSchema agent_runner.py
    5 路由到 Vision 模型 检测消息含图像 → 选择 vision_model_id 对应的 LLM Server llm_router.py
    6 调用 LLM(流式) OpenAI-compatible /chat/completions stream=true LLM Model Pool
    7 LLM 输出 tool_use 解析 tool_calls → 执行 web_search → 返回搜索结果 Tools Engine
    8 SSE 实时推送 text_delta 事件 → ReadableStream → updateStreamChunk useAgentChat.ts
    9 UI 实时渲染 Zustand streamingMessages → React Streaming 渲染 MessageList.tsx
    10 完成后更新 message_stop → invalidateQueries → 写审计日志 → 更新 memory.md 后端 + TanStack Query

    11 · 技术缺口与改进建议

    ⚠️ 高优先级问题

    原生视频处理缺失 无专用 /video/analyze 端点,需依赖帧提取 + MCP 工具间接实现。建议增加 Video API 模块,支持 Gemini / GPT-4o-mini 视频原生输入。

    ASR/TTS Web UI 体验不完整 v1.4.0 虽添加了 Multimodal Vision,但 Web UI 中的语音输入/输出 UI 组件尚不完整,仅通过 IM 渠道(飞书/Slack)间接支持语音。

    🔶 中优先级问题

    模型路由策略固定 当前模型路由仅基于"是否含图像"的简单判断,缺少基于 token 成本、响应速度、可用性的智能路由策略(类似 LLMRouter)。

    本地模型支持待加强 虽然 Ollama 可作为 custom provider 配置,但缺少对本地模型的专门优化(如 Llama.cpp 的上下文缓存、量化配置)。

    💡 建议改进方向

    流式 Tool UI 可视化 — 工具调用过程显示参数预览、执行进度条、结果折叠展开,而非仅显示状态文本。

    模型 A/B 测试框架 — 参考 BISHENG 的 FlowVersion 设计,为 Agent 实现模型版本切换与 A/B 对比评测功能。


    12 · 研究结论

    💡 核心发现: Clawith 的大模型设计逻辑本质上是一个上下文工程(Context Engineering)平台,而非传统意义上的 LLM 应用。它的价值不在于使用哪个模型,而在于如何将 soul/memory/org knowledge/tools 精准组合成最优 System Prompt,驱动 LLM 以"数字员工"身份行动。

    综合评分

    维度 评估 评分
    大模型抽象设计 LLM Model Pool 架构完善,多提供商统一、类型分类清晰 9/10
    提示词构造工程 soul+memory+KB+OrgCtx+Skill 多层注入,技术领先 9/10
    Chat 接口设计 SSE 流式 + WebSocket 双通道,tool_use 状态实时可见 8.5/10
    多模态(Vision) v1.4.0 完整支持图像,标准 OpenAI 格式 8/10
    ASR/TTS 支持 通过 Model Pool 间接支持,UI 体验待完善 6/10
    视频支持 仅间接方式,无原生视频 API 模块 5/10
    前端状态架构 Zustand + TanStack Query 职责分离清晰,实时性好 8.5/10
    模型管理 UI 管理界面功能完整,提供商预设、测试、配额覆盖全面 8/10

    对开发者的建议

    如果你希望在 Clawith 之上构建多模态应用,当前最成熟的路径是:

    1. 通过 Model Pool 配置 GPT-4o 或 claude-sonnet-4-6 作为默认 Vision 模型
    2. 通过 Code Executor 技能实现视频帧提取(Python + cv2/ffmpeg)
    3. 通过 MCP 工具市场安装所需的 ASR/TTS 专用服务器

    待 v1.5+ 版本原生视频和 ASR UI 模块发布后,再升级到原生接口。


    数据来源:github.com/dataelement/Clawith · clawith.ai Apache 2.0 · Python 66% · TypeScript 18% · 193 Commits

    Logo

    小龙虾开发者社区是 CSDN 旗下专注 OpenClaw 生态的官方阵地,聚焦技能开发、插件实践与部署教程,为开发者提供可直接落地的方案、工具与交流平台,助力高效构建与落地 AI 应用

    更多推荐