AI Chat Configuration
Configure OpenAI, Qwen, and DeepSeek chat
TinyShip's chat sample is built on the Vercel AI SDK (ai 6.x), AI Elements, and Streamdown. The provider list is OpenAI, Qwen, and DeepSeek. Keys and model ids live in config/ai.ts and .env.
For an English-language product, start with OpenAI. Qwen and DeepSeek stay available when you want stronger Chinese or a lower token price. The file in the repo still defaults to Qwen; change defaultProvider when you want OpenAI selected on first load.
AI quick setup: If you have Agent Skills installed, ask your AI to "help me configure AI features". The tinyship-ai skill walks through this setup.
Related pages
| Page | Path | Description |
|---|---|---|
| AI chat | /ai | Chat UI |
Providers
| Provider | Models in config/ai.ts | Fit |
|---|---|---|
| OpenAI | gpt-5, gpt-5-codex, gpt-5-pro | English products and harder reasoning |
| Qwen | qwen-max, qwen-plus, qwen-turbo | Chinese chat, lower cost |
| DeepSeek | deepseek-chat, deepseek-coder | Code help, low cost |
config/ai.ts
defaultProvider is 'qwen' | 'deepseek' | 'openai'. defaultModels maps each provider to one model id. availableModels maps each provider to a string array. Those arrays fill the model menu on /ai.
// config/ai.ts
export const aiConfig = {
defaultProvider: 'qwen' as const, // 'qwen' | 'deepseek' | 'openai'
defaultModels: {
qwen: 'qwen-turbo',
deepseek: 'deepseek-chat',
openai: 'gpt-5',
},
availableModels: {
qwen: ['qwen-max', 'qwen-plus', 'qwen-turbo'],
deepseek: ['deepseek-chat', 'deepseek-coder'],
openai: ['gpt-5', 'gpt-5-codex', 'gpt-5-pro'],
},
}Set defaultProvider to 'openai' if the first screen should open on GPT-5. Keep the same object shape when you add or remove model ids. API keys are not stored in this file. libs/ai/config.ts reads them from the environment (OPENAI_API_KEY, OPENAI_BASE_URL, QWEN_API_KEY, QWEN_BASE_URL, DEEPSEEK_API_KEY).
Environment variables
Configure at least one provider. You can set all three and let people switch in the UI.
# Optional. Read by getConfig() in libs/ai. The /ai page uses config/ai.ts instead.
AI_PROVIDER="qwen" # qwen | deepseek | openai
# OpenAI — start here for an English product
OPENAI_API_KEY="your-openai-api-key"
OPENAI_BASE_URL="https://api.openai.com/v1" # optional custom endpoint
# Qwen — Chinese chat and lower cost
QWEN_API_KEY="your-qwen-api-key"
QWEN_BASE_URL="https://dashscope.aliyuncs.com/compatible-mode/v1"
# DeepSeek — code and low cost
DEEPSEEK_API_KEY="your-deepseek-api-key"The /ai page initializes provider and model from config.ai.defaultProvider and config.ai.defaultModels. Changing AI_PROVIDER does not change that page. AI_PROVIDER is only the fallback inside getConfig() in libs/ai/config.ts (it defaults to 'openai' when the variable is unset). If a chat request omits provider, streamResponseWithUsage also falls back to 'openai'.
API keys
OpenAI
- Open the OpenAI platform.
- Create an API key.
- Put it in
OPENAI_API_KEY.
Use this when the product is aimed at English users. It costs more than Qwen or DeepSeek.
Qwen
- Open Alibaba Cloud Model Studio.
- Create an API key.
- Put it in
QWEN_API_KEY. The compatible-mode base URL above is the one inenv.example.
Qwen is the better default for Chinese conversations, and new accounts often include a free quota.
DeepSeek
- Open the DeepSeek platform.
- Create an API key.
- Put it in
DEEPSEEK_API_KEY.
DeepSeek is inexpensive and strong at code. New accounts often include a free quota.
The /ai page
The page is a small, streaming chat you can extend. It uses AI SDK 6, AI Elements, and Streamdown.
- Streaming replies from the AI SDK
- Markdown, including code blocks with copy
- Provider and model switching from
availableModels - New chat and regenerate
- A credit check:
/api/chatreturns 402 when the balance is empty, thencreditService.consumeCreditsafter the stream reports token usage - Layout that works on mobile and desktop
Treat it as a starting point. The same route can grow into longer memory, tool calls, file upload, per-user history, or a custom system prompt. Chat spend is configured in Credits. Model ids you want in the menu belong in config/ai.ts. The provider clients live in libs/ai.
Related docs: