AI 에이전트의 경우: 문서 인덱스는 https://www.mongodb.com/ko-kr/docs/llms.txt에서 사용할 수 있으며, 모든 페이지의 마크다운 버전은 어떤 URL 경로에 .md를 추가하여 사용할 수 있습니다.
See how MongoDB 9.0 delivers up to 2x higher throughput.
MongoDB Branding Shape
Register now >
Docs Menu

러너 SDK - 기술 아키텍처

Atlas Agent Engine을 위한 프레임워크에 구애받지 않는 테넌트 런타임 SDK입니다.

이는 내부 핵심 패키지 입니다. 에이전트가 직접 설치하지 않습니다. 종속된 프레임워크 SDK(agent-engine-sdk-langgraph 또는 agent-engine-sdk-adk)를 설치합니다.

Runner SDK는 플랫폼 아키텍처의 AER, 도구 파드 및 메모리 서버 통합 구성 요소를 제공합니다. 오케스트레이션 엔진은 별도의 Atlas Agent Engine 서비스입니다.

구성 요소
포트
신뢰 수준
네트워크 액세스
시크릿 액세스
목적

AER(에이전트 실행 런타임)

8001

중간

LLM API 전용

LLM 키 전용

실행 영역 - 에이전트 로직 실행

도구

8002

다름

필요에 따라

필요에 따라

데이터 영역 - 격리된 도구 실행

메모리 서버

8081

중간

MongoDB

DB 자격 증명

시맨틱/에피소딕/분류 메모리를 위한 메모리 서비스

Runner-shared auto-detects the listener bind at startup: :: (IPv6 dual-stack — uvicorn renders this as http://[::]:port in URL form) when the kernel has IPv6 enabled with IPV6_V6ONLY=0, otherwise 0.0.0.0. No configuration required — production deploys on IPv6-first networks (cell tenant namespaces) get :: automatically and local Docker dev (where bridge IPv6 is often disabled) falls back to 0.0.0.0. The probe-resolved host is logged at startup (listener bind resolved: host=...) so post-deploy verification doesn’t have to infer from uvicorn’s own startup line.

환경에서 APP_HOST를 설정하여 프로브를 재정의하는 프로브 — 커널이 IPv6를 사용 가능한 것으로 보고하지만 주변 네트워크가 IPv4만 라우팅하는 컨테이너에 필요합니다(예: host_ip: 127.0.0.1을 사용한 Docker 포트 포워딩). 이러한 이유로 통합 테스트 작성 템플릿은 APP_HOST=0.0.0.0를 설정하다 .

리스너는 활성 RUNNER_MODE(8001/8002/8081)에 대해 고정된 기본값 포트를 사용합니다. RUNNER_MODE는 플랫폼 런타임에 필요하며 주입됩니다. local dev는 사용자 .env 재정의를 무시하며, 작업 공간 시크릿은 이름을 완전히 보유합니다.

The image CMD is python -m agent_engine_runner_shared.launcher (TypeScript: node …/launcher.js). The launcher installs logging before it imports AGENT_ENTRYPOINT, so an import-time crash or an exception from the entrypoint function is an ERROR record (structured JSON when STRUCTURED_LOGGING=true) rather than a raw traceback that workspace logs would show as INFO. TenantRuntime still calls setup_logging / setupLogging later; that second install is idempotent. Failures that happen before the launcher process starts (interpreter/image errors) still rely on the API Gateway read-path heuristic documented in `docs/api-gateway/README.md <../../../../../docs/api-gateway/README.md#agent--operator-logs-s3-read-path>`__.

이러한 분리를 통해 다음과 같은 이점을 얻을 수 있습니다. - 감사 로깅 - OE는 모든 도구/LLM 호출을 실행하지 않고 확인 - 정책 시행 - OE는 실행 전에 호출을 차단 수 있음 - 최소 권한 - 각 구성 요소에 필요한 액세스 만 부여 - 재생 - OE는 결정론적 재개를 위해 캐시된 결과를 반환할 수 있음


전체 규범 계약: `docs/runner/README.md <../../../../../docs/runner/README.md#execution-Lifecycle--secret-availability>`__. 에이전트 작성자가 올바른 코드를 쓰기 (write) 데 필요한 규칙은 다음과 같습니다.

  • 모듈 최상위 코드(함수 본문 외부의 모든 항목)는 프로세스 스타트업 시 AER과 도구 파드 모두에서 한 번 실행됩니다. 이는 MCP OAuth 구성 및 MONGODB_URI 및 LLM API 키를 포함한 테넌트 제공 가능 스타트업 비밀에 의존할 수 있습니다. 스타트업 중에는 호출 세션과 위임된 요청 자격 증명 사용할 수 없습니다. MCP OAuth 캐시 쓰기(~/.agentic/mcp-oauth/<server>.json 또는 배포된 런타임의 AGENTIC_MCP_OAUTH_DIR)는 자문 <server>.json.lock 파일 에 직렬화되므로 동일한 서버 에 대한 동시 토큰 새로 고침이 서로 방해할 수 없습니다.

  • 도구 애플리케이션 구성은 스타트업 중에 @app.entrypoint 함수를 시도하여 모든 app.llm(llm_id=...) 등록을 검색합니다. 모델 요청은 준비된 레지스트리를 재사용합니다. 구성은 정적 스타트업 구성을 사용하며 비즈니스 차례, 모델 호출 또는 도구 본문을 실행해서는 안 됩니다. 구성에 실패하면 경고를 표시하고 이전 등록을 복원하여 이후 모델 요청 다시 시도할 수 있도록 합니다. 성공적인 구성은 명명된 LLM이 없어도 캐시됩니다. AER 그래프 캐싱 및 워밍업은 계속 프레임워크가 소유합니다.

  • ``앱.llm(llm, llm_id=...)``는 진입점이 호출 스택 에 있는 동안(본문에서 직접 또는 호출하는 헬퍼 함수에서) 호출되어야 합니다. 그 외부의 모든 곳( 모듈 최상위 수준, 도구 본문, 진입점이 아닌 다른 곳에서 호출된 헬퍼)에서 호출하면 즉시 RuntimeError가 발생하여 문제가 되는 호출 사이트 이름을 지정합니다.

  • 로컬 도구 본문(is_local=True)은 AER의 자체 프로세스 에서만 실행 . AER 및 도구 워크로드는 모두 스타트업 시 테넌트 제공 시크릿을 수신합니다.

  • 원격 도구 본문(is_local=False 또는 위임된 자격 증명 필요한 도구)은 OE가 호출을 라우팅할 때 온디맨드 방식으로 도구 파드에서만 실행 , 구성 중에는 절대 실행되지 않습니다. required_secrets 선언은 시크릿 요구 사항을 문서 . 스타트업 시크릿 환경의 범위를 좁히지 않습니다.

  • SDK가 로컬 기본값 제공하더라도 자격 권한 부여이 있는 도구는 원격으로 유지됩니다.


┌────────┐ ┌─────┐ ┌─────┐
│ Client │ │ OE │ │ AER │
└───┬────┘ └──┬──┘ └──┬──┘
│ │ │
│ POST /invoke │ │
│ ──────────────────────────►│ │
│ │ │
│ │ Create Execution (PENDING)
│ │ │
│ │ POST /execute │
│ │─────────────────────────►│
│ │ │
│ │ │ Build LangGraph
│ │ │ Start ainvoke()
│ │ │
│ ┌───────────────────────┼──────────────────────────┼───────────────┐
│ │ LOOP: For each tool/LLM call │ │
│ │ │ │ │
│ │ │ POST /tool/execute │ │
│ │ │◄─────────────────────────│ │
│ │ │ {tool, args, step} │ │
│ │ │ │ │
│ │ │ Log + Policy Check │ │
│ │ │ │ │
│ │ │ {proceed, route_to} │ │
│ │ │─────────────────────────►│ │
│ │ │ │ │
│ │ │ │ Execute tool │
│ │ │ │ │
│ │ │ POST /tool/result │ │
│ │ │◄─────────────────────────│ │
│ │ │ {result, status} │ │
│ └───────────────────────┼──────────────────────────┼───────────────┘
│ │ │
│ │ │ Graph completes
│ │ │
│ │ POST /executor/callback │
│ │◄─────────────────────────│
│ │ {COMPLETED, result} │
│ │ │
│ GET /execution/{id} │ │
│ ──────────────────────────►│ │
│ │ │
│ {status: completed, result}│ │
│ ◄──────────────────────────│ │
│ │ │
┌────────┐ ┌─────┐ ┌─────┐
│ Client │ │ OE │ │ AER │
└───┬────┘ └──┬──┘ └──┬──┘
│ │ │
│ POST /invoke │ │
│ ──────────────────────────►│ │
│ │ │
│ │ POST /execute │
│ │─────────────────────────►│
│ │ │
│ │ ... tool calls ... │
│ │ │
│ │ │ app.suspend(reason)
│ │ │ → tool pod reports
│ │ │ status: "suspend"
│ │ │ (out-of-band, not
│ │ │ result content)
│ │ │
│ │ │ interrupt() on the
│ │ │ OE-confirmed status
│ │ │ Save checkpoint
│ │ │
│ │ POST /executor/callback │
│ │◄─────────────────────────│
│ │ {SUSPENDED, metadata} │
│ │ │
│ GET /execution/{id} │ │
│ ──────────────────────────►│ │
│ {status: suspended} │ │
│ ◄──────────────────────────│ │
│ │ │
╠════════════════════════════╬══════════════════════════╣
║ ⏸️ WAITING FOR HUMAN - Reviews and Approves ║
╠════════════════════════════╬══════════════════════════╣
│ │ │
│ POST /resume/{id} │ │
│ {decision: "approved"} │ │
│ ──────────────────────────►│ │
│ │ │
│ │ Store human decision │
│ │ │
│ │ POST /execute │
│ │ {resume: true} │
│ │─────────────────────────►│
│ │ │
│ │ │ Resume from checkpoint
│ │ │
│ ┌───────────────────────┼──────────────────────────┼───────────────┐
│ │ Replayed steps return CACHED results │ │
│ │ │ │ │
│ │ │ POST /tool/execute │ │
│ │ │◄─────────────────────────│ │
│ │ │ │ │
│ │ │ {cached_result} │ │
│ │ │─────────────────────────►│ │
│ └───────────────────────┼──────────────────────────┼───────────────┘
│ │ │
│ │ │ Continue execution
│ │ │ (new steps)
│ │ │
│ │ POST /executor/callback │
│ │◄─────────────────────────│
│ │ {COMPLETED, result} │
│ │ │
│ GET /execution/{id} │ │
│ ──────────────────────────►│ │
│ {status: completed} │ │
│ ◄──────────────────────────│ │
│ │ │

참고

API 게이트웨이를 통한 재개: 위 다이어그램은 간결성을 위해 OE의 내부 /resume/{id} 경로를 사용합니다. 개발자는 플랫 JSON 본문을 사용하여 POST /api/v1/projects/{project_id}/executions/{execution_id}/resume에서 API 게이트웨이를 호출합니다.

{"decision": "approved", "reviewer_notes": "optional context"}

래핑된 {"human_review": {"decision": "..."}} 형태는 OE의 내부 엔드포인트 계약입니다. 게이트웨이가 HTTP 400로 이를 거부합니다.

OE가 실행을 지속적으로 취소하면 이를 소유한 도구/AER 런타임에 /drain를 게시합니다. 수신자 계약(client-libraries/test-fixtures/drain/contract.json의 공유 고정 장치에 의해 고정됨):

  • POST /drain {request_id, execution_id, reason, deadline_at_ms, workspace_id} — 작업 공간 범위 런타임(APP_ID 설정하다 즉, 모든 managed 런타임)에서 workspace_id은 필수이며 정확히 일치해야 합니다: 베어러 토큰은 호출자를 인증하지만 명명된 실행이 이 런타임에 속한다는 것을 증명하지는 않습니다.

  • 202 {"outcome": "accepted"} 배출 동안 ; 200를 최종 결과(completed / timed_out / delivery_failed)와 함께 반환합니다. accepted는 HTTP 수준에서만 허용되며, completed는 유일한 정지 신호입니다.

  • request_id에서 멱등원, 실행당 하나의 배출: 재시도 시 부작용을 다시 실행하는 대신 기록된 결과를 다시 읽습니다.

  • deadline_at_ms 절대적이며 절대 확장되지 않습니다. 런타임이 RUNNER_DRAIN_MAX_DEADLINE_MS(기본값 60) 이후의 기한을 거부합니다. 최종 기록은 RUNNER_DRAIN_RECORD_TTL_S(기본값 900) 동안 유지되므로 호출자의 재시 창 동안 멱등 유지 — 이를 호출자의 재시 창 이상으로 유지(OE는 15분 동안 배출 재시도): TTL 짧을 기록 제거됩니다. 발신자가 여전히 재시도하고 있고, 늦은 재전송은 기록된 결과 대신 execution_not_found를 받습니다.

  • 이 런타임이 제공하지 않은 실행은 delivery_failed에 reason_code=execution_not_found로 응답합니다. 한 번의 실행은 AER 및 도구 런타임에 독립적으로 적용될 수 있으므로 정확한 OE 타겟팅이 잘못된 completed 안전을 보장하지 않습니다.

언어별 제한은 구현 세부 정보가 아닌 계약의 일부입니다. Python 추적된 asyncio 작업을 취소하므로 협업 작업은 completed로 해결됩니다. 프로미스는 취소가 없으므로 TypeScript 런타임(agent-engine-runner-shared, 이 계약을 미러링하고 계약과 함께 변경되어야 함)은 등록된 AbortController(AER 턴 및 LLM 스트림)만 중단하고 일반 도구 함수는 신호를 수신하지 않습니다. 추적 및 허용이 차단되며, 기한을 초과하는 것은 정직한 timed_out입니다. 상태는 의도적으로 프로세스 로컬입니다: 재시작된 런타임이 활성 작업을 손실하고 delivery_failed에 응답합니다. 재시작 시 조정은 이 레지스트리가 아닌 호출자의 지속형 기록 에 속합니다.

POST /interrupt/call is the surgical sibling of the drain: the OE’s per-call interrupt names one call by {execution_id, step_number} and the runtime aborts exactly that call’s tracked handle — Python cancels the asyncio task, the TS runtime aborts the call’s AbortController — while the execution stays open and later calls proceed (no admission latch, ever). Always 200 with an outcome: interrupted (signalled, or recorded to fire at attach), not_found (no such in-flight call), already_settled (the call ended first), not_cancellable (tracked work with no signal channel — a sync tool body on a thread, a plain TS tool function — reported honestly, never claimed abandoned). Workspace scoping matches the drain route’s, and the shared vectors live in client-libraries/test-fixtures/interrupt-call/contract.json.


차단된 도구 호출과 invoke_llm는 이제 동일한 OE 소유 실행 흐름을 사용합니다. AER에서 실행 에이전트 도구나 LLM을 호출해야 하는 경우 래퍼는 가로채는 요청 OE로 보내고 OE가 최종 결과를 반환할 때까지 기다립니다. OE는 Tool Pod /execute를 통해 도구 호출을 라우팅하고 Tool Pod /invoke_llm를 통해 LLM 호출을 라우팅한 다음 최종 성공, 일시 중단 또는 오류 결과를 AER에 다시 반환합니다.

시퀀스 다이어그램:

┌─────┐ ┌─────┐ ┌──────────┐
│ AER │ │ OE │ │ Tool Pod │
└──┬──┘ └──┬──┘ └────┬─────┘
│ │ │
│ 1. POST /tool/execute │ │
│ ────────────────────────►│ │
│ {name or invoke_llm, │ │
│ args/messages, step} │ │
│ │ │
│ │ Log + Policy Check │
│ │ │
│ │ 2a. Replay cache hit │
│ 2a. Final cached result │ │
│ ◄────────────────────────│ │
│ {status, result, │ │
│ from_cache} │ │
│ │ │
├──────────────────────────┼────────────────────────────┤
│ if OE must execute the tool │
│ │ │
│ │ 2b. POST /execute or │
│ │ /invoke_llm │
│ │ ───────────────────────────────────────►
│ │ via Tool Pod │
│ │ ◄───────────────────────────────────────
│ │ {status, result} │
│ │ │
├──────────────────────────┼────────────────────────────┤
│ │ │
│ 3. Final OE-owned result │ │
│ ◄────────────────────────│ │
│ {status, result, error, │ │
│ duration_ms, pod_name} │ │
│ │ │

요점:

  1. 가로채는 모든 도구 또는 LLM 호출은 정책, 로깅 및 재생 소유권을 위해 먼저 OE를 교차합니다.

  2. OE는 라우팅을 소유합니다 — 원격 도구는 Tool Pod /execute을 사용합니다. 승인된 로컬 도구가 원래 AER 호출 스택 으로 돌아가서 프레임워크 네이티브 컨텍스트가 라이브 상태로 유지됩니다. 가로채는 LLM 호출은 Tool Pod /invoke_llm을(를) 사용합니다.

  3. Replay는 캐시된 결과를 사용합니다 — SUSPEND 후 재개 시 OE는 중복된 부작용을 방지하기 위해 저장된 최종 결과를 반환합니다.

  4. 일시 중단은 여전히 래퍼를 통해 풀립니다 — OE는 직렬화된 일시 중단 페이로드를 반환한 다음 SecureToolWrapper가 이를 프레임워크 중단으로 다시 변환합니다.

  5. 이제 ``invoke_llm``이 도구 계약과 일치합니다. — OE는 승인 후 AER을 실행하도록 요청하는 대신 최종 status/result/error 페이로드를 반환합니다.

  6. LLM 스트림 청크는 최종 메시지 메타데이터 보존합니다 — id, name, additional_kwargs 및 response_metadata는 입력된 스트림 이벤트 통과하여 재생에 사용되는 것과 동일한 최종 응답 형태로 다시 수집됩니다.

런타임 구성 로딩이 이제 테넌트 소유 agent.yaml 경로의 제한된 허용 목록(현재 mcp.servers.*.url)에 대해 ${VAR} 보간을 지원합니다.

작동 방식:

  • load_runtime_agent_config(env_vars=...) 허용 목록에 있는 경로에서만 ${VAR} 참조를 대체합니다.

  • 런타임은 원시 os.environ가 아닌 tenant_env_vars()을 전달하므로 플랫폼 소유 환경 변수와 시크릿은 대체에서 제외됩니다.

  • 허용 목록에 있는 경로가 설정되지 않은 변수를 참조하거나 잘못된 ${...} 마커를 포함하는 경우, 로더는 명확한 유효성 검사 오류를 발생시킵니다.

  • mcp.servers.*.auth.token_env 플랫폼 소유 환경 변수를 점 않아야 합니다.

예시:

mcp:
servers:
tableau:
url: https://${TABLEAU_HOST}/mcp

런타임에 ${TABLEAU_HOST}가 테넌트 소유 환경 하위 집합에서 확인됩니다. ${OPENAI_API_KEY}과 같은 참조는 해당 변수가 플랫폼 소유이고 보간 전에 필터링되기 때문에 거부됩니다.

도구 호출을 가로채는 중앙 보안 구성 요소:

# Every tool call goes through this flow:
def execute_tool(tool_name, arguments):
# 1. Send the intercepted tool call to OE
response = request_oe_approval(oe_url, execution_id, tool_name, arguments)
# 2. Check for policy denial
if not response.proceed:
raise PolicyDeniedException(response.reason)
# 3. OE either returns a final outcome or routes the call back in process
if response.route_to == "callback":
result = local_executor()
report_oe_result(result)
return result
if response.status == "error":
raise ToolExecutionError(response.error)
if response.status == "suspend":
interrupt(response.result)
return response.result

키 불변성: OE가 이를 알지 못하면 도구 또는 LLM 호출이 실행되지 않습니다.


OE는 정책 규칙에 따라 도구/LLM 호출을 차단 수 있습니다.

정책 시행은 고 (Go) OE에서 처리합니다. docs/orchestration-engine/README.md를 참조하세요.

SUSPEND 후 에이전트 재개되면 LangGraph 실행이 처음부터 재생됩니다. 캐싱이 없으면 도구와 LLM 호출이 다시 실행되어 중복된 부작용(예: 알림 두 번 전송)이 발생합니다.

작동 방식:

  1. OE는 모든 단계를 추적 - 모든 도구/LLM 호출은 단계 번호, 이름 및 결과와 함께 기록됩니다.

  2. 재개 시 에이전트 재생 - LangGraph가 처음부터 다시 실행하여 동일한 호출을 순서대로 수행

  3. OE는 캐시된 결과를 반환 - OE는 다시 실행하는 대신 저장된 결과를 반환합니다.

Original Execution:
Step 1: lookup_policy("POL-123") → executed, result stored
Step 2: query_mongogpt(...) → executed, result stored
Step 3: human_review(...) → SUSPEND (waiting for human)
Resume Execution:
Step 1: lookup_policy("POL-123") → CACHED (returns stored result)
Step 2: query_mongogpt(...) → CACHED (returns stored result)
Step 3: human_review(...) → CACHED (returns human's decision)
Step 4: send_notification(...) → executed (new step)

재생 캐싱은 고 (Go) OE에서 처리합니다. AER/SecureToolWrapper는 캐시된 응답을 투명하게 처리합니다.

AER/SecureToolWrapper 처리:

# In secure_wrapper.py - OE already returns the final replay outcome
response = await request_oe_approval(...)
if response.from_cache:
log_cached_result(tool_name, step)
return response.result

이렇게 하면 결정론적 재개가 보장되며, 에이전트 일시 중단하기 전에 본 것과 정확히 동일한 결과를 볼 수 있으므로 중복 부작용을 방지할 수 있습니다.

인메모리 및 MongoDB 체크포인터를 모두 지원합니다.

# In runtime.py
def get_checkpointer(self):
if mongodb_uri:
return MongoDBSaver(client, db_name)
return MemorySaver() # Development only

src/agent_engine_runner_shared/
├── runtime.py # TenantRuntime - main SDK entry point
├── secure_wrapper.py # SecureToolWrapper, SecureWrappedLLM
├── models.py # Pydantic models for all API contracts
├── context.py # Per-execution context (contextvars)
├── metrics.py # Metrics collection and @with_metrics decorator
├── utils.py # Logging utilities, env helpers
├── logging.py # Durable execution logging (JSONL + MongoDB)
├── memory.py # MemoryEngine integration, MemoryWriter
├── voyage.py # VoyageService for embeddings
├── events.py # SSE event streaming, observability
├── types.py # Protocol definitions (MemoryEngineProtocol)
├── tracing/ # OpenTelemetry tracing
│ ├── setup.py # setup_tracing(), get_current_trace_context()
│ └── exporters.py # JSONLSpanExporter, MongoDBSpanExporter
└── server/
├── base.py # BaseServer abstract class
├── aer.py # AER implementation
├── tool.py # Tool Pod implementation
└── memory.py # Memory Server implementation

지연 시간 추가되지만, OE를 통한 라우팅은 다음을 제공합니다: 1. 전체 감사 추적 - 모든 통화가 2로 기록됩니다. 정책 시행 점 - 3 호출을 차단 수 있는 단일장소입니다. 재생 역량 - OE는 재개 4에 대해 캐시된 결과를 반환할 수 있습니다. 프레임워크에 구애받지않음 - OE가 LangGraph를 알 수 없음

  • AER에는 LLM API 액세스 필요하지만 데이터베이스 자격 증명 없어야 합니다.

  • 도구에 데이터베이스 액세스 필요할 수 있지만 LLM 키는 없어야 합니다.

  • 서로 다른 도구를 서로 다른 권한으로 서로 다른 도구에서 실행 수 있습니다.


이제 Runner SDK는 모놀리식 agent-runtime과 기능 패리티를 제공합니다.

기능
에이전트 런타임
러너 SDK

@ 앱.tool 데코레이터

✅

✅

명시적 네트워크/시간 초과 메타데이터

✅

✅

필드 편집

✅

✅

MongoDB 체크포인트

✅

✅

실행 로깅(JSONL + MongoDB)

✅

✅

OpenTelemetry 추적

✅

✅

메모리 통합

✅

✅

Voyage AI 임베딩

✅

✅

멀티 테넌트(org_id/user_id)

✅

✅

SSE 이벤트 스트리밍

✅

✅

gRPC 서버

✅

✅

스트리밍 지원

✅

✅

인간-인-더-루프

❌

✅

3 컴포넌트 아키텍처

❌

✅

캐싱 재생

❌

✅

필요에 따라 기능을 설치합니다. 프로젝트 가 uv로 managed 경우 uv add를 사용하고, 그렇지 않은 경우 pip install을 사용합니다:

# uv projects
uv add agent-engine-runner-shared
uv add "agent-engine-runner-shared[mongodb,tracing]"
uv add "agent-engine-runner-shared[tracing]"
uv add "agent-engine-runner-shared[mongodb]"
# pip
pip install agent-engine-runner-shared
pip install "agent-engine-runner-shared[mongodb,tracing]"
pip install "agent-engine-runner-shared[tracing]"
pip install "agent-engine-runner-shared[mongodb]"
이 페이지 평가하기