跳转到主要内容
dedalus-reactuseChat hook 与 Python 后端一起使用。这种模式支持实时流式传输、客户端工具执行以及模型选择。
dedalus-react 包由 Colby Gilbert 创建。完整文档请参见 npm 包页面

架构

Dedalus Python 软件开发工具包(SDK)会以与 OpenAI 兼容的格式流式传输数据块。React hook 通过服务器发送事件 (SSE) 来接收这些数据块。

环境准备

安装依赖项

# Backend
pip install fastapi uvicorn dedalus-labs python-dotenv

# 前端
pnpm add dedalus-react dedalus-labs react

Python 后端(FastAPI)

创建一个流式传输端点,将 DedalusRunner 的输出封装为服务器发送事件 (SSE):
# server.py
import json
from fastapi import FastAPI, Request
from fastapi.responses import StreamingResponse
from fastapi.middleware.cors import CORSMiddleware
from dotenv import load_dotenv

from dedalus_labs import AsyncDedalus
from dedalus_labs.lib.runner import DedalusRunner

load_dotenv()

app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=["http://localhost:3000"],
    allow_methods=["POST"],
    allow_headers=["*"],
)

client = AsyncDedalus()
runner = DedalusRunner(client)


@app.post("/api/chat")
async def chat(request: Request):
    body = await request.json()
    messages = body.get("messages", [])
    model = body.get("model", "openai/gpt-5.2")

    stream = runner.run(
        messages=messages,
        model=model,
        stream=True,
    )

    async def generate():
        async for chunk in stream:
            yield f"data: {chunk.model_dump_json()}\n\n"
        yield "data: [DONE]\n\n"

    return StreamingResponse(
        generate(),
        media_type="text/event-stream",
        headers={
            "Cache-Control": "no-cache",
            "Connection": "keep-alive",
        },
    )


if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

React 前端

使用 useChat 钩子管理 messages 和流式传输:
// App.tsx
import { useChat } from "dedalus-react";
import { useState } from "react";

function Chat() {
  const [input, setInput] = useState("");

  const { messages, sendMessage, status, stop } = useChat({
    transport: { api: "http://localhost:8000/api/chat" },
  });

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    if (!input.trim()) return;
    sendMessage(input);
    setInput("");
  };

  return (
    <div>
      <div className="messages">
        {messages.map((msg, i) => (
          <div key={i} className={`message ${msg.role}`}>
            <strong>{msg.role}:</strong> {msg.content}
          </div>
        ))}
      </div>

      <form onSubmit={handleSubmit}>
        <input
          value={input}
          onChange={(e) => setInput(e.target.value)}
          placeholder="输入消息..."
          disabled={status === "streaming"}
        />
        <button type="submit" disabled={status === "streaming"}>
          发送
        </button>
        {status === "streaming" && (
          <button type="button" onClick={stop}>
            停止
          </button>
        )}
      </form>
    </div>
  );
}

export default Chat;

客户端工具执行

useChat hook 支持通过 onToolCalladdToolResult 在客户端执行工具:
import { useChat } from "dedalus-react";

function ChatWithTools() {
  const { messages, sendMessage, addToolResult } = useChat({
    transport: { api: "/api/chat" },

    // 当模型请求 tool 时调用
    onToolCall: async ({ toolCall }) => {
      if (toolCall.function.name === "get_user_location") {
        // 在客户端执行(例如浏览器地理定位)
        const position = await new Promise<GeolocationPosition>((resolve) =>
          navigator.geolocation.getCurrentPosition(resolve)
        );

        addToolResult({
          toolCallId: toolCall.id,
          result: {
            lat: position.coords.latitude,
            lng: position.coords.longitude,
          },
        });
      }
    },

    // tool 结果返回后自动继续
    sendAutomaticallyWhen: ({ messages }) => {
      const last = messages[messages.length - 1];
      return last?.role === "assistant" &&
             last.tool_calls?.length > 0;
    },
  });

  // ... 组件的其余部分
}

工作原理

  1. 模型请求工具 - 后端在响应中以流式方式发送 tool_calls
  2. 钩子调用回调 - 每次调用 tool 时都会触发 onToolCall
  3. Client 执行 - 你的代码运行该工具(应用程序编程接口 API 调用、浏览器 API、用户 prompt 等)
  4. 结果返回 - addToolResult 向历史记录中添加一条 tool 消息
  5. 自动继续 - 如果 sendAutomaticallyWhen 返回 true,则会携带 tool 结果再次发起请求
Python 后端不需要任何特殊处理——它只会接收包含 role: "tool" 条目的 messages,并继续对话。

模型选择

通过请求体传递额外数据:
const [model, setModel] = useState("openai/gpt-5.2");

const { messages, sendMessage } = useChat({
  transport: {
    api: "/api/chat",
    body: { model },  // 合并到每个请求中
  },
});
更新后端代码以读取它:
@app.post("/api/chat")
async def chat(request: Request):
    body = await request.json()
    messages = body.get("messages", [])
    model = body.get("model", "openai/gpt-5.2")  # 从请求体读取

    stream = runner.run(messages=messages, model=model, stream=True)
    # ...

运行示例

# Terminal 1: Start backend
python server.py

# Terminal 2: Start frontend
cd frontend && pnpm dev

生产环境注意事项

ConcernSolution
CORS为你的域名配置允许的来源列表
Authentication添加 JWT/会话中间件,在请求头中传递令牌
Rate limiting实现基于用户的限流策略
Error handling在 try/catch 中包裹流式传输,并将错误反馈到 UI
通过模型上下文协议 (MCP) 将这些文档以编程方式连接到 Claude、VS Code 等,以获取实时解答。