# Discourse AI로 인해 새로운 SSL 및 Connection Reset by Peer 오류 발생

**URL:** https://meta.discourse.org/t/discourse-ai-causing-new-ssl-and-connection-reset-by-peer-errors/353600
**Category:** Bug
**Tags:** ai
**Created:** [2월 21, 2025, 1:21오후 UTC](https://meta.discourse.org/t/discourse-ai-causing-new-ssl-and-connection-reset-by-peer-errors/353600 "2025-02-21T13:21:26Z")
**Posts on this page:** 10
**Page:** 1

<div class="post-metadata">

### Author: ![oznyet](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/oznyet/32/489947_2.png) [@oznyet](https://meta.discourse.org/u/oznyet)
#### Post date: [2월 21, 2025, 1:21오후 UTC](https://meta.discourse.org/t/discourse-ai-causing-new-ssl-and-connection-reset-by-peer-errors/353600/1 "2025-02-21T13:21:26Z")

</div>

**우선순위/중요도** :  
최근 저장소 변경 사항으로 인해 현재 OpenAI API와 함께 Discourse AI가 거의 작동하지 않습니다.

**플랫폼** :

- 자체 호스팅, 표준 스탠드얼론 빌드 사용
- Ubuntu 24.04 호스트 VM, Docker 컨테이너
- OpenAI API
- Anthropic API

**설명** :

Discourse AI는 외부 API인 OpenAI 모델을 호출하고 있으며, 2월 15일(마지막 컨테이너 재빌드)까지는 잘 작동하고 있었습니다. 오늘(2월 21일) 컨테이너를 재빌드한 후 문제가 발생했습니다.

알고 있는 내용은 다음과 같습니다:

**2월 15일 기준**  
설정 및 정상 작동 중이던 OpenAI 모델:

- LLM/페르소나
  - GPT4 Omni
  - GPT4 Omni Mini

- 임베딩
  - text-embedding-ada-002

**2월 21일 기준**

모든 OpenAI 모델에서 LLM 호출 시 약 70~80%의 오류율이 발생하며, 오류 메시지는 "Connection Reset by Peer"입니다. 일부 채팅은 성공하지만, 일부는 중간에 실패합니다. 임베딩 호출은 `Faraday::ConnectionFailed` SSL 오류로 실패합니다.

추가적으로 실패하는 OpenAI 모델:

- o1-mini와 o1-preview는 LLM 테스트/저장 시 코드 오류(‘developer’ is not a valid role)로 실패합니다. ‘developer’ 역할은 `o1` 및 `o3` 모델에서만 유효하며, `-mini` 버전에서는 유효하지 않기 때문입니다. 소스 코드 [github.com/discourse/discourse-ai/…/chat\_gpt.rb:61](https://github.com/discourse/discourse-ai/blob/f9220124991357d5f3044c6cce4a9f62a4a5763a/lib/completions/dialects/chat_gpt.rb#L61)은 `starts_with` 매칭이 아닌 정확한 모델 이름 매칭을 수행하도록 업데이트되어야 합니다. 73번째 줄의 `else` 케이스에는 더 이상 `system` 사용자가 없으므로, 단순히 `user`로 업데이트해야 합니다. 현재 `o1-mini`는 도구를 사용할 수 없습니다.

시도해 본 내용:

- OpenAI 플랫폼 한도를 확인했으며, Rate Limits를 훨씬 하회하고 OpenAI 계정에 잔액이 있습니다.
- 컨테이너 재빌드
- LLM 페르소나 및 사용자 삭제 후 재생성
- LLM 모델 삭제 후 생성
- 새로운 API 토큰 키 생성
- 컨테이너 내부에서 SSL 및 인증서가 업데이트되었는지 확인
- 컨테이너에 로그인하여 bash 및 curl을 사용하여 API 호출 (성공)
- rails 콘솔 `RAILS_ENV=production bundle exec rails console`에 로그인하여 http 객체를 사용해 OpenAI API 호출 (성공)
- claude-3.5-sonnet에 대한 Anthropic API 호출 (성공)

**재현 단계** :

최신 Discourse를 사용하여 새로운 컨테이너 빌드를 생성하고 plugins에 Discourse AI 플러그인을 추가합니다:

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

```

다음과 같이 OpenAI LLM 및 임베딩 모델을 구성합니다:

- GPT4 Omni, GPT4 Omni Mini
  - 모든 기본값 유지, API 키 삽입
  - 토큰: 64000
  - “테스트 실행” 클릭, 응답 대기, 때로는 성공하지만 종종 “Internal Server Error” 발생. 성공하더라도 페르소나와 채팅을 시도하면 Inference LLM Model 스택 트레이스가 나타남

- text-embedding-ada-002, text-embedding-3-large
  - 성공적으로 저장되지만, 오류 로그 생성, 5분마다 반복적으로 발생

### Internal Server Error 스택 트레이스

> **Internal Server Error 스택 트레이스**
>
> ```plaintext
> Message (2 copies reported)
> 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/contentsecurity_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/contentsecurity_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>'
> 
> ```

로그를 확인하면 다음과 같은 오류가 있습니다:

## 임베딩 모델

로그의 오류 메시지: _(5분마다)_ `Connection reset by peer (Faraday::ConnectionFailed)`

application\_version: `00907363d4b290df1c755df1a2494b95265e40b4`

job: `Jobs::EmbeddingsBackfill`

### 임베딩 모델 오류 스택 트레이스

> **임베딩 모델 오류 스택 트레이스**
>
> ```plaintext
> Job exception: 5 errors
> 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' 
> 
> ```

## 추론 LLM 모델

로그의 오류 메시지: `Job exception: Connection reset by peer`

application\_version: `00907363d4b290df1c755df1a2494b95265e40b4`

job: `Jobs::CreateAiReply`

### LLM 모델 오류 스택 트레이스

> **LLM 모델 오류 스택 트레이스**
>
> ```plaintext
> Message
> Job exception: 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' 
> 
> ```

아무 아이디어나 제안 등이 있다면 매우 환영합니다

---

<div class="post-metadata">

### Author: ![Falco](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/falco/32/179432_2.png) [@Falco](https://meta.discourse.org/u/Falco)
#### Post date: [2월 21, 2025, 3:43오후 UTC](https://meta.discourse.org/t/discourse-ai-causing-new-ssl-and-connection-reset-by-peer-errors/353600/4 "2025-02-21T15:43:54Z")

</div>

> [@oznyet](#):
>
> 모든 OpenAI 모델에서 LLM 호출 시 “Connection Reset by Peer” 오류 메시지와 함께 약 70~80%의 오류율이 발생하고 있습니다. 일부 채팅은 정상적으로 처리되지만, 일부는 중간에 실패합니다. 임베딩(Embedding) 호출은 `Faraday::ConnectionFailed` SSL 오류로 실패합니다.

지난 한 달 동안 이 사이트에서 OpenAI API에 2,000건 이상의 요청을 보냈지만, 로그에 그러한 오류는 없습니다.

우리가 호스팅하는 OpenAI를 대량으로 사용하는 다른 사이트에는 지난 한 달 동안 80,000건의 요청이 있었고, Faraday 오류는 전혀 없으며, 해당 기간 동안 “Connection Reset by Peer” 오류는 단 두 건만 발생했습니다.

서버의 네트워크 구성에 문제가 있는 것은 아닌지 확인해 보셨나요? 한 번은 불량한 NIC 드라이버 때문에 `Errno::ECONNRESET (Connection reset by peer)` 오류가 발생한 적이 있습니다.

> [@oznyet](#):
>
> o1-mini와 o1-preview는 LLM 테스트/저장 시 코드 오류(‘developer’는 유효한 역할이 아님)로 실패합니다. 이는 developer 역할이 `o1` 및 `o3` 모델에만 유효하고, `-mini` 버전에는 적용되지 않기 때문입니다. 소스 코드 [github.com/discourse/discourse-ai/…/chat\_gpt.rb:61](https://github.com/discourse/discourse-ai/blob/f9220124991357d5f3044c6cce4a9f62a4a5763a/lib/completions/dialects/chat_gpt.rb#L61)는 `starts_with` 매칭이 아닌 정확한 모델 이름 매칭을 수행하도록 업데이트되어야 합니다. 73번째 줄의 `else` 케이스에서는 더 이상 `system` 사용자가 없으므로 단순히 `user`로 업데이트해야 합니다. 현재 시점에서 `o1-mini`는 도구를 사용할 수 없습니다.

확인해 보겠습니다.

---

<div class="post-metadata">

### Author: ![oznyet](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/oznyet/32/489947_2.png) [@oznyet](https://meta.discourse.org/u/oznyet)
#### Post date: [2월 23, 2025, 11:33오후 UTC](https://meta.discourse.org/t/discourse-ai-causing-new-ssl-and-connection-reset-by-peer-errors/353600/5 "2025-02-23T23:33:13Z")

</div>

말씀하신 대로, 처음에는 네트워크 스택 문제인 줄 알았지만, 해당 컨테이너에서 반복적으로 OpenAI API를 호출하면 정상적으로 동작합니다.

또한, 이는 2월 21일 기준으로 매우 최근의 빌드에서 테스트한 것입니다.

이를 증명하기 위해(토큰 소모를 감수하고) OpenAI 네트워크 스택을 확인하기 위한 간단한 스크립트를 작성했습니다.

- 600초(10분) 동안 실행됩니다.
- 초당 1회씩 채팅 완성(chat completion) 호출을 수행합니다.
- 캐시를 피하기 위해 프롬프트를 변경합니다.

컨테이너 내부에서 `./launcher enter app`을 실행하고, 아래 스크립트를 저장한 후 `chmod +x test_openai.sh`로 실행 권한을 부여하고, `OPENAI_API_KEY=.... ./test_openai.sh`로 실행하세요.

> **test\_openai.sh**
>
> ```bash
> #!/bin/bash
> 
> # 실행 시간
> DURATION_SECS=600
> 
> # 카운터 초기화
> successful=0
> unsuccessful=0
> declare -A error_messages
> 
> # 백분율 계산 함수
> calc_percentage() {
> local total=$(($1 + $2))
> if [$total -eq 0]; then
> echo "0.00"
> else
> echo "scale=2; ($2 * 100) / $total" | bc
> fi
> }
> 
> # 통계 출력 함수
> print_stats() {
> local percent=$(calc_percentage $successful $unsuccessful)
> echo "-------------------"
> echo "성공한 호출: $successful"
> echo "실패한 호출: $unsuccessful"
> echo "실패율: ${percent}%"
> echo "에러 메시지:"
> for error in "${!error_messages[@]}"; do
> echo " - $error (${error_messages[$error]} 회)"
> done
> }
> 
> end_time=$((SECONDS + DURATION_SECS))
> 
> counter=1
> while [$SECONDS -lt $end_time]; do
> # 타임아웃과 함께 API 호출 수행
> 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\": \"Use this number to choose a one word response: $counter\"}]
> }" \
> --connect-timeout 5 \
> --max-time 10 \
> https://api.openai.com/v1/chat/completions 2>&1)
> 
> # 마지막 줄(상태 코드)과 응답 본문 가져오기
> http_code=$(echo "$response" | tail -n1)
> body=$(echo "$response" | sed '$d')
> 
> # 호출이 성공했는지 확인
> if ["$http_code" = "200"]; then
> ((successful++))
> else
> ((unsuccessful++))
> # 에러 메시지 추출
> error_msg=$(echo "$body" | grep -o '"message":"[^"]*"' | cut -d'"' -f4)
> if [-z "$error_msg"]; then
> error_msg="Connection error: $body"
> fi
> # 에러 메시지 카운터 증가
> ((error_messages["$error_msg"]++))
> fi
> 
> # 현재 통계 출력
> print_stats
> 
> ((counter++))
>     
> # 다음 호출 전 1초 대기
> sleep 1
> done
> 
> ```

테스트 스크립트 실행 결과, 실패율은 0.5% 미만으로, 해당 규모에서는 허용 가능한 수준이었습니다.

이로써 문제는 컨테이너나 이를 구동하는 네트워크 스택이 아니라 Discourse 소프트웨어 자체에 있음을 알 수 있습니다.

최근 커밋으로 해결되지 않았다면, 더 자세히 조사해 보겠습니다.

---

<div class="post-metadata">

### Author: ![sam](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/sam/32/102149_2.png) [@sam](https://meta.discourse.org/u/sam)
#### Post date: [2월 24, 2025, 5:40오전 UTC](https://meta.discourse.org/t/discourse-ai-causing-new-ssl-and-connection-reset-by-peer-errors/353600/6 "2025-02-24T05:40:05Z")

</div>

o1-mini와 o1-preview 주변의 회귀 버그를 여기에서 수정했습니다:

> <https://github.com/discourse/discourse-ai/pull/1149>
>
> 1. Legacy reasoning models (o1-preview / o1-mini) do not support developer or sy…stem messages, do not use them.
> 2. LLM editor form not showing all provider params due to missing remap

다만 SSL 문제에 대해서는 이해가 잘 안 됩니다. 우리는 여기서 기초 라이브러리를 변경한 적이 없거든요.

이것이 스트리밍과 관련이 있을 수 있으니, OpenAI LLM에서 스트리밍을 비활성화해 보시고 문제가 해결되는지 확인해 보세요. 해당 테스트에서는 스트리밍을 사용하지 않고 gpt-4o-mini를 사용하고 있습니다.

---

<div class="post-metadata">

### Author: ![oznyet](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/oznyet/32/489947_2.png) [@oznyet](https://meta.discourse.org/u/oznyet)
#### Post date: [2월 25, 2025, 10:05오전 UTC](https://meta.discourse.org/t/discourse-ai-causing-new-ssl-and-connection-reset-by-peer-errors/353600/7 "2025-02-25T10:05:23Z")

</div>

> [@sam](#):
>
> o1-mini와 o1-preview 주위의 회귀 문제를 여기서 수정했습니다:
> 
> [FIX: legacy reasoning models not working, missing provider params by SamSaffron · Pull Request #1149 · discourse/discourse-ai · GitHub](https://github.com/discourse/discourse-ai/pull/1149)

정말 훌륭합니다! 잘 하셨습니다!

진단하는 과정에서 또 다른 버그를 발견했습니다. LLM 설정 페이지(`/admin/plugins/discourse-ai/ai-llms/%/edit`)에서 _“네이티브 도구 지원 비활성화 (XML 기반 도구 사용) (선택)”_ 또는 _“스트리밍 완료 비활성화 (스트리밍을 비스트리밍 요청으로 변환)”_ 옵션 중 하나를 선택하고 저장 버튼을 클릭하면 "성공!"이라는 임시 토스트 알림이 표시되지만, 페이지를 새로고침하면 두 옵션 중 하나 또는 둘 다 해제되어 있습니다.

연결 리셋 문제는 여전히 지속되고 있으며 저는 여전히 조사 중이지만, Ruby 코드(FinalDestination / DNS 이름 해석 / Faraday)의 소켓 처리와 Debian 12 컨테이너가 Ubuntu 24.04 VM에서 실행되는 환경이 결합된 것으로 보입니다.

테스트용 Ubuntu 22.04 VM을 설정해 보았더니 문제가 없으며, 모든 임베딩과 추론이 완벽하게 작동합니다. 리셋 현상을 한 번도 목격하지 못했습니다.

계속해서 문제를 파헤쳐 보겠습니다. 아마도 Ubuntu 24.04가 netplan으로 TCP 스택을 관리하는 새로운 방식과 관련이 있을 수도 있습니다.

---

<div class="post-metadata">

### Author: ![sam](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/sam/32/102149_2.png) [@sam](https://meta.discourse.org/u/sam)
#### Post date: [2월 25, 2025, 10:07오전 UTC](https://meta.discourse.org/t/discourse-ai-causing-new-ssl-and-connection-reset-by-peer-errors/353600/8 "2025-02-25T10:07:59Z")

</div>

감사합니다. 오늘 영속성 문제를 해결했습니다. 업그레이드 후 다시 시도해 주세요.

---

<div class="post-metadata">

### Author: ![oznyet](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/oznyet/32/489947_2.png) [@oznyet](https://meta.discourse.org/u/oznyet)
#### Post date: [2월 26, 2025, 6:45오전 UTC](https://meta.discourse.org/t/discourse-ai-causing-new-ssl-and-connection-reset-by-peer-errors/353600/9 "2025-02-26T06:45:43Z")

</div>

자, 업데이트를 조금 하겠습니다. 기업 IP 범위에서 OpenAI API와 직접 연결을 설정하는 데 실패했습니다. Cloudflare가 TLS 직후 약 1ms 뒤에 RST 패킷을 전송했기 때문입니다.

그래서 OpenAI API 엔드포인트의 URL 드롭인 대체재로 [Cloudflare AI Gateway](https://developers.cloudflare.com/ai-gateway/)를 설정했는데, LLM 구성과 완벽하게 작동합니다.

 ![이미지는 Persona(Discourse Helper)가 사용할 GPT-4 OpenAI 모델의 서비스 호스팅을 보여주며, 이름, 모델 ID, 제공자, URL, API 키를 포함합니다. (AI가 캡션을 작성함)](https://global.discourse-cdn.com/meta/original/4X/8/4/d/84ddb7b1b7db9bcea964b2aaaaa11c865965f4d9.png)

Cloudflare에는 문서화되지 않은 레이트 리밋 정책이 있는 것 같습니다. 이는 알려지지 않은 IP 범위(예: Azure, AWS, GCP 등)에서 발동됩니다. Embeddings의 100개 연결 풀이 이 한도를 초과하게 되었습니다.

참고로, Cloudflare에는 [Authenticated Gateway](https://developers.cloudflare.com/ai-gateway/configuration/authentication/)라는 기능이 있어 특수 헤더 토큰을 추가합니다.

해당 문서에서 발췌한 내용입니다:

```bash
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" ........

```

LLM 구성 화면에서 LLM별 헤더를 추가할 수 있는 기능이 있다면 정말 좋겠습니다.

그렇게 하면 우리가 수행하는 모든 호출에 대해 LLM에 `cf-aig-authorization` 키와 값을 추가할 수 있을 것입니다.

---

<div class="post-metadata">

### Author: ![sam](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/sam/32/102149_2.png) [@sam](https://meta.discourse.org/u/sam)
#### Post date: [2월 26, 2025, 8:47오후 UTC](https://meta.discourse.org/t/discourse-ai-causing-new-ssl-and-connection-reset-by-peer-errors/353600/10 "2025-02-26T20:47:09Z")

</div>

이건 좀 까다로운 문제예요. 엣지 케이스를 위해 너무 많은 UI를 부담해야 하거든요.

혹시 openrouter.ai를 시도해 볼 수 있을까요? 이 문제도 해결될 수 있을 것 같아요.

임의의 헤더를 허용하는 것에 대해 원칙적으로 반대하는 건 아니지만, 이건 아주 고급 설정이에요. 숨겨진 사이트 설정 뒤에 두면 괜찮을 것 같아요 (고급 UI를 활성화하는 사이트 설정).

이 회사가 오픈소스 플러그인에 대한 이 기여를 주도할 수 있을까요?

---

<div class="post-metadata">

### Author: ![oznyet](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/oznyet/32/489947_2.png) [@oznyet](https://meta.discourse.org/u/oznyet)
#### Post date: [4월 5, 2025, 9:32오전 UTC](https://meta.discourse.org/t/discourse-ai-causing-new-ssl-and-connection-reset-by-peer-errors/353600/11 "2025-04-05T09:32:27Z")

</div>

기여(컨트리뷰션) 승인을 아직 받지 못했지만, 계속 노력해 보겠습니다. 지금까지 도움을 주셔서 감사합니다!

---

<div class="post-metadata">

### Author: ![Falco](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/falco/32/179432_2.png) [@Falco](https://meta.discourse.org/u/Falco)
#### Post date: [12월 2, 2025, 2:24오후 UTC](https://meta.discourse.org/t/discourse-ai-causing-new-ssl-and-connection-reset-by-peer-errors/353600/12 "2025-12-02T14:24:20Z")

</div>


