dramaling-vocab-learning/docs/03_development/api/AI分析API技術實現規格.md

815 lines
21 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# AI分析API技術實現規格
## 📋 **文件資訊**
- **文件名稱**: AI分析API技術實現規格
- **版本**: v2.0
- **建立日期**: 2025-01-25
- **最後更新**: 2025-01-25
- **負責團隊**: DramaLing後端技術團隊
- **對應產品需求**: 《AI句子分析功能產品需求規格》
---
## 🛠 **技術架構概述**
### **系統架構設計**
```yaml
分層架構:
- API Gateway: 認證、限流、路由
- Controllers: HTTP請求處理、參數驗證
- Services: 業務邏輯、AI整合
- Data Access: 資料庫操作、快取管理
- External APIs: AI服務、第三方整合
技術棧:
- 語言: C# / .NET 8
- 框架: ASP.NET Core Web API
- AI服務: Google Gemini 1.5 Flash
- 資料庫: SQLite (開發) / PostgreSQL (生產)
- 快取: Redis (生產) / In-Memory (開發)
- 監控: Application Insights
```
### **核心設計原則**
- **單一職責**: 每個服務類別職責明確
- **依賴注入**: 基於介面的鬆耦合設計
- **配置外部化**: 強型別配置管理
- **錯誤恢復**: 重試機制和降級策略
- **可觀測性**: 結構化日誌和健康檢查
---
## 📡 **API端點設計**
### **核心分析端點**
#### **POST /api/ai/analyze-sentence**
**功能**: 智能英文句子分析
**請求格式**:
```json
{
"inputText": "She just join the team, so let's cut her some slack until she get used to the workflow.",
"analysisMode": "full",
"options": {
"includeGrammarCheck": true,
"includeVocabularyAnalysis": true,
"includeTranslation": true,
"includeIdiomDetection": true,
"includeExamples": true
}
}
```
**回應格式**:
```json
{
"success": true,
"processingTime": 2.34,
"data": {
"analysisId": "uuid-string",
"originalText": "原始輸入文本",
"grammarCorrection": {
"hasErrors": true,
"correctedText": "修正後文本",
"corrections": [
{
"position": { "start": 9, "end": 13 },
"error": "join",
"correction": "joined",
"type": "時態錯誤",
"explanation": "第三人稱單數過去式應使用 'joined'",
"severity": "high"
}
]
},
"sentenceMeaning": "中文翻譯",
"vocabularyAnalysis": {
"word": {
"word": "詞彙",
"translation": "中文翻譯",
"definition": "英文定義",
"partOfSpeech": "詞性",
"pronunciation": "/IPA發音/",
"difficultyLevel": "A1-C2",
"frequency": "high/medium/low",
"synonyms": ["同義詞陣列"],
"example": "例句",
"exampleTranslation": "例句翻譯"
}
},
"idioms": [
{
"idiom": "cut someone some slack",
"translation": "對某人寬容一點",
"definition": "to be more lenient or forgiving",
"pronunciation": "/發音/",
"difficultyLevel": "B2",
"frequency": "medium",
"synonyms": ["be lenient", "give leeway"],
"example": "例句",
"exampleTranslation": "例句翻譯"
}
],
"metadata": {
"analysisModel": "gemini-1.5-flash",
"analysisVersion": "2.0",
"processingDate": "2025-01-25T10:30:00Z"
}
}
}
```
#### **GET /api/ai/health**
**功能**: 服務健康檢查
**回應格式**:
```json
{
"status": "Healthy",
"service": "AI Analysis Service",
"timestamp": "2025-01-25T10:30:00Z",
"version": "2.0",
"dependencies": {
"geminiApi": "healthy",
"database": "healthy",
"cache": "healthy"
}
}
```
---
## 🤖 **AI集成架構**
### **Prompt工程設計**
#### **核心Prompt模板**
```text
You are an English learning assistant. Analyze this sentence and return ONLY a valid JSON response.
**Input Sentence**: "{inputText}"
**Required JSON Structure:**
{
"sentenceTranslation": "Traditional Chinese translation of the entire sentence",
"hasGrammarErrors": true/false,
"grammarCorrections": [
{
"original": "incorrect text",
"corrected": "correct text",
"type": "error type (tense/subject-verb/preposition/word-order)",
"explanation": "brief explanation in Traditional Chinese"
}
],
"vocabularyAnalysis": {
"word1": {
"word": "the word",
"translation": "Traditional Chinese translation",
"definition": "English definition",
"partOfSpeech": "noun/verb/adjective/etc",
"pronunciation": "/phonetic/",
"difficultyLevel": "A1/A2/B1/B2/C1/C2",
"frequency": "high/medium/low",
"synonyms": ["synonym1", "synonym2"],
"example": "example sentence",
"exampleTranslation": "Traditional Chinese example translation"
}
},
"idioms": [
{
"idiom": "idiomatic expression",
"translation": "Traditional Chinese meaning",
"definition": "English explanation",
"pronunciation": "/phonetic notation/",
"difficultyLevel": "A1/A2/B1/B2/C1/C2",
"frequency": "high/medium/low",
"synonyms": ["synonym1", "synonym2"],
"example": "usage example",
"exampleTranslation": "Traditional Chinese example"
}
]
}
**Analysis Guidelines:**
1. **Grammar Check**: Detect tense errors, subject-verb agreement, preposition usage, word order
2. **Vocabulary Analysis**: Include ALL significant words (exclude articles: a, an, the)
3. **CEFR Levels**: Assign accurate A1-C2 levels for each word
4. **Idioms**: Identify any idiomatic expressions or phrasal verbs
5. **Translations**: Use Traditional Chinese (Taiwan standard)
**IMPORTANT**: Return ONLY the JSON object, no additional text or explanation.
```
### **AI服務配置**
#### **Gemini API配置**
```yaml
模型配置:
- 模型: gemini-1.5-flash
- 溫度: 0.7 (平衡創造性和準確性)
- 最大輸出: 2000 tokens
- 超時: 30秒
重試策略:
- 最大重試: 3次
- 退避策略: 指數退避 (1s, 2s, 4s)
- 重試條件: 網路錯誤、超時、5xx錯誤
- 熔斷條件: 連續失敗 > 5次
降級策略:
- 備用回應: 基礎翻譯和詞性分析
- 快取回退: 相似句子的歷史分析結果
- 服務狀態: 實時監控和告警
```
---
## 🔧 **數據模型設計**
### **請求模型**
#### **SentenceAnalysisRequest**
```csharp
public class SentenceAnalysisRequest
{
[Required]
[StringLength(300, MinimumLength = 1)]
public string InputText { get; set; } = string.Empty;
public string AnalysisMode { get; set; } = "full";
public AnalysisOptions? Options { get; set; }
}
public class AnalysisOptions
{
public bool IncludeGrammarCheck { get; set; } = true;
public bool IncludeVocabularyAnalysis { get; set; } = true;
public bool IncludeTranslation { get; set; } = true;
public bool IncludeIdiomDetection { get; set; } = true;
public bool IncludeExamples { get; set; } = true;
}
```
### **回應模型**
#### **核心資料模型**
```csharp
public class SentenceAnalysisResponse
{
public bool Success { get; set; } = true;
public double ProcessingTime { get; set; }
public SentenceAnalysisData? Data { get; set; }
public string? Message { get; set; }
}
public class SentenceAnalysisData
{
public string AnalysisId { get; set; } = Guid.NewGuid().ToString();
public string OriginalText { get; set; } = string.Empty;
public GrammarCorrectionDto? GrammarCorrection { get; set; }
public string SentenceMeaning { get; set; } = string.Empty;
public Dictionary<string, VocabularyAnalysisDto> VocabularyAnalysis { get; set; } = new();
public List<IdiomDto> Idioms { get; set; } = new();
public AnalysisMetadata Metadata { get; set; } = new();
}
```
#### **詳細模型定義**
```csharp
public class VocabularyAnalysisDto
{
public string Word { get; set; } = string.Empty;
public string Translation { get; set; } = string.Empty;
public string Definition { get; set; } = string.Empty;
public string PartOfSpeech { get; set; } = string.Empty;
public string Pronunciation { get; set; } = string.Empty;
public string DifficultyLevel { get; set; } = string.Empty;
public string Frequency { get; set; } = string.Empty;
public List<string> Synonyms { get; set; } = new();
public string? Example { get; set; }
public string? ExampleTranslation { get; set; }
}
public class IdiomDto
{
public string Idiom { get; set; } = string.Empty;
public string Translation { get; set; } = string.Empty;
public string Definition { get; set; } = string.Empty;
public string Pronunciation { get; set; } = string.Empty;
public string DifficultyLevel { get; set; } = string.Empty;
public string Frequency { get; set; } = string.Empty;
public List<string> Synonyms { get; set; } = new();
public string? Example { get; set; }
public string? ExampleTranslation { get; set; }
}
public class GrammarCorrectionDto
{
public bool HasErrors { get; set; }
public string CorrectedText { get; set; } = string.Empty;
public List<GrammarErrorDto> Corrections { get; set; } = new();
}
public class GrammarErrorDto
{
public ErrorPosition Position { get; set; } = new();
public string Error { get; set; } = string.Empty;
public string Correction { get; set; } = string.Empty;
public string Type { get; set; } = string.Empty;
public string Explanation { get; set; } = string.Empty;
public string Severity { get; set; } = "medium";
}
```
---
## 🔧 **服務層架構**
### **核心服務設計**
#### **IGeminiService介面**
```csharp
public interface IGeminiService
{
Task<SentenceAnalysisData> AnalyzeSentenceAsync(string inputText, AnalysisOptions options);
Task<bool> HealthCheckAsync();
Task<string> GetModelVersionAsync();
}
```
#### **服務實現重點**
```csharp
public class GeminiService : IGeminiService
{
private readonly HttpClient _httpClient;
private readonly IOptions<GeminiOptions> _options;
private readonly ILogger<GeminiService> _logger;
// ✅ 強型別配置注入
public GeminiService(HttpClient httpClient, IOptions<GeminiOptions> options, ILogger<GeminiService> logger)
{
_httpClient = httpClient;
_options = options;
_logger = logger;
ConfigureHttpClient();
}
// ✅ 結構化錯誤處理
public async Task<SentenceAnalysisData> AnalyzeSentenceAsync(string inputText, AnalysisOptions options)
{
try
{
var prompt = BuildPrompt(inputText, options);
var aiResponse = await CallGeminiAPIWithRetry(prompt);
return ParseResponse(inputText, aiResponse);
}
catch (HttpRequestException ex)
{
throw new AIServiceException("Gemini", "Network error", ex);
}
catch (JsonException ex)
{
throw new AIServiceException("Gemini", "Invalid response format", ex);
}
}
}
```
### **配置管理架構**
#### **強型別配置**
```csharp
public class GeminiOptions
{
public const string SectionName = "Gemini";
[Required]
public string ApiKey { get; set; } = string.Empty;
[Range(1, 120)]
public int TimeoutSeconds { get; set; } = 30;
[Range(1, 10)]
public int MaxRetries { get; set; } = 3;
public string Model { get; set; } = "gemini-1.5-flash";
public double Temperature { get; set; } = 0.7;
public int MaxOutputTokens { get; set; } = 2000;
}
// 配置驗證器
public class GeminiOptionsValidator : IValidateOptions<GeminiOptions>
{
public ValidateOptionsResult Validate(string name, GeminiOptions options)
{
var failures = new List<string>();
if (string.IsNullOrWhiteSpace(options.ApiKey))
failures.Add("Gemini API key is required");
if (!IsValidApiKey(options.ApiKey))
failures.Add("Invalid Gemini API key format");
return failures.Any()
? ValidateOptionsResult.Fail(failures)
: ValidateOptionsResult.Success;
}
}
```
---
## 🛡️ **錯誤處理與穩定性**
### **異常層次結構**
```csharp
public abstract class DramaLingException : Exception
{
public string ErrorCode { get; }
public Dictionary<string, object> Context { get; }
protected DramaLingException(string errorCode, string message) : base(message)
{
ErrorCode = errorCode;
Context = new Dictionary<string, object>();
}
}
public class AIServiceException : DramaLingException
{
public AIServiceException(string provider, string details)
: base("AI_SERVICE_ERROR", $"AI service '{provider}' failed: {details}")
{
Context["Provider"] = provider;
Context["Details"] = details;
}
}
public class ValidationException : DramaLingException
{
public ValidationException(string field, string message)
: base("VALIDATION_ERROR", $"Validation failed for {field}: {message}")
{
Context["Field"] = field;
}
}
```
### **錯誤回應標準**
```json
{
"success": false,
"error": {
"code": "AI_SERVICE_ERROR",
"message": "AI服務暫時不可用",
"details": {
"provider": "gemini",
"originalError": "Network timeout"
},
"suggestions": [
"請稍後重試",
"如果問題持續,請聯繫客服"
]
},
"timestamp": "2025-01-25T10:30:00Z",
"requestId": "uuid-string"
}
```
### **重試與熔斷機制**
```csharp
// 使用Polly實現重試策略
services.AddHttpClient<IGeminiService, GeminiService>()
.AddPolicyHandler(GetRetryPolicy())
.AddPolicyHandler(GetCircuitBreakerPolicy());
private static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.WaitAndRetryAsync(
retryCount: 3,
sleepDurationProvider: retryAttempt =>
TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
onRetry: (outcome, timespan, retryCount, context) =>
{
logger.LogWarning("Retry {RetryCount} after {Delay}ms",
retryCount, timespan.TotalMilliseconds);
});
}
```
---
## 📊 **性能優化設計**
### **快取策略**
```yaml
多層快取架構:
L1: 應用程序記憶體快取 (5分鐘)
L2: Redis分散式快取 (1小時)
L3: 資料庫持久快取 (24小時)
快取鍵設計:
- 格式: "analysis:{hash(inputText)}"
- 過期: 基於內容複雜度動態調整
- 清理: 背景服務定期清理過期快取
快取命中率目標: > 70%
```
### **資料庫優化**
```csharp
// 查詢優化範例
public async Task<AnalysisCache> GetCachedAnalysisAsync(string inputText)
{
var textHash = ComputeHash(inputText);
return await _context.AnalysisCache
.AsNoTracking() // 只讀查詢優化
.Where(c => c.InputTextHash == textHash && c.ExpiresAt > DateTime.UtcNow)
.Select(c => new AnalysisCache // 投影查詢,只選需要的欄位
{
Id = c.Id,
CachedData = c.CachedData,
CreatedAt = c.CreatedAt
})
.FirstOrDefaultAsync();
}
```
---
## 🔒 **安全架構設計**
### **API安全**
```yaml
認證機制:
- JWT Bearer Token認證
- Token過期時間: 24小時
- 刷新機制: Refresh Token
授權控制:
- 角色基礎存取控制 (RBAC)
- 資源級別權限
- API速率限制
輸入驗證:
- 參數類型檢查
- 字符長度限制
- XSS防護過濾
- SQL注入防護
```
### **資料安全**
```yaml
傳輸安全:
- TLS 1.3強制加密
- HSTS標頭
- 安全標頭 (CSP, X-Frame-Options)
存儲安全:
- 敏感資料加密
- API金鑰安全管理
- 個人資料匿名化
- 定期安全掃描
```
---
## 🧪 **測試策略**
### **測試金字塔**
```yaml
單元測試 (70%):
- 服務邏輯測試
- 配置驗證測試
- 錯誤處理測試
- Mock外部依賴
整合測試 (20%):
- API端點測試
- 資料庫整合測試
- 快取系統測試
- 健康檢查測試
E2E測試 (10%):
- 完整分析流程測試
- 真實AI API測試
- 性能基準測試
- 安全滲透測試
```
### **測試案例設計**
```csharp
[TestFixture]
public class AIAnalysisServiceTests
{
[Test]
public async Task AnalyzeAsync_WithValidInput_ReturnsAnalysisResult()
{
// Arrange
var request = new AnalysisRequest { InputText = "She just joined the team." };
// Act
var result = await _service.AnalyzeAsync(request);
// Assert
Assert.That(result.VocabularyAnalysis.Count, Is.GreaterThan(0));
Assert.That(result.SentenceMeaning, Is.Not.Empty);
}
[Test]
public async Task AnalyzeAsync_WhenAIServiceFails_ThrowsAIServiceException()
{
// 測試AI服務故障時的錯誤處理
}
}
```
---
## 📈 **監控與可觀測性**
### **日誌標準**
```csharp
// 結構化日誌擴展
public static class LoggerExtensions
{
public static void LogAIRequest(this ILogger logger, string requestId,
string inputText, string provider, double processingTime)
{
logger.LogInformation("AI Request: {RequestId} Provider: {Provider} " +
"Length: {Length} Time: {Time}ms",
requestId, provider, inputText.Length, processingTime);
}
}
```
### **健康檢查**
```csharp
public class AIServiceHealthCheck : IHealthCheck
{
public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context,
CancellationToken cancellationToken = default)
{
var checks = new Dictionary<string, bool>
{
["gemini_api"] = await CheckGeminiHealthAsync(),
["database"] = await CheckDatabaseHealthAsync(),
["cache"] = await CheckCacheHealthAsync()
};
var failedChecks = checks.Where(c => !c.Value).Select(c => c.Key).ToList();
return failedChecks.Any()
? HealthCheckResult.Unhealthy($"Failed: {string.Join(", ", failedChecks)}")
: HealthCheckResult.Healthy("All systems operational");
}
}
```
### **性能指標**
```yaml
關鍵指標:
- API回應時間分佈 (P50, P95, P99)
- AI API調用成功率
- 快取命中率
- 記憶體和CPU使用率
- 錯誤率和異常分佈
告警閾值:
- 回應時間P95 > 5秒
- 錯誤率 > 5%
- AI API失敗率 > 10%
- 記憶體使用 > 80%
```
---
## 🚀 **部署與配置**
### **環境配置**
```yaml
Development:
- Database: SQLite
- Cache: In-Memory
- AI Provider: Gemini (測試Key)
- Logging: Debug Level
Production:
- Database: PostgreSQL (HA)
- Cache: Redis Cluster
- AI Provider: Gemini (生產Key)
- Logging: Information Level
- Monitoring: Application Insights
```
### **Docker配置**
```dockerfile
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 5008
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY ["DramaLing.Api.csproj", "."]
RUN dotnet restore
COPY . .
RUN dotnet publish -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=build /app/publish .
HEALTHCHECK --interval=30s --timeout=3s \
CMD curl -f http://localhost:5008/health || exit 1
ENTRYPOINT ["dotnet", "DramaLing.Api.dll"]
```
---
## 📋 **開發指導**
### **程式碼規範**
```yaml
命名規範:
- 類別: PascalCase (UserService)
- 方法: PascalCase (AnalyzeAsync)
- 參數: camelCase (inputText)
- 常數: UPPER_CASE (MAX_LENGTH)
註釋規範:
- 公開API: 完整XML註釋
- 複雜邏輯: 行內註釋解釋
- 業務邏輯: 意圖說明註釋
- TODO: 使用標準格式
錯誤處理:
- 自訂異常類型
- 結構化錯誤回應
- 日誌記錄完整
- 用戶友善訊息
```
### **API設計原則**
```yaml
RESTful設計:
- 使用標準HTTP動詞
- 資源導向URL設計
- 狀態碼語義明確
- 一致的回應格式
版本管理:
- URL版本控制 (/api/v1/)
- 向下相容保證
- 淘汰策略明確
- 版本變更文檔
安全實踐:
- 最小權限原則
- 輸入驗證完整
- 輸出編碼安全
- 審計日誌記錄
```
---
## 🔄 **變更管理**
### **API版本演進**
- **v1.0**: 基礎分析功能 (2025-01-20)
- **v1.1**: 移除userLevel簡化API (2025-01-25)
- **v2.0**: 重構技術規格,標準化設計 (2025-01-25)
### **技術債務管理**
```yaml
已解決:
- 硬編碼配置移除
- 強型別配置實施
- API規格標準化
待解決:
- 重試機制實施
- 健康檢查完善
- 監控指標實施
- 性能優化
```
---
**文件版本**: v2.0
**技術負責人**: DramaLing後端技術團隊
**最後更新**: 2025-01-25
**下次審查**: 2025-02-25
**關聯文件**:
- 《AI句子分析功能產品需求規格》- 業務需求和用戶故事
- 《系統整合與部署規格》- 整合和部署細節
- 《AI驅動產品後端技術架構指南》- 架構設計指導原則