搜尋與對話
Search & Chat

以下為前端整合最常用的端點。

These are the most commonly used endpoints for frontend integration.

語意搜尋
Semantic Search

POST /api/v1/search

透過混合語意搜尋 + 關鍵字搜尋,並支援同義詞擴展,搜尋知識庫。

Search the knowledge base using hybrid semantic + keyword search with synonym expansion.

請求
Request

{
  "query": "How to improve Core Web Vitals",
  "top_k": 5,
  "category": "Technical SEO"
}
欄位 / Field 型別 / Type 必填 / Required 說明 / Description
query string Yes 搜尋查詢(1-500 字元)
Search query (1-500 chars)
top_k number No 回傳結果數(預設:5,最大:20)
Number of results (default: 5, max: 20)
category string No 依分類篩選
Filter by category
extraction_model string No 依萃取模型篩選(例如 "claude-code"
Filter by extraction model (e.g. "claude-code")
maturity_level string No 提升符合指定成熟度等級的結果排序("L1""L4"
Boost results matching this maturity level ("L1""L4")

回應
Response

{
  "results": [
    {
      "question": "What are Core Web Vitals and how do they impact SEO?",
      "answer": "Core Web Vitals are a set of metrics...",
      "score": 0.89,
      "source_type": "meeting",
      "source_collection": "weekly-meetings",
      "category": "Technical SEO",
      "difficulty": "advanced",
      "id": "a1b2c3d4e5f67890"
    }
  ],
  "total": 5,
  "mode": "hybrid"
}

搜尋模式(自動)
Search Modes (automatic)

條件 / Condition Mode 說明 / Description
已設定 Supabase
Supabase configured
hybrid pgvector embedding + 關鍵字加權
pgvector embedding + keyword boost
僅有 OpenAI Key
OpenAI key only
hybrid Embedding 相似度 + 關鍵字加權
Embedding similarity + keyword boost
無 OpenAI Key
No OpenAI key
keyword 純關鍵字搜尋,支援同義詞擴展
Keyword-only search with synonym expansion

前端範例
Frontend Example

async function searchKnowledgeBase(query: string, category?: string) {
  const res = await fetch("/api/proxy/search", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ query, top_k: 10, category }),
  });
  const data = await res.json();
  return data.results; // { question, answer, score, source_type, category }[]
}

RAG 對話
RAG Chat

POST /api/v1/chat

單輪問答,自動從知識庫檢索相關內容。

Single-turn question answering with automatic knowledge base retrieval.

請求
Request

{
  "message": "What is the difference between canonical URL and 301 redirect?",
  "history": [
    { "role": "user", "content": "What is canonical URL?" },
    { "role": "assistant", "content": "A canonical URL is..." }
  ],
  "mode": "rag"
}
欄位 / Field 型別 / Type 必填 / Required 說明 / Description
message string Yes 使用者訊息(1-2000 字元)
User message (1-2000 chars)
history array No 上下文用的歷史訊息(最多 20 條)
Previous messages for context (max 20)
mode string No "rag""agent"(預設:auto)
"rag" or "agent" (default: auto)
maturity_level string No 客戶 SEO 成熟度("L1""L4"),用於調整回應深度
Client SEO maturity level ("L1""L4") for response depth tuning

回應
Response

{
  "answer": "Canonical URLs and 301 redirects serve different purposes...",
  "sources": [
    {
      "question": "What is canonical URL?",
      "answer": "...",
      "source_type": "meeting",
      "category": "Technical SEO",
      "id": "abc123def456"
    }
  ],
  "mode": "rag",
  "metadata": {
    "model": "gpt-5.4-nano",
    "provider": "openai",
    "mode": "rag",
    "input_tokens": 1250,
    "output_tokens": 380,
    "total_tokens": 1630,
    "duration_ms": 2340,
    "retrieval_count": 5
  }
}

模式比較
Mode Comparison

Mode 行為 / Behavior 延遲 / Latency 適用情境 / Use Case
rag 單次檢索 + 生成
Single retrieval + generation
~2-3s 簡單事實性問題
Simple factual questions
agent 多輪搜尋(最多 5 輪)
Multi-turn search (up to 5 rounds)
~5-15s 複雜的比較型問題
Complex comparison questions
context-only 不呼叫 LLM,直接回傳來源
No LLM, returns sources only
~0.5s 未設定 OpenAI Key 時
When no OpenAI key

前端範例
Frontend Example

interface ChatResponse {
  answer: string | null;
  sources: Array<{
    question: string;
    answer: string;
    source_type: string;
    category: string;
    id: string;
  }>;
  mode: "rag" | "agent" | "context-only";
  metadata?: {
    model: string;
    duration_ms: number;
    total_tokens: number;
  };
}

async function askQuestion(message: string, mode?: "rag" | "agent") {
  const res = await fetch("/api/proxy/chat", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ message, mode }),
  });
  return (await res.json()) as ChatResponse;
}

Session 對話
Session-Based Chat

適用於需要跨訊息保留對話上下文的多輪對話情境。

For multi-turn conversations where context needs to be preserved across messages.

建立 Session
Create Session

const session = await fetch("/api/proxy/sessions", { method: "POST" });
const { id } = await session.json();
// id: "550e8400-e29b-41d4-a716-446655440000"

發送訊息
Send Message

const response = await fetch(`/api/proxy/sessions/${sessionId}/messages`, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ message: "What is structured data?", mode: "rag" }),
});

回應包含 Metadata
Response includes metadata

{
  "role": "assistant",
  "content": "Structured data is...",
  "metadata": {
    "model": "gpt-5.4-nano",
    "mode": "rag",
    "duration_ms": 1820,
    "retrieval_count": 3
  }
}

取得對話歷史
Get Session History

const session = await fetch(`/api/proxy/sessions/${sessionId}`);
const { messages } = await session.json();
// messages: Array<{ role, content, metadata?, created_at }>