Discourse AI provoquant de nouvelles erreurs SSL et Connection Reset by Peer

Priorité/Sévérité :
Les récentes modifications du dépôt rendent Discourse AI presque inutilisable avec l’API OpenAI actuelle.

Plateforme :

  • Auto-hébergé, utilisant la version autonome standard
  • VM hôte Ubuntu 24.04, conteneurs Docker
  • API OpenAI
  • API Anthropic

Description :

Discourse AI appelait une API externe - OpenAI avec des modèles et fonctionnait bien jusqu’au 15 février (dernier rebuild du conteneur). Aujourd’hui (21 février), j’ai reconstruit le conteneur et cela ne fonctionne plus.

Voici ce que je sais :

Au 15 février
Modèles OpenAI configurés et fonctionnels :

  • LLM/Persona
    • GPT4 Omni
    • GPT4 Omni Mini
  • Embeddings
    • text-embedding-ada-002

Au 21 février

Tous les modèles OpenAI présentent un taux d’erreur d’environ 70-80 % pour les appels LLM avec le message d’erreur “Connection Reset by Peer”. Certaines conversations passent, d’autres échouent en cours de route. Les appels d’embedding échouent avec une erreur SSL Faraday::ConnectionFailed.

D’autres modèles OpenAI échouent également :

  • o1-mini et o1-preview échouent lors du test/enregistrement du LLM avec une erreur de code (‘developer’ n’est pas un rôle valide) car le rôle ‘developer’ n’est valide que pour les modèles o1 et o3, et non pour leurs versions -mini. Le code source github.com/discourse/discourse-ai/…/chat_gpt.rb:61 doit être mis à jour pour effectuer une correspondance exacte du nom du modèle et non une correspondance starts_with. Pour le cas else à la ligne 73, il n’y a plus d’utilisateur system et cela doit être mis à jour pour être simplement user. À ce jour, o1-mini ne peut pas utiliser d’outils.

J’ai essayé :

  • Vérifié les limites de la plateforme OpenAI : nous sommes bien en dessous des limites de débit et le compte OpenAI est financé.
  • Reconstruit le conteneur
  • Supprimé et recréé les personas et utilisateurs LLM
  • Supprimé et recréé les modèles LLM
  • Créé de nouvelles clés de token API
  • Vérifié que les certificats SSL ont été mis à jour à l’intérieur du conteneur
  • Connecté au conteneur et utilisé bash & curl pour appeler l’API (avec succès)
  • Connecté à la console Rails RAILS_ENV=production bundle exec rails console et utilisé un objet http pour appeler l’API OpenAI (avec succès)
  • Appels API Anthropic vers claude-3.5-sonnet (avec succès)

Étapes reproductibles :

Créer une nouvelle build de conteneur en utilisant la dernière version de Discourse et ajouter le plugin Discourse AI aux plugins :

  ...
  after_code:
    - exec:
        cd: $home/plugins
        cmd:
          - git clone https://github.com/discourse/discourse-ai.git

Configurer les modèles LLM et Embeddings OpenAI avec les paramètres suivants :

  • GPT4 Omni, GPT4 Omni Mini
    • Toutes les valeurs par défaut, insérez votre clé API
    • Tokens : 64000
    • Cliquez sur “Run test”, attendez la réponse, parfois succès, souvent “Internal Server Error”. Lorsque cela réussit, essayer de discuter avec le persona provoque la stack trace Inference LLM Model
  • text-embedding-ada-002, text-embedding-3-large
    • Sauvegarde réussie, génère des journaux d’erreurs, plusieurs répétitions toutes les 5 minutes

Stack trace Internal Server Error

Stack trace Internal Server Error
Message (2 copies rapportées)
Errno::ECONNRESET (Connection reset by peer)
app/controllers/application_controller.rb:427:in `block in with_resolved_locale'
app/controllers/application_controller.rb:427:in `with_resolved_locale'
lib/middleware/omniauth_bypass_middleware.rb:35:in `call'
lib/content_security_policy/middleware.rb:12:in `call'
lib/middleware/anonymous_cache.rb:409:in `call'
lib/middleware/csp_script_nonce_injector.rb:12:in `call'
config/initializers/008-rack-cors.rb:26:in `call'
config/initializers/100-quiet_logger.rb:20:in `call'
config/initializers/100-silence_logger.rb:29:in `call'
lib/middleware/enforce_hostname.rb:24:in `call'
lib/middleware/processing_request.rb:12:in `call'
lib/middleware/request_tracker.rb:385:in `call'
Backtrace
openssl (3.3.0) lib/openssl/buffering.rb:217:in `sysread_nonblock'
openssl (3.3.0) lib/openssl/buffering.rb:217:in `read_nonblock'
net-protocol (0.2.2) lib/net/protocol.rb:218:in `rbuf_fill'
net-protocol (0.2.2) lib/net/protocol.rb:199:in `readuntil'
net-protocol (0.2.2) lib/net/protocol.rb:209:in `readline'
net-http (0.6.0) lib/net/http/response.rb:625:in `read_chunked'
net-http (0.6.0) lib/net/http/response.rb:595:in `block in read_body_0'
net-http (0.6.0) lib/net/http/response.rb:570:in `inflater'
net-http (0.6.0) lib/net/http/response.rb:593:in `read_body_0'
net-http (0.6.0) lib/net/http/response.rb:363:in `read_body'
plugins/discourse-ai/lib/completions/endpoints/base.rb:374:in `non_streaming_response'
plugins/discourse-ai/lib/completions/endpoints/base.rb:160:in `block (2 levels) in perform_completion!'
net-http (0.6.0) lib/net/http.rb:2433:in `block in transport_request'
net-http (0.6.0) lib/net/http/response.rb:320:in `reading_body'
net-http (0.6.0) lib/net/http.rb:2430:in `transport_request'
net-http (0.6.0) lib/net/http.rb:2384:in `request'
rack-mini-profiler (3.3.1) lib/patches/net_patches.rb:19:in `block in request_with_mini_profiler' 
rack-mini-profiler (3.3.1) lib/mini_profiler/profiling_methods.rb:44:in `step' 
rack-mini-profiler (3.3.1) lib/patches/net_patches.rb:18:in `request_with_mini_profiler' 
(eval at /var/www/discourse/lib/method_profiler.rb:38):12:in `request'
plugins/discourse-ai/lib/completions/endpoints/base.rb:122:in `block in perform_completion!'
net-http (0.6.0) lib/net/http.rb:1632:in `start'
net-http (0.6.0) lib/net/http.rb:1070:in `start'
plugins/discourse-ai/lib/completions/endpoints/base.rb:105:in `perform_completion!'
plugins/discourse-ai/lib/completions/endpoints/open_ai.rb:44:in `perform_completion!'
plugins/discourse-ai/lib/completions/llm.rb:281:in `generate'
plugins/discourse-ai/lib/configuration/llm_validator.rb:36:in `run_test'
plugins/discourse-ai/app/controllers/discourse_ai/admin/ai_llms_controller.rb:128:in `test'
actionpack (7.2.2.1) lib/action_controller/metal/basic_implicit_render.rb:8:in `send_action'
actionpack (7.2.2.1) lib/abstract_controller/base.rb:226:in `process_action'
actionpack (7.2.2.1) lib/action_controller/metal/rendering.rb:193:in `process_action'
actionpack (7.2.2.1) lib/abstract_controller/callbacks.rb:261:in `block in process_action'
activesupport (7.2.2.1) lib/active_support/callbacks.rb:121:in `block in run_callbacks'
app/controllers/application_controller.rb:427:in `block in with_resolved_locale'
i18n (1.14.7) lib/i18n.rb:353:in `with_locale'
app/controllers/application_controller.rb:427:in `with_resolved_locale'
activesupport (7.2.2.1) lib/active_support/callbacks.rb:130:in `block in run_callbacks'
activesupport (7.2.2.1) lib/active_support/callbacks.rb:141:in `run_callbacks'
actionpack (7.2.2.1) lib/abstract_controller/callbacks.rb:260:in `process_action'
actionpack (7.2.2.1) lib/action_controller/metal/rescue.rb:27:in `process_action'
actionpack (7.2.2.1) lib/action_controller/metal/instrumentation.rb:77:in `block in process_action'
activesupport (7.2.2.1) lib/active_support/notifications.rb:210:in `block in instrument'
activesupport (7.2.2.1) lib/active_support/notifications/instrumenter.rb:58:in `instrument'
activesupport (7.2.2.1) lib/active_support/notifications.rb:210:in `instrument'
actionpack (7.2.2.1) lib/action_controller/metal/instrumentation.rb:76:in `process_action'
actionpack (7.2.2.1) lib/action_controller/metal/params_wrapper.rb:259:in `process_action'
activerecord (7.2.2.1) lib/active_record/railties/controller_runtime.rb:39:in `process_action'
actionpack (7.2.2.1) lib/abstract_controller/base.rb:163:in `process'
actionview (7.2.2.1) lib/action_view/rendering.rb:40:in `process'
rack-mini-profiler (3.3.1) lib/mini_profiler/profiling_methods.rb:115:in `block in profile_method' 
actionpack (7.2.2.1) lib/action_controller/metal.rb:252:in `dispatch'
actionpack (7.2.2.1) lib/action_controller/metal.rb:335:in `dispatch'
actionpack (7.2.2.1) lib/action_dispatch/routing/route_set.rb:67:in `dispatch'
actionpack (7.2.2.1) lib/action_dispatch/routing/route_set.rb:50:in `serve'
actionpack (7.2.2.1) lib/action_dispatch/routing/mapper.rb:32:in `block in <class:Constraints>'
actionpack (7.2.2.1) lib/action_dispatch/routing/mapper.rb:62:in `serve'
actionpack (7.2.2.1) lib/action_dispatch/journey/router.rb:53:in `block in serve'
actionpack (7.2.2.1) lib/action_dispatch/journey/router.rb:133:in `block in find_routes'
actionpack (7.2.2.1) lib/action_dispatch/journey/router.rb:126:in `each'
actionpack (7.2.2.1) lib/action_dispatch/journey/router.rb:126:in `find_routes'
actionpack (7.2.2.1) lib/action_dispatch/journey/router.rb:34:in `serve'
actionpack (7.2.2.1) lib/action_dispatch/routing/route_set.rb:896:in `call'
lib/middleware/omniauth_bypass_middleware.rb:35:in `call'
rack (2.2.11) lib/rack/tempfile_reaper.rb:15:in `call'
rack (2.2.11) lib/rack/conditional_get.rb:27:in `call'
rack (2.2.11) lib/rack/head.rb:12:in `call'
actionpack (7.2.2.1) lib/action_dispatch/http/permissions_policy.rb:38:in `call'
lib/content_security_policy/middleware.rb:12:in `call'
lib/middleware/anonymous_cache.rb:409:in `call'
lib/middleware/csp_script_nonce_injector.rb:12:in `call'
config/initializers/008-rack-cors.rb:26:in `call'
rack (2.2.11) lib/rack/session/abstract/id.rb:266:in `context'
rack (2.2.11) lib/rack/session/abstract/id.rb:260:in `call'
actionpack (7.2.2.1) lib/action_dispatch/middleware/cookies.rb:704:in `call'
actionpack (7.2.2.1) lib/action_dispatch/middleware/callbacks.rb:31:in `block in call'
activesupport (7.2.2.1) lib/active_support/callbacks.rb:101:in `run_callbacks'
actionpack (7.2.2.1) lib/action_dispatch/middleware/callbacks.rb:30:in `call'
actionpack (7.2.2.1) lib/action_dispatch/middleware/debug_exceptions.rb:31:in `call'
actionpack (7.2.2.1) lib/action_dispatch/middleware/show_exceptions.rb:32:in `call'
logster (2.20.1) lib/logster/middleware/reporter.rb:40:in `call'
railties (7.2.2.1) lib/rails/rack/logger.rb:41:in `call_app'
railties (7.2.2.1) lib/rails/rack/logger.rb:29:in `call'
config/initializers/100-quiet_logger.rb:20:in `call'
config/initializers/100-silence_logger.rb:29:in `call'
actionpack (7.2.2.1) lib/action_dispatch/middleware/request_id.rb:33:in `call'
lib/middleware/enforce_hostname.rb:24:in `call'
rack (2.2.11) lib/rack/method_override.rb:24:in `call'
actionpack (7.2.2.1) lib/action_dispatch/middleware/executor.rb:16:in `call'
rack (2.2.11) lib/rack/sendfile.rb:110:in `call'
plugins/discourse-prometheus/lib/middleware/metrics.rb:14:in `call'
rack-mini-profiler (3.3.1) lib/mini_profiler.rb:334:in `call'
lib/middleware/processing_request.rb:12:in `call'
message_bus (4.3.9) lib/message_bus/rack/middleware.rb:60:in `call'
lib/middleware/request_tracker.rb:385:in `call'
actionpack (7.2.2.1) lib/action_dispatch/middleware/remote_ip.rb:96:in `call'
railties (7.2.2.1) lib/rails/engine.rb:535:in `call'
railties (7.2.2.1) lib/rails/railtie.rb:226:in `public_send'
railties (7.2.2.1) lib/rails/railtie.rb:226:in `method_missing'
rack (2.2.11) lib/rack/urlmap.rb:74:in `block in call'
rack (2.2.11) lib/rack/urlmap.rb:58:in `each'
rack (2.2.11) lib/rack/urlmap.rb:58:in `call'
unicorn (6.1.0) lib/unicorn/http_server.rb:634:in `process_client'
unicorn (6.1.0) lib/unicorn/http_server.rb:739:in `worker_loop'
unicorn (6.1.0) lib/unicorn/http_server.rb:547:in `spawn_missing_workers'
unicorn (6.1.0) lib/unicorn/http_server.rb:143:in `start'
unicorn (6.1.0) bin/unicorn:128:in `<top (required)>'
vendor/bundle/ruby/3.3.0/bin/unicorn:25:in `load'
vendor/bundle/ruby/3.3.0/bin/unicorn:25:in `<main>'

En examinant les journaux, les erreurs sont :

Modèle Embeddings

Message d’erreur dans les journaux : (toutes les 5 minutes) Connection reset by peer (Faraday::ConnectionFailed)

application_version : 00907363d4b290df1c755df1a2494b95265e40b4

job : Jobs::EmbeddingsBackfill

Stack trace erreur modèle Embeddings

Stack trace erreur modèle Embeddings
Exception de job : 5 erreurs
Connection reset by peer (Faraday::ConnectionFailed)
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/openssl-3.3.0/lib/openssl/buffering.rb:217:in `sysread_nonblock'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/openssl-3.3.0/lib/openssl/buffering.rb:217:in `read_nonblock'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/net-protocol-0.2.2/lib/net/protocol.rb:218:in `rbuf_fill'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/net-protocol-0.2.2/lib/net/protocol.rb:199:in `readuntil'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/net-protocol-0.2.2/lib/net/protocol.rb:209:in `readline'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/net-http-0.6.0/lib/net/http/response.rb:625:in `read_chunked'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/net-http-0.6.0/lib/net/http/response.rb:595:in `block in read_body_0'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/net-http-0.6.0/lib/net/http/response.rb:570:in `inflater'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/net-http-0.6.0/lib/net/http/response.rb:593:in `read_body_0'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/net-http-0.6.0/lib/net/http/response.rb:363:in `read_body'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/net-http-0.6.0/lib/net/http/response.rb:401:in `body'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/net-http-0.6.0/lib/net/http/response.rb:321:in `reading_body'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/net-http-0.6.0/lib/net/http.rb:2430:in `transport_request'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/net-http-0.6.0/lib/net/http.rb:2384:in `request'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rack-mini-profiler-3.3.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-3.3.1/lib/mini_profiler/profiling_methods.rb:50:in `step'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rack-mini-profiler-3.3.1/lib/patches/net_patches.rb:18:in `request_with_mini_profil...
Backtrace
concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/promises.rb:1268:in `raise' 
concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/promises.rb:1268:in `wait_until_resolved!' 
concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/promises.rb:998:in `value!' 
/var/www/discourse/plugins/discourse-ai/lib/embeddings/vector.rb:50:in `gen_bulk_reprensentations' 
/var/www/discourse/plugins/discourse-ai/app/jobs/scheduled/embeddings_backfill.rb:134:in `block in populate_topic_embeddings' 
/var/www/discourse/plugins/discourse-ai/app/jobs/scheduled/embeddings_backfill.rb:133:in `each' 
/var/www/discourse/plugins/discourse-ai/app/jobs/scheduled/embeddings_backfill.rb:133:in `each_slice' 
/var/www/discourse/plugins/discourse-ai/app/jobs/scheduled/embeddings_backfill.rb:133:in `populate_topic_embeddings' 
/var/www/discourse/plugins/discourse-ai/app/jobs/scheduled/embeddings_backfill.rb:36:in `execute' 
/var/www/discourse/app/jobs/base.rb:316:in `block (2 levels) in perform' 
rails_multisite-6.1.0/lib/rails_multisite/connection_management/null_instance.rb:49:in `with_connection'
rails_multisite-6.1.0/lib/rails_multisite/connection_management.rb:21:in `with_connection'
/var/www/discourse/app/jobs/base.rb:303:in `block in perform' 
/var/www/discourse/app/jobs/base.rb:299:in `each' 
/var/www/discourse/app/jobs/base.rb:299:in `perform' 
/var/www/discourse/app/jobs/base.rb:379:in `perform' 
mini_scheduler-0.18.0/lib/mini_scheduler/manager.rb:137:in `process_queue' 
mini_scheduler-0.18.0/lib/mini_scheduler/manager.rb:77:in `worker_loop' 
mini_scheduler-0.18.0/lib/mini_scheduler/manager.rb:63:in `block (2 levels) in ensure_worker_threads' 

Modèle LLM d’inférence

Message d’erreur dans les journaux : Exception de job : Connection reset by peer

application_version : 00907363d4b290df1c755df1a2494b95265e40b4

job : Jobs::CreateAiReply

Stack trace erreur modèle LLM

Stack trace erreur modèle LLM
Message
Exception de job : Connection reset by peer
Backtrace
openssl-3.3.0/lib/openssl/buffering.rb:217:in `sysread_nonblock' 
openssl-3.3.0/lib/openssl/buffering.rb:217:in `read_nonblock' 
net-protocol-0.2.2/lib/net/protocol.rb:218:in `rbuf_fill' 
net-protocol-0.2.2/lib/net/protocol.rb:199:in `readuntil' 
net-protocol-0.2.2/lib/net/protocol.rb:209:in `readline' 
net-http-0.6.0/lib/net/http/response.rb:625:in `read_chunked' 
net-http-0.6.0/lib/net/http/response.rb:595:in `block in read_body_0' 
net-http-0.6.0/lib/net/http/response.rb:570:in `inflater' 
net-http-0.6.0/lib/net/http/response.rb:593:in `read_body_0' 
net-http-0.6.0/lib/net/http/response.rb:363:in `read_body' 
/var/www/discourse/plugins/discourse-ai/lib/completions/endpoints/base.rb:374:in `non_streaming_response' 
/var/www/discourse/plugins/discourse-ai/lib/completions/endpoints/base.rb:160:in `block (2 levels) in perform_completion!' 
net-http-0.6.0/lib/net/http.rb:2433:in `block in transport_request' 
net-http-0.6.0/lib/net/http/response.rb:320:in `reading_body' 
net-http-0.6.0/lib/net/http.rb:2430:in `transport_request' 
net-http-0.6.0/lib/net/http.rb:2384:in `request' 
rack-mini-profiler-3.3.1/lib/patches/net_patches.rb:19:in `block in request_with_mini_profiler' 
rack-mini-profiler-3.3.1/lib/mini_profiler/profiling_methods.rb:50:in `step' 
rack-mini-profiler-3.3.1/lib/patches/net_patches.rb:18:in `request_with_mini_profiler' 
(eval at /var/www/discourse/lib/method_profiler.rb:38):5:in `request'
/var/www/discourse/plugins/discourse-ai/lib/completions/endpoints/base.rb:122:in `block in perform_completion!' 
net-http-0.6.0/lib/net/http.rb:1632:in `start' 
net-http-0.6.0/lib/net/http.rb:1070:in `start' 
/var/www/discourse/plugins/discourse-ai/lib/completions/endpoints/base.rb:105:in `perform_completion!' 
/var/www/discourse/plugins/discourse-ai/lib/completions/endpoints/open_ai.rb:44:in `perform_completion!' 
/var/www/discourse/plugins/discourse-ai/lib/completions/llm.rb:281:in `generate' 
/var/www/discourse/plugins/discourse-ai/lib/ai_bot/bot.rb:65:in `get_updated_title' 
/var/www/discourse/plugins/discourse-ai/lib/ai_bot/playground.rb:252:in `title_playground' 
/var/www/discourse/plugins/discourse-ai/lib/ai_bot/playground.rb:561:in `ensure in reply_to' 
/var/www/discourse/plugins/discourse-ai/lib/ai_bot/playground.rb:561:in `reply_to' 
/var/www/discourse/plugins/discourse-ai/app/jobs/regular/create_ai_reply.rb:18:in `execute' 
/var/www/discourse/app/jobs/base.rb:316:in `block (2 levels) in perform' 
rails_multisite-6.1.0/lib/rails_multisite/connection_management/null_instance.rb:49:in `with_connection'
rails_multisite-6.1.0/lib/rails_multisite/connection_management.rb:21:in `with_connection'
/var/www/discourse/app/jobs/base.rb:303:in `block in perform' 
/var/www/discourse/app/jobs/base.rb:299:in `each' 
/var/www/discourse/app/jobs/base.rb:299:in `perform' 
sidekiq-6.5.12/lib/sidekiq/processor.rb:202:in `execute_job' 
sidekiq-6.5.12/lib/sidekiq/processor.rb:170:in `block (2 levels) in process' 
sidekiq-6.5.12/lib/sidekiq/middleware/chain.rb:177:in `block in invoke' 
/var/www/discourse/lib/sidekiq/pausable.rb:132:in `call' 
sidekiq-6.5.12/lib/sidekiq/middleware/chain.rb:179:in `block in invoke' 
sidekiq-6.5.12/lib/sidekiq/middleware/chain.rb:182:in `invoke' 
sidekiq-6.5.12/lib/sidekiq/processor.rb:169:in `block in process' 
sidekiq-6.5.12/lib/sidekiq/processor.rb:136:in `block (6 levels) in dispatch' 
sidekiq-6.5.12/lib/sidekiq/job_retry.rb:113:in `local' 
sidekiq-6.5.12/lib/sidekiq/processor.rb:135:in `block (5 levels) in dispatch' 
sidekiq-6.5.12/lib/sidekiq.rb:44:in `block in <module:Sidekiq>' 
sidekiq-6.5.12/lib/sidekiq/processor.rb:131:in `block (4 levels) in dispatch' 
sidekiq-6.5.12/lib/sidekiq/processor.rb:263:in `stats' 
sidekiq-6.5.12/lib/sidekiq/processor.rb:126:in `block (3 levels) in dispatch' 
sidekiq-6.5.12/lib/sidekiq/job_logger.rb:13:in `call' 
sidekiq-6.5.12/lib/sidekiq/processor.rb:125:in `block (2 levels) in dispatch' 
sidekiq-6.5.12/lib/sidekiq/job_retry.rb:80:in `global' 
sidekiq-6.5.12/lib/sidekiq/processor.rb:124:in `block in dispatch' 
sidekiq-6.5.12/lib/sidekiq/job_logger.rb:39:in `prepare' 
sidekiq-6.5.12/lib/sidekiq/processor.rb:123:in `dispatch' 
sidekiq-6.5.12/lib/sidekiq/processor.rb:168:in `process' 
sidekiq-6.5.12/lib/sidekiq/processor.rb:78:in `process_one' 
sidekiq-6.5.12/lib/sidekiq/processor.rb:68:in `run' 
sidekiq-6.5.12/lib/sidekiq/component.rb:8:in `watchdog' 
sidekiq-6.5.12/lib/sidekiq/component.rb:17:in `block in safe_thread' 

Toute idée, suggestion, etc. serait la bienvenue

1 « J'aime »

Nous avons effectué plus de 2 000 requêtes pour l’API OpenAI sur ce site le mois dernier, et nous n’avons aucune erreur de ce type dans nos journaux.

J’ai examiné un autre site que nous hébergeons, qui utilise intensivement OpenAI, avec 80 000 requêtes le mois dernier, et ils n’ont aucune erreur Faraday, et seulement deux erreurs « Connection Reset by Peer » sur la période.

Est-il possible que votre serveur ait un problème réseau ? J’ai eu Errno::ECONNRESET (Connection reset by peer) une fois à cause d’un pilote NIC défectueux.

Je vais examiner cela.

1 « J'aime »

Comme vous l’avez écrit, j’ai d’abord pensé qu’il s’agissait d’un problème de pile réseau, mais les appels répétés à l’API OpenAI depuis le conteneur lui-même fonctionnent bien.

Ceci est également avec une version très récente, des commits datant du 21 février.

Pour le prouver (au prix de la consommation de tokens), j’ai élaboré un script rapide pour vérifier la pile réseau OpenAI.

  • S’exécute pendant 600 secondes (10 minutes)
  • Effectue un appel de complétion de chat par seconde
  • Change l’invite pour éviter le cache

Exécutez à l’intérieur du conteneur ./launcher enter app, enregistrez le script ci-dessous, rendez-le exécutable avec chmod +x test_openai.sh et appelez-le ensuite avec OPENAI_API_KEY=.... ./test_openai.sh

test_openai.sh
#!/bin/bash

# Durée d'exécution
DURATION_SECS=600

# Initialiser les compteurs
successful=0
unsuccessful=0
declare -A error_messages

# Fonction pour calculer le pourcentage
calc_percentage() {
    local total=$(($1 + $2))
    if [ $total -eq 0 ]; then
        echo "0.00"
    else
        echo "scale=2; ($2 * 100) / $total" | bc
    fi
}

# Fonction pour afficher les statistiques
print_stats() {
    local percent=$(calc_percentage $successful $unsuccessful)
    echo "-------------------"
    echo "Appels réussis : $successful"
    echo "Appels échoués : $unsuccessful"
    echo "Taux d'échec : ${percent}%"
    echo "Messages d'erreur :"
    for error in "${!error_messages[@]}"; do
        echo "  - $error (${error_messages[$error]} fois)"
    done
}

end_time=$((SECONDS + DURATION_SECS))

counter=1
while [ $SECONDS -lt $end_time ]; do
    # Effectuer l'appel API avec timeout
    response=$(curl -s -w "\n%{http_code}" \
        -X POST \
        -H "Content-Type: application/json" \
        -H "Authorization: Bearer $OPENAI_API_KEY" \
        -d "{
            \"model\": \"gpt-4o-mini\",
            \"messages\": [{\"role\": \"user\", \"content\": \"Utilise ce nombre pour choisir une réponse en un mot : $counter\"}]
        }" \
        --connect-timeout 5 \
        --max-time 10 \
        https://api.openai.com/v1/chat/completions 2>&1)

    # Obtenir la dernière ligne (code de statut) et le corps de la réponse
    http_code=$(echo "$response" | tail -n1)
    body=$(echo "$response" | sed '$d')

    # Vérifier si l'appel a réussi
    if [ "$http_code" = "200" ]; then
        ((successful++))
    else
        ((unsuccessful++))
        # Extraire le message d'erreur
        error_msg=$(echo "$body" | grep -o '"message":"[^"]*"' | cut -d'"' -f4)
        if [ -z "$error_msg" ]; then
            error_msg="Erreur de connexion : $body"
        fi
        # Incrémenter le compteur de message d'erreur
        ((error_messages["$error_msg"]++))
    fi

    # Afficher les statistiques actuelles
    print_stats

    ((counter++))
    
    # Attendre 1 seconde avant le prochain appel
    sleep 1
done

Pour le script de test, mon taux d’échec était inférieur à 0,5 %, ce qui est acceptable à cette échelle.

Cela me dit que le problème réside dans le logiciel Discourse plutôt que dans le conteneur ou la pile réseau qui l’alimente.

S’il n’a pas été corrigé avec un commit récent, je vais y regarder de plus près.

2 « J'aime »

J’ai corrigé la régression autour de o1-mini et o1-preview ici :

Cependant, je suis confus au sujet des problèmes SSL, nous n’avons rien changé à notre bibliothèque sous-jacente ici.

C’est peut-être lié au streaming, essayez de désactiver le streaming sur votre LLM OpenAI et voyez si cela se résout ? votre test là-bas utilise gpt-4o-mini sans utiliser le streaming.

3 « J'aime »

C’est génial ! Bien joué !

Dans le processus de diagnostic, j’ai trouvé un autre bug : sur la page de configuration LLM (/admin/plugins/discourse-ai/ai-llms/%/edit), la sélection de l’une ou l’autre option pour « Désactiver la prise en charge des outils natifs (utiliser des outils basés sur XML) (facultatif) » ou « Désactiver les complétions en streaming (convertir les requêtes en streaming en requêtes non-streaming) » et la clique sur Enregistrer affiche un toast temporaire « Succès ! », mais le rechargement de la page montre que les deux options ou l’une d’elles sont décochées.

Les problèmes de réinitialisation de connexion persistent et je continue de les examiner, mais il semble qu’il s’agisse d’une combinaison du code Ruby (FinalDestination / résolution DNS / Faraday) pour la gestion des sockets, combinée à un conteneur Debian 12 sur une VM Ubuntu 24.04.

J’ai lancé une VM de test Ubuntu 22.04 et il n’y a aucun problème, toutes les intégrations et l’inférence fonctionnent parfaitement. Je n’ai vu aucune réinitialisation.

Je vais continuer à y travailler, peut-être est-ce lié à une nouvelle façon dont Ubuntu 24.04 gère la pile TCP avec netplan.

2 « J'aime »

Merci, j’ai résolu ce problème de persistance aujourd’hui, pouvez-vous mettre à niveau et réessayer

3 « J'aime »

Ok, petite mise à jour : nous n’avons pas réussi à établir de connexion directe à l’API OpenAI sur la plage d’adresses IP de l’entreprise. Cloudflare envoyait des paquets RST environ 1 ms après la connexion TLS.

Nous avons donc configuré une Cloudflare AI Gateway comme remplacement transparent de l’URL du point de terminaison de l’API OpenAI, et cela fonctionne parfaitement avec la configuration LLM.

Il semble que Cloudflare ait une politique de limitation de débit non documentée pour les plages d’adresses IP inconnues (c’est-à-dire non Azure, AWS, GCP, etc.) qui s’active. Le pool de 100 connexions pour les Embeddings déclencherait cette limite.

Par ailleurs, Cloudflare propose une fonctionnalité Authenticated Gateway qui ajoute un jeton d’en-tête spécial.

D’après leur documentation :

curl https://gateway.ai.cloudflare.com/v1/{account_id}/{gateway_id}/openai/chat/completions \
  --header 'cf-aig-authorization: Bearer {CF_AIG_TOKEN}' \
  --header 'Authorization: Bearer OPENAI_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{\"model\": \"gpt-4o\" .......

Ce serait génial s’il existait une fonctionnalité pour ajouter des en-têtes par LLM dans l’écran de configuration du LLM.

De cette façon, nous pourrions ajouter la clé et la valeur cf-aig-authorization au LLM pour chaque appel que nous effectuons.

C’est difficile, cela représente beaucoup d’interface utilisateur pour un cas extrême.

Y a-t-il une chance que vous puissiez essayer openrouter.ai, cela pourrait également résoudre ce problème ?

Je ne suis pas catégoriquement contre l’autorisation d’en-têtes arbitraires, mais c’est une configuration très avancée. Peut-être que si c’était derrière un paramètre de site caché, ce serait bien (paramètre de site pour activer l’interface utilisateur avancée).

Est-ce une contribution que votre entreprise pourrait aider à promouvoir pour le plugin open source ?

1 « J'aime »

Je n’ai pas encore réussi à obtenir l’approbation pour une contribution, mais nous continuerons d’essayer. Merci pour l’aide jusqu’à présent !