文档版本 / Document Version: 1.1 创建日期 / Created: 2026-03-07
本文档详细描述 AskOnce 项目的技术架构、模块设计和实现细节。
This document details the technical architecture, module design, and implementation details of the AskOnce project.
- 系统概述 / System Overview
- 系统架构 / System Architecture
- 核心模块设计 / Core Module Design
- 前端设计 / Frontend Design
- 浏览器扩展设计 / Browser Extension Design
- API 设计 / API Design
- 部署架构 / Deployment Architecture
- 安全考虑 / Security Considerations
- 性能优化 / Performance Optimization
- 扩展点 / Extension Points
AskOnce 是一个多模型并发查询平台,实现"问一次,得到所有模型的答案"的核心价值。
AskOnce is a multi-model concurrent query platform that delivers the core value of "Ask once, get all models' answers".
- 一次输入,多模型响应 / Single Input, Multiple Responses: 同时向 20+ 个 AI 模型发送问题 / Send questions to 20+ AI models simultaneously
- 实时流式输出 / Real-time Streaming: 边生成边显示,无需等待 / Display as generated, no waiting
- AI 评审机制 / AI Judge Mechanism: 自动分析对比所有回答 / Automatically analyze and compare all responses
- 多模式支持 / Multi-mode Support: API、网页版、零成本模式(需部署 openclaw-zero-token)/ API, Web, Zero-cost mode (requires deploying openclaw-zero-token)
- 多端部署 / Multi-platform Deployment: Web、Chrome 扩展、桌面应用 / Web, Chrome Extension, Desktop
┌─────────────────────────────────────────────────────────────────────┐
│ AskOnce │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ 客户端层 / Client Layer │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ Web UI │ │ Extension │ │ Desktop │ │ │
│ │ │ (React) │ │ (Chrome) │ │ (Electron) │ │ │
│ │ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │ │
│ └─────────┼─────────────────┼─────────────────┼────────────────┘ │
│ │ │ │ │
│ ┌─────────▼─────────────────▼─────────────────▼────────────────┐ │
│ │ API 网关层 / API Gateway Layer │ │
│ │ ┌─────────────────────────────────────────────────────────┐ │ │
│ │ │ REST API │ WebSocket │ SSE (Streaming) │ │ │
│ │ └─────────────────────────────────────────────────────────┘ │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌───────────────────────────▼─────────────────────────────────┐ │
│ │ 业务逻辑层 / Business Logic Layer │ │
│ │ ┌─────────────────────────────────────────────────────────┐ │ │
│ │ │ Query Orchestrator │ │ │
│ │ │ - 并发控制/Concurrency - 超时管理/Timeout - 重试/Retry │ │ │
│ │ │ - 结果聚合/Aggregation - 流式/Streaming - 进度/Progress│ │ │
│ │ └─────────────────────────────────────────────────────────┘ │ │
│ │ ┌─────────────────────────────────────────────────────────┐ │ │
│ │ │ Judge Engine │ │ │
│ │ │ - 响应收集/Collection - 分析/Analysis - 排名/Ranking│ │ │
│ │ └─────────────────────────────────────────────────────────┘ │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌───────────────────────────▼─────────────────────────────────┐ │
│ │ 模型接口层 / Model Interface Layer │ │
│ │ ┌──────────┬──────────┬──────────┬──────────┬─────────┐ │ │
│ │ │ OpenAI │ Anthropic │ DeepSeek │OpenRouter│ Custom │ │ │
│ │ │ Provider │ Provider │ Provider │ Provider │Provider │ │ │
│ │ └──────────┴──────────┴──────────┴──────────┴─────────┘ │ │
│ └───────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
askonce/
├── backend/ # 后端服务 / Backend Services
│ ├── python/ # Python FastAPI 后端
│ │ ├── main.py # FastAPI 应用入口 / Entry point
│ │ ├── models.py # Pydantic 数据模型 / Data models
│ │ ├── orchestrator.py # 查询编排器 / Query orchestrator
│ │ └── providers.py # 模型提供者 / Model providers
│ └── node/ # Node.js Express 后端
│ ├── src/
│ │ ├── index.ts # Express 应用入口 / Entry point
│ │ ├── routes/
│ │ │ ├── models.ts # 模型列表 API
│ │ │ └── query.ts # 查询 API
│ │ └── services/
│ │ └── providers.ts # 模型提供者
│ └── package.json
│
├── frontend/ # React 前端 / React Frontend
│ ├── src/
│ │ ├── main.tsx # React 入口 / Entry point
│ │ ├── App.tsx # 主应用组件 / Main component
│ │ ├── api.ts # API 客户端 / API client
│ │ ├── store.ts # Zustand 状态管理 / State management
│ │ └── components/
│ │ ├── Header.tsx
│ │ ├── QueryInput.tsx
│ │ ├── ModelSelector.tsx
│ │ ├── ResultsGrid.tsx
│ │ └── AnalysisPanel.tsx
│ └── package.json
│
├── extension/ # Chrome 扩展 / Chrome Extension
│ ├── manifest.json # 扩展配置 / Extension config
│ ├── rules.json # 头部移除规则 / Header rules
│ ├── background/
│ │ └── service-worker.js
│ ├── content-scripts/
│ │ └── content.js
│ └── popup/
│ ├── popup.html
│ └── popup.js
│
├── shared/ # 共享代码 / Shared Code
│ └── types.ts # TypeScript 类型定义 / Type definitions
│
├── docker-compose.yml # Docker 编排 / Docker Compose
└── README.md # 项目说明 / Project Description
文件 / Files: backend/python/orchestrator.py / backend/node/src/routes/query.ts
- 管理多个模型的并发请求 / Manage concurrent requests to multiple models
- 超时控制和重试逻辑 / Timeout control and retry logic
- 结果聚合和错误处理 / Result aggregation and error handling
async def query(request_id: str, prompt: str, model_ids: list[str]):
# 1. 并发启动所有模型查询 / Start all model queries concurrently
tasks = [query_single_model(model_id, prompt) for model_id in model_ids]
# 2. 使用 asyncio.gather 并发执行 / Execute concurrently with asyncio.gather
results = await asyncio.gather(*tasks, return_exceptions=True)
# 3. 处理异常 / Handle exceptions
processed_results = process_results(results)
# 4. 返回聚合结果 / Return aggregated results
return processed_resultsclass QueryOrchestrator:
def __init__(self, max_concurrent: int = 10):
self.semaphore = asyncio.Semaphore(max_concurrent)
async def query(self, ...):
async with self.semaphore: # 限制并发数 / Limit concurrency
# 执行查询 / Execute query文件 / Files: backend/python/providers.py / backend/node/src/services/providers.ts
| 模型 / Model | 提供商 / Provider | API 端点 / Endpoint |
|---|---|---|
| GPT-4o | OpenAI | api.openai.com |
| Claude Sonnet 4 | Anthropic | api.anthropic.com |
| DeepSeek V3 | DeepSeek | api.deepseek.com |
| Gemini | OpenRouter | openrouter.ai |
| Llama | OpenRouter | openrouter.ai |
class BaseProvider(ABC):
@abstractmethod
async def query(self, prompt: str, **kwargs) -> dict:
"""执行查询 / Execute query"""
pass
@abstractmethod
async def stream(self, prompt: str, **kwargs) -> AsyncGenerator[StreamChunk]:
"""流式查询 / Streaming query"""
pass文件 / File: backend/python/orchestrator.py (judge method)
- 收集所有模型的响应 / Collect all model responses
- 使用选定的 AI 进行分析和比较 / Use selected AI for analysis and comparison
- 生成排名和推荐 / Generate rankings and recommendations
文件 / File: frontend/src/store.ts
interface QueryState {
// 模型 / Models
models: Model[];
selectedModels: string[];
// 查询 / Query
prompt: string;
isQuerying: boolean;
results: QueryResult[];
// 分析 / Analysis
analysis: AnalysisResult | null;
isAnalyzing: boolean;
// 历史 / History
history: HistoryEntry[];
// 设置 / Settings
settings: Settings;
}App
├── Header
│ └── Theme Toggle
├── QueryInput
│ └── Textarea + Submit Button
├── ModelSelector
│ └── Collapsible Groups
├── ResultsGrid
│ ├── ViewMode Toggle (Card/Split)
│ └── ResultCard[]
│ ├── Status Indicator
│ ├── Markdown Content
│ └── Actions (Copy/Expand)
└── AnalysisPanel
├── Summary
├── Common Points
├── Differences
├── Rankings
└── Recommendation
- Service Worker: 消息路由、状态管理、头部移除规则 / Message routing, state management, header rules
- Popup/SidePanel: 用户界面 / User interface
- Content Scripts: DOM 注入、响应提取 / DOM injection, response extraction
文件 / File: extension/content-scripts/content.js
// 1. 检测当前 AI 网站 / Detect current AI website
function detectCurrentModel() {
const hostname = window.location.hostname;
if (hostname.includes('chatgpt.com')) return 'chatgpt';
if (hostname.includes('claude.ai')) return 'claude';
// ...
}
// 2. 查找输入元素 / Find input element
async function findInputElement(selectors) {
for (const selector of selectors) {
const element = document.querySelector(selector);
if (element) return element;
}
throw new Error('Input element not found');
}
// 3. 注入查询 / Inject query
async function injectQuery(prompt) {
const input = await findInputElement(config.inputSelectors);
input.value = prompt;
input.dispatchEvent(new Event('input', { bubbles: true }));
// 4. 提交表单 / Submit form
const submitBtn = await findInputElement(config.submitSelectors);
submitBtn.click();
}文件 / File: extension/rules.json
[
{
"id": 1,
"action": {
"type": "modifyHeaders",
"responseHeaders": [
{ "header": "X-Frame-Options", "operation": "remove" },
{ "header": "Content-Security-Policy", "operation": "remove" }
]
},
"condition": {
"urlFilter": "*://chatgpt.com/*",
"resourceTypes": ["sub_frame"]
}
}
]| 方法 / Method | 端点 / Endpoint | 描述 / Description |
|---|---|---|
| GET | /api/models |
获取可用模型列表 / Get available model list |
| POST | /api/query |
并发查询多个模型 / Query multiple models concurrently |
| POST | /api/query/stream |
流式查询 / Streaming query |
| POST | /api/judge |
AI 评审功能 / AI judging feature |
| GET | /api/health |
健康检查 / Health check |
POST /api/query
{
"prompt": "解释量子计算 / Explain quantum computing",
"model_ids": ["gpt-4o", "claude-sonnet-4", "deepseek-v3"],
"timeout": 60000,
"retries": 2,
"temperature": 0.7,
"max_tokens": 4096
}{
"request_id": "req_123456",
"status": "completed",
"results": [
{
"model_id": "gpt-4o",
"status": "completed",
"content": "量子计算是... / Quantum computing is...",
"tokens_used": 150,
"duration": 2500
},
{
"model_id": "claude-sonnet-4",
"status": "completed",
"content": "量子计算是一种... / Quantum computing is a...",
"tokens_used": 180,
"duration": 3200
}
]
}data: {"model_id": "gpt-4o", "delta": "量子", "accumulated": "量子", "is_complete": false}
data: {"model_id": "gpt-4o", "delta": "计算", "accumulated": "量子计算", "is_complete": false}
data: {"model_id": "gpt-4o", "delta": "是", "accumulated": "量子计算是", "is_complete": false}
data: {"model_id": "gpt-4o", "accumulated": "量子计算是一种利用...", "is_complete": true}
version: '3.8'
services:
backend:
build: ./backend/python
ports:
- "8000:8000"
environment:
- OPENAI_API_KEY=${OPENAI_API_KEY}
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
frontend:
build: ./frontend
ports:
- "3000:3000"
depends_on:
- backend
searxng:
image: searxng/searxng:latest
ports:
- "8888:8080"
profiles:
- free# API Keys
OPENAI_API_KEY=sk-xxx
ANTHROPIC_API_KEY=sk-ant-xxx
DEEPSEEK_API_KEY=sk-xxx
OPENROUTER_API_KEY=sk-or-xxx
GOOGLE_API_KEY=xxx
XAI_API_KEY=xxx
# 配置 / Configuration
PORT=8000
MAX_CONCURRENT=10
DEFAULT_TIMEOUT=60000- API Key 管理 / API Key Management: 通过环境变量或密钥管理系统 / Via environment variables or secret management
- 请求验证 / Request Validation: 验证模型 ID 和参数有效性 / Validate model IDs and parameters
- 本地存储 / Local Storage: 历史记录存储在本地 / History stored locally
- 数据加密 / Data Encryption: 敏感信息加密存储 / Sensitive data encrypted
- 无追踪 / No Tracking: 不收集用户数据 / No user data collection
- 请求限制 / Request Limits: 每个 API Key 的速率限制 / Rate limits per API Key
- 并发限制 / Concurrency Limits: 通过信号量控制并发数 / Control concurrency via semaphore
- 使用
asyncio.Semaphore限制并发数 / Useasyncio.Semaphoreto limit concurrency - 默认最大并发 / Default max concurrent: 10
- Server-Sent Events (SSE) 实现流式响应 / SSE for streaming responses
- 减少首字节时间 (TTFB) / Reduce Time to First Byte
- 模型列表缓存 / Model list caching
- 响应缓存(可选)/ Response caching (optional)
class CustomProvider(BaseProvider):
async def query(self, prompt: str, **kwargs) -> dict:
# 实现自定义逻辑 / Implement custom logic
passinterface JudgeCriteria {
name: string;
weight: number;
evaluate: (response: string) => number;
}文档版本 / Document Version: v1.1 创建日期 / Created: 2026-03-07 最后更新 / Last Updated: 2026-03-07 作者 / Author: SeekSage