이상하게도 한도 제한에 부딪히는 것 같습니다. 번역 백필을 시작하기 전에는 Discourse AI 검색/도움말 봇이 정상적으로 작동했습니다(AI의 주요 용도였습니다). 하지만 지금은 Gemini Flash 2.5의 한도 제한에 부딪히고 있습니다. 이 한도는 분당 10회 요청(RPM), 분당 250,000 토큰(TPM), 일일 250회 요청(RPD)입니다. 로그를 보면 백필이 활성화된 상태에서 어떤 이유로든 일일 250회 요청(RPD) 한도에 도달하는 것으로 보입니다.
보내는 요청의 수나 요청 빈도를 확인하기 위해 이를 디버깅할 수 있는 방법이 있을까요?
Message
DiscourseAi::Completions::Endpoints::Gemini: status: 429 - body: {
"error": {
"code": 429,
"message": "You exceeded your current quota, please check your plan and billing details. For more information on this error, head to: https://ai.google.dev/gemini-api/docs/rate-limits. To monitor your current usage, head to: https://ai.dev/usage?tab=rate-limit. \n* Quota exceeded for metric: generativelanguage.googleapis.com/generate_content_free_tier_requests, limit: 250\nPlease retry in 45.454864372s.",
"status": "RESOURCE_EXHAUSTED",
"details": [
{
"@type": "type.googleapis.com/google.rpc.Help",
"links": [
{
"description": "Learn more about Gemini API quotas",
"url": "https://ai.google.dev/gemini-api/docs/rate-limits"
}
]
},
{
"@type": "type.googleapis.com/google.rpc.QuotaFailure",
"violations": [
{
"quotaMetric": "generativelanguage.googleapis.com/generate_content_free_tier_requests",
"quotaId": "GenerateRequestsPerDayPerProjectPerModel-FreeTier",
"quotaDimensions": {
"location": "global",
"model": "gemini-2.5-flash"
},
"quotaValue": "250"
}
]
},
{
"@type": "type.googleapis.com/google.rpc.RetryInfo",
"retryDelay": "45s"
}
]
}
}
Backtrace
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activesupport-8.0.4/lib/active_support/broadcast_logger.rb:218:in `block in dispatch'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activesupport-8.0.4/lib/active_support/broadcast_logger.rb:217:in `map'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activesupport-8.0.4/lib/active_support/broadcast_logger.rb:217:in `dispatch'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activesupport-8.0.4/lib/active_support/broadcast_logger.rb:129:in `error'
/var/www/discourse/plugins/discourse-ai/lib/completions/endpoints/base.rb:189:in `block (2 levels) in perform_completion!'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/net-http-0.7.0/lib/net/http.rb:2428:in `block in transport_request'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/net-http-0.7.0/lib/net/http/response.rb:320:in `reading_body'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/net-http-0.7.0/lib/net/http.rb:2425:in `transport_request'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/net-http-0.7.0/lib/net/http.rb:2379:in `request'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rack-mini-profiler-4.0.1/lib/patches/net_patches.rb:19:in `block in request_with_mini_profiler'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rack-mini-profiler-4.0.1/lib/mini_profiler/profiling_methods.rb:51:in `step'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rack-mini-profiler-4.0.1/lib/patches/net_patches.rb:18:in `request_with_mini_profiler'
/var/www/discourse/plugins/discourse-ai/lib/completions/endpoints/base.rb:187:in `block in perform_completion!'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/net-http-0.7.0/lib/net/http.rb:1626:in `start'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/net-http-0.7.0/lib/net/http.rb:1064:in `start'
/var/www/discourse/plugins/discourse-ai/lib/completions/endpoints/base.rb:140:in `perform_completion!'
/var/www/discourse/plugins/discourse-ai/lib/completions/llm.rb:447:in `generate'
/var/www/discourse/plugins/discourse-ai/lib/personas/bot.rb:90:in `reply'
/var/www/discourse/plugins/discourse-ai/lib/translation/base_translator.rb:53:in `get_translation'
/var/www/discourse/plugins/discourse-ai/lib/translation/base_translator.rb:29:in `block in translate'
/var/www/discourse/plugins/discourse-ai/lib/translation/base_translator.rb:29:in `map'
/var/www/discourse/plugins/discourse-ai/lib/translation/base_translator.rb:29:in `translate'
/var/www/discourse/plugins/discourse-ai/lib/translation/topic_localizer.rb:12:in `localize'
/var/www/discourse/plugins/discourse-ai/app/jobs/regular/localize_topics.rb:40:in `block (2 levels) in execute'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-8.0.4/lib/active_record/relation/delegation.rb:101:in `each'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-8.0.4/lib/active_record/relation/delegation.rb:101:in `each'
/var/www/discourse/plugins/discourse-ai/app/jobs/regular/localize_topics.rb:38:in `block in execute'
/var/www/discourse/plugins/discourse-ai/app/jobs/regular/localize_topics.rb:22:in `each'
/var/www/discourse/plugins/discourse-ai/app/jobs/regular/localize_topics.rb:22:in `execute'
/var/www/discourse/app/jobs/base.rb:318:in `block (2 levels) in perform'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rails_multisite-7.0.0/lib/rails_multisite/connection_management/null_instance.rb:49:in `with_connection'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rails_multisite-7.0.0/lib/rails_multisite/connection_management.rb:17:in `with_connection'
/var/www/discourse/app/jobs/base.rb:305:in `block in perform'
/var/www/discourse/app/jobs/base.rb:301:in `each'
/var/www/discourse/app/jobs/base.rb:301:in `perform'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:220:in `execute_job'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:185:in `block (4 levels) in process'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/middleware/chain.rb:180:in `traverse'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/middleware/chain.rb:183:in `block in traverse'
/var/www/discourse/lib/sidekiq/discourse_event.rb:6:in `call'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/middleware/chain.rb:182:in `traverse'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/middleware/chain.rb:183:in `block in traverse'
/var/www/discourse/lib/sidekiq/pausable.rb:131:in `call'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/middleware/chain.rb:182:in `traverse'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/middleware/chain.rb:183:in `block in traverse'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/job/interrupt_handler.rb:9:in `call'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/middleware/chain.rb:182:in `traverse'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/middleware/chain.rb:183:in `block in traverse'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/metrics/tracking.rb:26:in `track'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/metrics/tracking.rb:134:in `call'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/middleware/chain.rb:182:in `traverse'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/middleware/chain.rb:173:in `invoke'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:184:in `block (3 levels) in process'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:145:in `block (6 levels) in dispatch'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/job_retry.rb:118:in `local'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:144:in `block (5 levels) in dispatch'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/config.rb:39:in `block in <class:Config>'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:139:in `block (4 levels) in dispatch'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:281:in `stats'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:134:in `block (3 levels) in dispatch'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/job_logger.rb:15:in `call'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:133:in `block (2 levels) in dispatch'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/job_retry.rb:85:in `global'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:132:in `block in dispatch'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/job_logger.rb:40:in `prepare'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:131:in `dispatch'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:183:in `block (2 levels) in process'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:182:in `handle_interrupt'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:182:in `block in process'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:181:in `handle_interrupt'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:181:in `process'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:86:in `process_one'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/processor.rb:76:in `run'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/component.rb:10:in `watchdog'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/sidekiq-7.3.9/lib/sidekiq/component.rb:19:in `block in safe_thread'
번역에 무료 티어를 사용하는 것을 권장하지 않습니다. 간단한 게시글 하나를 번역하는 데도 무료 티어의 할당량이 모두 소진될 수 있습니다.
토큰을 소모하는 게시글이 무엇인지 확인하려면 다음 쿼리를 사용할 수 있습니다:
-- [params]
-- date :start_date = '2025-11-01'
SELECT
feature_name,
created_at,
post_id,
response_tokens
FROM
ai_api_audit_logs
WHERE
post_id IS NOT NULL
AND created_at > :start_date
AND (response_tokens IS NULL OR response_tokens != 1)
ORDER BY
created_at DESC
여전히 고객님의 사이트에 접근 권한이 있으므로, 데이터 탐색기에서 해당 쿼리를 생성해 두었습니다. 실제로 할당량을 모두 소진한 게시글이며, /admin/plugins/explorer/queries/7 경로에서 확인할 수 있습니다.
아니요, 우리는 요청을 추적하지 않습니다. 사실, 이 기능을 위해 요청 횟수로 제한되는 무료 플랜을 사용하는 것은 전혀 권장하지 않습니다. 번역을 위해 키에 비용을 지불하거나 해당 기능을 끄는 것이 좋습니다.
AI 기능을 사용할 때 우리가 중요하게 여기는 것은 요청 횟수가 아니라 토큰 사용량입니다. 토큰 사용량은 /admin/plugins/discourse-ai/ai-usage에서 매우 잘 관리할 수 있는 기능입니다. 우리의 시스템은 요청 횟수에 대해서는 신경 쓰지 않습니다.
정말 정확하고 훌륭한 지적입니다. 각 페르소나나 모델별로 서로 다른 프로젝트를 사용해 API 속도 제한이 서로 영향을 주지 않도록 하고, 더 높은 한도를 확보할 수 있는 방법을 알아보겠습니다.
여기서 질문이 하나 있습니다. Discourse에서 모든 페르소나나 AI 서비스가 동일한 API 키를 사용하는 데 어떤 이점이 있을까요? AI 서비스가 다른 API 키를 사용하는 경우, 모두 동일한 키를 사용하는 경우와 비교하여 어떤 컨텍스트나 히스토리가 손실되나요? 아니면 각 요청이 완전히 독립적이고 트랜잭션 기반인 것인가요?