AIML / Architecture Deep Dive

ontology-for-mfg: 하이테크 제조 온톨로지 PoC 아키텍처 분석

22개 온톨로지 클래스로 제조 도메인(BOM, 공급망, 표준/규제, 품질, 운영)을 지식 그래프로 모델링하고, 그 위에 Bedrock 에이전트와 12개 시나리오를 올린 PoC의 구조를 코드와 스키마 기준으로 분석합니다.

작성 기준일은 2026-08-09입니다.

분석 대상은 ontology-for-mfg v0.5.6(2026-05-15 릴리스)입니다.

온톨로지 정의 파일은 ontology/schema.ttl, 에이전트 진입점은 api/services/agent.py입니다.

주 출처는 GitHub 저장소 whchoi98/ontology-for-mfg의 코드, 스키마, docs/ 문서입니다.

요약

01제조에서 온톨로지가 필요한 이유

이 절은 제조 현장의 데이터 질문이 왜 어려운지 설명합니다. 그리고 지식을 그래프 형태로 정리하는 방식이 그 어려움을 어떻게 푸는지 보여줍니다.

하이테크 제조의 데이터 질문은 대부분 관계를 여러 단계 따라가야 답이 나옵니다. 예를 들어 "이 제품에 들어가는 부품 중 REACH 규제 물질을 포함한 것은 무엇인가"라는 질문을 봅니다. 답을 얻으려면 제품 → 모듈 → 부품 → 물질 → 규제로 이어지는 4단계 이상의 조인이 필요합니다.

관계형 테이블로도 답할 수는 있습니다. 하지만 질문이 바뀔 때마다 조인 경로를 다시 설계해야 합니다. LLM이 스스로 이런 질의를 만들기도 어렵습니다.

이 프로젝트는 온톨로지(도메인의 개념과 관계를 기계가 읽을 수 있게 정의한 스키마)로 제조 고유의 관계 사슬 세 갈래를 명시합니다.

  • BOM 계층. BOM은 제품이 어떤 부품으로 구성되는지 적은 자재 명세서입니다. Product -hasModule-> Module -consistsOf-> Component -madeOf-> RawMaterial로 제품 구조가 4계층 그래프로 내려갑니다.
  • 규제 추적. Component -containsSubstance-> Substance -regulatedBy-> Regulation 사슬이 있습니다. 부품에서 출발해 REACH-SVHC, RoHS 해당 여부를 그래프 탐색만으로 판정할 수 있습니다.
  • 품질 추적. QualityIncident -about-> Component, EightDReport -addresses-> QualityIncident, EightDReport -identifies-> RootCause -linkedTo-> Supplier 관계가 있습니다. 품질 사고에서 근본 원인, 책임 협력사까지 한 그래프 안에서 연결됩니다.

표준과 규제를 데이터가 아니라 클래스로 승격한 점이 자매 프로젝트인 리테일 편과 갈라지는 지점입니다. Standard, Certification, Regulation, Substance 4개 클래스가 스키마에 존재합니다. JEDEC, IPC, AEC-Q, IATF 16949, ISO 9001, REACH-SVHC, RoHS, CBAM, IRA, USMCA 10개 체계의 실제 표준 데이터 서브셋이 data/public/에 적재됩니다.

그 결과 부품의 인증 여부와 무역 규제 노출이 그래프 질의 대상이 됩니다.

참고 - 이 문서에서 말하는 온톨로지

여기서 온톨로지는 OWL 추론기까지 쓰는 무거운 시맨틱 웹 스택이 아닙니다. schema.ttl에 OWL 문법으로 정의한 클래스/관계 정의를 Neptune 프로퍼티 그래프의 라벨과 엣지 타입으로 옮겨 쓰는 실용적 스키마를 뜻합니다. 질의는 SPARQL이 아니라 openCypher(그래프 데이터베이스용 질의 언어)로 합니다.

02전체 구조: 22클래스 스키마와 AWS 아키텍처

이 절은 시스템의 뼈대를 살펴봅니다. 지식을 담는 스키마, 그것을 돌리는 AWS 서비스 구성, 어떤 AI 모델을 어디에 쓰는지 순서로 정리합니다.

2.1 22클래스 스키마

스키마의 크기는 어느 정도일까요? ontology/schema.ttl에는 22개 owl:Class와 24개 owl:ObjectProperty가 정의되어 있습니다. 클래스는 다섯 그룹으로 나뉩니다.

아래 표에서 볼 것은 22개 클래스가 어떤 다섯 그룹으로 묶이고, 각 그룹이 어떤 관계로 이어지는지입니다.

표 1. 22개 온톨로지 클래스 (ontology/schema.ttl 기준)
그룹클래스대표 관계
BOM 계층 (4) Product, Module, Component, RawMaterial hasModule, consistsOf, madeOf
공급망 (7) Manufacturer, Supplier, SubSupplier, CustomerAccount, Plant, Region, TradeLane suppliedBy, subSupplies, operates, shipsVia, connects
표준/규제 (4) Standard, Certification, Regulation, Substance conformsTo, certifiedBy, containsSubstance, regulatedBy, subjectTo
품질 (3) QualityIncident, EightDReport, RootCause about, addresses, identifies, linkedTo
운영/ESG (4) Telemetry, MaintenanceEvent, ESGIndicator, CarbonScope from, on, measuredAt, emits

데이터는 어떻게 채워질까요? 합성 데이터 생성기(data/synthetic/)가 이 스키마대로 약 10,644개 노드를 만들어 ndjson으로 내보냅니다. 이어서 VPC 내부 로더가 Neptune(openCypher 벌크)과 OpenSearch(_bulk)에 적재합니다.

같은 스키마는 Pydantic 모델(data/schemas.py)로도 존재합니다. 덕분에 생성, 적재, API 응답이 하나의 타입 정의를 공유합니다.

2.2 AWS 아키텍처

실행 환경은 전부 AWS 관리형 서비스입니다. 역할별 구성은 다음과 같습니다.

  • 지식 그래프는 Amazon Neptune입니다(openCypher, VPC 내부 전용).
  • 의미 검색은 Amazon OpenSearch Serverless입니다(VECTORSEARCH 컬렉션, 한국어 Nori 분석기 + k-NN HNSW).
  • LLM은 Amazon Bedrock Converse API, 컴퓨트는 ECS Fargate ARM64 서비스 2개(api, web)입니다.
  • 엣지는 CloudFront와 ACM 커스텀 도메인, 인증은 Amazon Cognito입니다.

인프라 전체는 AWS CDK v2(TypeScript) 6개 스택(network, data, ai, compute, edge, observability)으로 정의됩니다.

flowchart LR U["브라우저"] --> CF["CloudFront + Cognito 인증"] CF --> WEB["ECS Web - Next.js 14"] CF --> ALB["ALB /api/*"] ALB --> API["ECS API - FastAPI AgentRunner"] API --> NEP["Neptune openCypher 22클래스"] API --> AOSS["OpenSearch Serverless BM25 + k-NN"] API --> BR["Bedrock Sonnet 4.6 / Haiku 4.5 + KB + Guardrails"]
그림 1. 요청 흐름. CloudFront가 정적 웹과 /api/* 경로를 분기하고, FastAPI의 에이전트가 Neptune, OpenSearch, Bedrock 세 엔진을 조합해 SSE로 응답을 스트리밍합니다.

2.3 Bedrock 모델 라우팅

모델은 용도별로 나눠 씁니다. 긴 한국어 추론과 다회차 tool-use(모델이 대화 중에 외부 도구를 호출하는 기능)가 필요한 대화와 인사이트는 Sonnet이 맡습니다. 스키마가 고정된 구조화 출력은 Haiku가 맡습니다.

아래 표에서 볼 것은 용도별 모델 ID이며, 값은 api/config.py의 기본값 기준입니다.

표 2. 모델 라우팅 (api/config.py 기본값 기준)
용도모델 ID
대화형 에이전트, 인사이트 (tool-use 오케스트레이터)global.anthropic.claude-sonnet-4-6
8D 초안 작성, 후속 질문 생성, 코드 그래프 커뮤니티 라벨링global.anthropic.claude-haiku-4-5-20251001-v1:0
임베딩 (1,024차원)amazon.titan-embed-text-v2:0
리랭커환경변수 빈 값 - ap-northeast-2 미제공으로 비활성화

03핵심 동작 원리 네 가지

이 절은 시스템의 심장부 네 곳을 들여다봅니다. 에이전트가 도구를 고르는 루프, 두 검색을 합치는 방법, 보는 사람에 맞춘 표현, 대표 시나리오 하나입니다.

3.1 에이전트 tool-use 루프: 도구 5종

대화형 에이전트(시나리오 B)의 중심은 api/services/agent.py의 AgentRunner입니다. Bedrock converse_stream을 호출하고, 모델이 도구를 요청하면 실행 결과를 대화에 되돌려줍니다. 이 루프를 최대 8라운드(max_rounds=8) 돕니다.

응답은 얼마나 빨라졌을까요? v0.5.6부터 contentBlockDelta 텍스트 청크가 도착하는 즉시 SSE(서버가 응답을 잘게 쪼개 실시간으로 밀어주는 웹 표준) delta 이벤트로 전달됩니다. 저장소 CHANGELOG 기준으로 첫 토큰까지의 시간이 2-5초에서 300-600ms 수준으로 줄었습니다.

아래 표에서 볼 것은 에이전트가 고를 수 있는 도구 5종과 각 도구가 실제로 부르는 백엔드입니다.

표 3. 에이전트 도구 5종 (api/routers/chat.py의 _TOOLS)
도구역할백엔드
search_semantic퍼지 개념 검색 (예: 차량용 -40°C BGA)OpenSearch 하이브리드 검색
neptune_queryBOM, Supplier, Plant, TradeLane의 정밀 그래프 질의Neptune openCypher
kb_retrieve데이터시트, 8D, 규제 문서 패시지 검색Bedrock Knowledge Base
compliance_check부품 ID 기준 REACH, RoHS, AEC-Q 검증결정적 규칙 엔진
memory_save세션 단위 사실 저장DynamoDB 테이블 (ontology-mfg-dev-memory) - 코드 주석의 Aurora 전환 계획은 아직 미반영

안정성 장치는 두 겹입니다. 첫째, 동기식 Bedrock 호출의 타임아웃입니다. 8D(품질 사고의 원인과 대책을 8개 항목으로 정리하는 제조업 표준 보고서) 파이프라인과 ops 평가 실행 등은 ThreadPoolExecutor.submit().result(timeout=25)로 25초 타임아웃에 묶입니다.

초과하면 결정적 템플릿으로 폴백합니다(ADR-003). 채팅은 converse_stream 스트리밍으로 별도 처리됩니다.

둘째, 합성 폴백입니다. 데이터 경로가 죽어도 데모가 빈 화면이 되지 않도록, 결정형 시나리오 대부분(10개 라우터)에 합성 폴백과 _synthetic 플래그가 있습니다. 검색(A)과 채팅(B)에는 없습니다.

주의 - LLM에게 그래프 질의를 맡길 때의 방어선

neptune_query는 모델이 직접 Cypher를 작성하는 도구입니다. 그래서 프롬프트 인젝션(악의적 입력으로 모델의 행동을 바꾸는 공격)으로 쓰기 질의가 흘러들 수 있습니다.

이 프로젝트는 chat.py:_tool_neptune에 읽기 전용 게이트웨이를 둡니다. CREATE, DELETE, SET, MERGE, DROP 등을 정규식 거부 목록으로 차단하고(ADR-002), 사용자 제공 라벨은 22클래스 허용 목록으로만 통과시킵니다. 같은 구조를 만들 때 이 계층을 생략하면 에이전트가 그래프를 변조할 수 있는 경로가 그대로 열립니다.

3.2 하이브리드 검색: BM25 + k-NN + RRF

의미 검색(시나리오 A)은 두 검색을 병렬로 돌려 합칩니다. 하나는 한국어 Nori 분석기 기반 BM25(단어 일치 점수로 문서를 찾는 고전적 키워드 검색)입니다. 다른 하나는 Titan 1,024차원 임베딩(문장의 의미를 숫자 벡터로 바꾼 표현)을 쓰는 k-NN(벡터 거리가 가장 가까운 문서를 찾는 검색)입니다.

두 결과는 어떻게 합쳐질까요? 각각 50건씩 뽑고, 각 목록에서의 등수만으로 점수를 매기는 Reciprocal Rank Fusion, 줄여서 RRF(k=60)로 순위를 융합해 상위 10건을 반환합니다. OpenSearch Serverless에는 search pipeline 모듈이 없어서 RRF 융합을 Python에서 직접 수행합니다.

api/services/search.py - RRF 융합 (발췌)
@staticmethod
def rrf(hit_lists: list[list[dict]], k: int = 60) -> list[tuple[str, float]]:
    scores: dict[str, float] = {}
    for hits in hit_lists:
        for rank, h in enumerate(hits, start=1):
            doc_id = h["_id"]
            scores[doc_id] = scores.get(doc_id, 0.0) + 1.0 / (k + rank)
    return sorted(scores.items(), key=lambda kv: kv[1], reverse=True)

설계 의도는 상호 보완입니다. BM25는 부품 번호나 표준 이름 같은 정확한 토큰에 강합니다. k-NN은 "차량용 고온 환경 커패시터"처럼 표현이 다른 질의에 강합니다.

리랭커(검색 결과를 더 정밀한 모델로 다시 정렬하는 단계)는 Bedrock 기반으로 코드에 준비되어 있습니다. 다만 ap-northeast-2 미제공으로 현재 배포에서는 비활성입니다.

3.3 페르소나별 프레이밍

같은 화면, 같은 질문이라도 보는 사람의 KPI가 다릅니다. 이 프로젝트는 Buyer, Engineer, Quality, SCM, Plant 5개 페르소나(사용자 역할 유형)를 라우팅이 아닌 런타임 컨텍스트로 다룹니다.

웹에서는 단일 useActivePersona() 컨텍스트가 12개 시나리오 화면의 프레이밍을 바꿉니다. API에서는 시스템 프롬프트가 persona 값으로 포맷됩니다. 페르소나별 라우트 디렉터리를 만들었다가 v0.5.2에서 제거한 이력이 CLAUDE.md에 남아 있습니다.

매 턴이 끝나면 api/services/followups.py가 Haiku(300 토큰 한도)로 한국어 후속 질문 3개를 생성합니다. 결과는 SSE suggested_followups 이벤트로 내보내고, 이때 페르소나별 어조 맵이 들어갑니다.

예를 들어 Buyer는 단가, 리드타임, MOQ 방향으로 질문이 기울어집니다. Engineer는 스펙과 AEC-Q, JEDEC 인증, Quality는 8D와 REACH-SVHC, SCM은 TradeLane과 IRA, CBAM, Plant는 OEE와 텔레메트리 방향입니다. 생성 실패 시에는 빈 배열로 조용히 폴백합니다.

3.4 대표 시나리오 패턴: 8D / RCA

8D 보고서 시나리오(J)는 이 아키텍처의 조합 방식을 가장 잘 보여줍니다. 그래프에는 QualityIncident에서 EightDReport, RootCause를 거쳐 Supplier까지 이어지는 품질 사슬이 있습니다. 보고서 초안은 api/services/eight_d_writer.py가 작성합니다.

출력 형식은 어떻게 보장될까요? Haiku가 emit_eight_d 도구를 정확히 한 번 호출하도록 강제되고, 도구 스키마가 8개 필수 문자열 필드(D1-D8)를 요구하므로 형식이 프롬프트가 아니라 스키마로 보장됩니다. maxTokens=1500으로 25초 예산 안에 들어옵니다.

원칙: 정형 출력은 작은 모델과 tool-use 스키마로 풉니다. 자유 추론은 큰 모델과 도구 루프로 풉니다. 이 분리가 프로젝트 전체를 관통합니다(ADR-001).

0412개 시나리오 한눈에 보기

이 절은 데모가 제공하는 12개 화면을 한 표로 정리합니다. 무엇이 LLM을 쓰고 무엇이 쓰지 않는지가 핵심입니다.

시나리오 A부터 L까지가 제조 라이프사이클을 덮습니다. 각 시나리오는 api/routers/의 라우터 하나와 웹 페이지 하나로 대응됩니다. LLM이 개입하는 것은 B, J 계열이고 나머지 다수는 그래프 질의와 결정적 도메인 엔진의 조합입니다.

아래 표에서 볼 것은 각 시나리오를 구현하는 라우터와 핵심 엔진이며, 핵심 엔진 열은 각 라우터가 실제로 import하는 서비스 기준입니다.

표 4. 12개 시나리오 A-L (api/routers/ 기준)
코드시나리오라우터핵심 엔진
A의미 검색search.py하이브리드 검색(BM25 + k-NN + RRF) + Neptune
B대화형 에이전트chat.pyAgentRunner(Sonnet 4.6) + 도구 5종, SSE
C인사이트insights.pyNeptune 집계 + 결정적 템플릿 (LLM 미사용, 일반 POST)
D스펙 매치spec_match.py하이브리드 검색 + 리랭커 인터페이스
E규제 검증compliance.pycompliance_engine + Neptune
F대체 부품substitute.pyNeptune 그래프 질의
G단가/재고 비교price.pyNeptune 그래프 질의
H글로벌 SCM lane 재라우팅scm_lane.pylane_router 시뮬레이션 + carbon_calc
I협력사 RFMsupplier_rfm.pyrfm_scorer + Neptune
J8D / RCAeight_d.pyeight_d_writer(Haiku 4.5, 8필드 tool-use), SSE
KESG / CBAMesg_cbam.pycarbon_calc + Neptune
LPdM / IoTpdm.pyTelemetry, MaintenanceEvent 그래프 질의

패턴은 셋으로 압축됩니다. 검색형(A, D)은 하이브리드 검색이 후보를 만들고 그래프가 맥락을 붙입니다. 결정형(C, E, F, G, H, I, K, L)은 openCypher 질의와 도메인 엔진(관세 lane 시뮬레이션, RFM 점수, 탄소 계산)이 LLM 없이 값을 계산합니다.

생성형(B, J)만 Bedrock이 개입하고, 전부 SSE 스트리밍과 타임아웃 폴백을 갖습니다. 12개를 나열식으로 읽기보다 이 세 패턴의 조합으로 읽는 편이 구조 이해에 유리합니다.

한 가지 어긋남이 있습니다. 인사이트(C)는 저장소 문서(ADR-001)가 LLM 서사 생성을 서술합니다. 반면 현재 코드는 Neptune 집계와 결정적 템플릿만 사용하는, 문서와 코드가 어긋나는 지점입니다.

05실제 운영: 배포, 인증, 라이브 데모

이 절은 이 시스템을 실제로 어떻게 배포하고 보호하는지 다룹니다. 그리고 어디에서 직접 볼 수 있는지도 안내합니다.

5.1 배포 파이프라인

CI(코드가 올라올 때마다 자동으로 도는 빌드와 테스트)는 GitHub Actions 3개 병렬 잡입니다. api는 pytest, web은 tsc + next build, cdk는 Jest 불변식 테스트를 돌립니다. 테스트 규모는 어느 정도일까요? v0.5.6 기준 pytest 스위트는 175개가 통과합니다.

이미지 배포는 수동입니다. ARM64 이미지를 빌드해 ECR에 푸시한 뒤 ECS 서비스를 강제 재배포합니다.

배포 - 개발 호스트에서 실행 (CLAUDE.md의 절차)
docker build --platform linux/arm64 -f api/Dockerfile -t <ecr>/ontology-mfg-dev-api:latest .
docker push <ecr>/ontology-mfg-dev-api:latest
aws ecs update-service --cluster ontology-mfg-dev-cluster \
  --service ontology-mfg-dev-api --force-new-deployment   # 롤링 재배포 ~3-5분

5.2 인증과 가드레일

전체 사이트는 Amazon Cognito User Pool(us-east-1)로 보호됩니다. API 미들웨어가 JWT(로그인 사실을 담은 서명된 토큰)를 검증하고, /healthz 같은 경로만 예외입니다.

여기에 Bedrock Guardrails(LLM의 입출력을 정책으로 거르는 필터)가 제조 특화 4개 토픽(기밀 IP, 경쟁사 비방, 규제 위반, 유해 화학물질)을 거릅니다. 개입 내역은 운영 콘솔에서 노출됩니다. Neptune과 OpenSearch는 VPC 내부 전용이라 외부에서 직접 접근할 수 없고 API 태스크 롤로만 접근이 허용됩니다.

5.3 라이브 데모와 운영 콘솔

라이브 데모는 https://mfg-ontology.whchoi.net 에서 동작하며 Cognito 로그인이 필요합니다 (계정은 프로젝트 소유자를 통해 발급). 운영 콘솔에는 관측 도구 두 가지가 있습니다.

하나는 30개 제조 도메인 질의를 재실행해 점수를 매기는 평가 보드(/api/ops/eval)입니다. 다른 하나는 최근 200개 tool_call 이벤트를 보여주는 트레이스 링 버퍼(/api/ops/trace)입니다. 에이전트가 어떤 도구를 어떤 인자로 불렀는지 배포 환경에서 바로 확인할 수 있습니다.

참고 - SSE와 CloudFront의 궁합

토큰 스트리밍은 중간의 어떤 계층이라도 버퍼링하면 무너집니다. 이 프로젝트는 CloudFront의 origin 압축을 SSE 경로에서 비활성화했습니다(ADR-007). Lambda@Edge는 viewer request(인증)에만 붙여 origin response 단계의 버퍼링을 피했습니다.

SSE가 배포에서만 한 덩어리로 도착한다면 이 두 지점을 먼저 확인할 필요가 있습니다.

06한계

이 절은 이 프로젝트를 근거로 판단하기 전에 알아야 할 경계를 정리합니다. 좋은 점만 보지 않기 위한 목록입니다.

이 프로젝트는 PoC(개념 검증용 프로젝트)이고, 저장소 스스로도 그렇게 선언합니다. 도입 판단을 하기 전에 다음을 확인해야 합니다.

  • 합성 데이터입니다. 그래프의 약 10,644개 노드는 생성기가 만든 것으로, 실제 협력사와 부품 정보는 포함하지 않습니다. 표준/규제 데이터만 실제 체계의 서브셋입니다. 실데이터 규모(수백만 노드)에서의 Neptune 질의 성능은 검증되지 않았습니다.
  • 리랭커가 비활성 상태입니다. ap-northeast-2 미제공으로 검색 품질은 RRF 융합까지만 반영되어 있습니다. 코드의 리랭크 단계는 현재 배포에서 통과(pass-through)합니다.
  • 이미지 배포가 수동입니다. CI는 테스트만 수행하고, ECR 푸시와 ECS 재배포는 사람이 실행합니다.
  • Cypher 읽기 전용 게이트웨이는 정규식 거부 목록 기반입니다. 방어층으로 유효하지만, 프로덕션이라면 권한 분리(읽기 전용 엔드포인트나 IAM 정책 수준의 제약)를 병행하는 편이 안전합니다.
  • 데모가 Cognito로 잠겨 있어 문서만으로는 화면을 검증할 수 없습니다. 코드와 docs/의 서술이 1차 근거입니다.
  • 수치 검증 과정에서 문서와 코드의 어긋남은 발견하지 못했습니다. 22클래스, 도구 5종, 페르소나 5종, 시나리오 12종 모두 README 서술과 schema.ttl, 코드가 일치합니다. 다만 docs/architecture.md의 "16 routers" 서술은 라우터 파일 15개에 main.py/healthz 엔드포인트를 더해 세어야 맞습니다.

07결론

마지막으로 이 프로젝트가 남기는 교훈을 정리합니다. 한 문장으로 요약하면, 지식은 그래프에, 정확한 계산은 결정적 엔진에, 해석과 서술만 LLM에 맡기는 역할 분리가 이 프로젝트의 핵심입니다.

ontology-for-mfg가 보여주는 것은 "LLM에 제조 데이터를 붙이는" 일반론이 아니라 역할 분리의 구체적인 배치입니다. 도메인 지식은 22클래스 스키마와 그래프에, 정확한 계산은 결정적 엔진에, 모호한 질의 해석과 서술만 LLM에 둡니다. 그 결과 12개 시나리오 중 LLM이 필요한 것은 2개(B, J)뿐이고, 나머지는 재현 가능한 그래프 질의로 답합니다.

제조 도메인에 온톨로지 기반 에이전트를 검토한다면 재사용할 수 있는 패턴은 네 가지입니다. BOM과 규제를 클래스로 승격한 스키마 설계, 읽기 전용 Cypher 게이트웨이, Sonnet/Haiku 역할 분리와 25초 타임아웃에 결정적 폴백을 더한 구성, 그리고 페르소나를 라우팅이 아닌 런타임 컨텍스트로 다루는 프레이밍 구조입니다.

코드는 GitHub에 공개되어 있습니다. schema.ttl과 api/services/agent.py부터 읽기 시작하는 것을 권합니다.

인터랙티브 아키텍처 맵 전체 이미지 - 시스템 구성 요소와 흐름을 한 화면으로 보여줍니다
그림 2. 인터랙티브 아키텍처 맵 전체 보기. 이미지를 클릭하면 노드 탐색, 경로 추적, 다크/라이트 테마를 지원하는 인터랙티브 버전 ↗이 열립니다.

--참고 자료

본문이 근거로 삼은 저장소와 공식 문서 목록입니다.

핵심 출처

공식 문서

AIML / Architecture Deep Dive

ontology-for-mfg: Architecture Analysis of a High-Tech Manufacturing Ontology PoC

A PoC that models the manufacturing domain (BOM, supply chain, standards/regulations, quality, operations) as a knowledge graph with 22 ontology classes, then puts a Bedrock agent and 12 scenarios on top of it. This analysis is grounded in the code and the schema.

This document was written as of 2026-08-09.

The subject of the analysis is ontology-for-mfg v0.5.6 (released 2026-05-15).

The ontology definition file is ontology/schema.ttl; the agent entry point is api/services/agent.py.

The primary sources are the code, schema, and docs/ documentation of the GitHub repository whchoi98/ontology-for-mfg.

Summary

01Why Manufacturing Needs an Ontology

This section explains why data questions on a manufacturing floor are hard to answer. It then shows how organizing knowledge as a graph removes that difficulty.

Most data questions in high-tech manufacturing can only be answered by following relationships across several hops. Take a single question: "which components in this product contain substances regulated under REACH?" Answering it requires a join of four or more hops: product → module → component → substance → regulation.

Relational tables can answer it. But every new question forces the join path to be redesigned. It is also hard for an LLM to compose such queries on its own.

This project uses an ontology (a schema that defines a domain's concepts and relationships in a machine-readable way) to make three manufacturing-specific relationship chains explicit.

  • The BOM hierarchy. A BOM (bill of materials) lists which parts a product is built from. Product -hasModule-> Module -consistsOf-> Component -madeOf-> RawMaterial takes the product structure down into a 4-level graph.
  • Regulatory tracing. The Component -containsSubstance-> Substance -regulatedBy-> Regulation chain exists in the schema. You can start from a component and determine REACH-SVHC or RoHS applicability with graph traversal alone.
  • Quality tracing. The schema holds QualityIncident -about-> Component, EightDReport -addresses-> QualityIncident, and EightDReport -identifies-> RootCause -linkedTo-> Supplier. A quality incident connects to its root cause and the responsible supplier within a single graph.

Promoting standards and regulations from data to classes is where this project diverges from its sibling retail project. Four classes (Standard, Certification, Regulation, Substance) exist in the schema. Real standards-data subsets from 10 frameworks (JEDEC, IPC, AEC-Q, IATF 16949, ISO 9001, REACH-SVHC, RoHS, CBAM, IRA, USMCA) are loaded from data/public/.

As a result, a component's certification status and trade-regulation exposure become graph-queryable.

Note - what "ontology" means in this document

Here, ontology does not mean a heavyweight semantic-web stack with an OWL reasoner. It means a pragmatic schema: class and relationship definitions written in OWL syntax in schema.ttl, then carried over as labels and edge types in a Neptune property graph. Queries are written in openCypher (a query language for graph databases), not SPARQL.

02The Big Picture: the 22-Class Schema and AWS Architecture

This section walks through the system's skeleton. It covers the schema that holds the knowledge, the AWS services that run it, and which AI model is used where.

2.1 The 22-class schema

How big is the schema? ontology/schema.ttl defines 22 owl:Class and 24 owl:ObjectProperty entries. The classes fall into five groups.

What to look for in the table below: how the 22 classes group into five families, and which relationships tie each family together.

Table 1. The 22 ontology classes (from ontology/schema.ttl)
GroupClassesRepresentative relationships
BOM hierarchy (4) Product, Module, Component, RawMaterial hasModule, consistsOf, madeOf
Supply chain (7) Manufacturer, Supplier, SubSupplier, CustomerAccount, Plant, Region, TradeLane suppliedBy, subSupplies, operates, shipsVia, connects
Standards/Regulations (4) Standard, Certification, Regulation, Substance conformsTo, certifiedBy, containsSubstance, regulatedBy, subjectTo
Quality (3) QualityIncident, EightDReport, RootCause about, addresses, identifies, linkedTo
Operations/ESG (4) Telemetry, MaintenanceEvent, ESGIndicator, CarbonScope from, on, measuredAt, emits

Where does the data come from? A synthetic-data generator (data/synthetic/) produces roughly 10,644 nodes following this schema and exports them as ndjson. An in-VPC loader then ingests them into Neptune (openCypher bulk) and OpenSearch (_bulk).

The same schema also exists as Pydantic models (data/schemas.py). Thanks to this, generation, loading, and API responses share a single type definition.

2.2 AWS architecture

The runtime environment is entirely AWS managed services. By role, the lineup is as follows.

  • The knowledge graph is Amazon Neptune (openCypher, VPC-internal only).
  • Semantic search is Amazon OpenSearch Serverless (VECTORSEARCH collection, Korean Nori analyzer + k-NN HNSW).
  • The LLM is the Amazon Bedrock Converse API, and compute is two ECS Fargate ARM64 services (api, web).
  • The edge is CloudFront with an ACM custom domain, and auth is Amazon Cognito.

The entire infrastructure is defined as 6 AWS CDK v2 (TypeScript) stacks (network, data, ai, compute, edge, observability).

flowchart LR U["Browser"] --> CF["CloudFront + Cognito auth"] CF --> WEB["ECS Web - Next.js 14"] CF --> ALB["ALB /api/*"] ALB --> API["ECS API - FastAPI AgentRunner"] API --> NEP["Neptune openCypher, 22 classes"] API --> AOSS["OpenSearch Serverless BM25 + k-NN"] API --> BR["Bedrock Sonnet 4.6 / Haiku 4.5 + KB + Guardrails"]
Figure 1. Request flow. CloudFront splits static web and /api/* paths, and the FastAPI agent combines the three engines (Neptune, OpenSearch, Bedrock) to stream responses over SSE.

2.3 Bedrock model routing

Models are split by purpose. Conversation and insights, which need long-form Korean reasoning and multi-round tool use (the model calling external tools mid-conversation), go to Sonnet. Structured output with a fixed schema goes to Haiku.

What to look for in the table below: the model ID for each purpose, using the defaults in api/config.py.

Table 2. Model routing (defaults in api/config.py)
PurposeModel ID
Conversational agent, insights (tool-use orchestrator)global.anthropic.claude-sonnet-4-6
8D drafting, follow-up question generation, code-graph community labelingglobal.anthropic.claude-haiku-4-5-20251001-v1:0
Embeddings (1,024 dimensions)amazon.titan-embed-text-v2:0
RerankerEnv var left empty - disabled, not available in ap-northeast-2

03Four Core Mechanisms

This section looks into four parts at the heart of the system. They are the loop where the agent picks tools, the way two searches are merged, the viewer-specific framing, and one representative scenario.

3.1 The agent tool-use loop: 5 tools

The heart of the conversational agent (scenario B) is the AgentRunner in api/services/agent.py. It calls Bedrock converse_stream and, whenever the model requests a tool, feeds the execution result back into the conversation. This loop runs for up to 8 rounds (max_rounds=8).

How much faster did responses get? Since v0.5.6, contentBlockDelta text chunks are forwarded as SSE (a web standard where the server pushes a response in small real-time pieces) delta events the moment they arrive. Per the repository CHANGELOG, time to first token dropped from 2-5 seconds to around 300-600ms.

What to look for in the table below: the 5 tools the agent can pick from, and the backend each tool actually calls.

Table 3. The agent's 5 tools (_TOOLS in api/routers/chat.py)
ToolRoleBackend
search_semanticFuzzy concept search (e.g. automotive -40°C BGA)OpenSearch hybrid search
neptune_queryPrecise graph queries over BOM, Supplier, Plant, TradeLaneNeptune openCypher
kb_retrievePassage retrieval over datasheets, 8D reports, regulatory documentsBedrock Knowledge Base
compliance_checkREACH, RoHS, AEC-Q verification by component IDDeterministic rule engine
memory_saveSession-scoped fact storageDynamoDB table (ontology-mfg-dev-memory) - the Aurora migration noted in code comments is not yet implemented

There are two layers of stability protection. First, timeouts on synchronous Bedrock calls. The 8D pipeline (8D is a standard manufacturing report format that organizes a quality incident's causes and countermeasures into 8 items) and ops evaluation runs are bounded by a 25-second timeout via ThreadPoolExecutor.submit().result(timeout=25).

On expiry they fall back to a deterministic template (ADR-003). Chat is handled separately as converse_stream streaming.

Second, synthetic fallbacks. So that the demo never renders an empty screen when a data path dies, most deterministic scenarios (10 routers) carry a synthetic fallback and a _synthetic flag. Search (A) and chat (B) do not.

Caution - the defenses you need when an LLM writes graph queries

neptune_query is a tool where the model writes Cypher directly. That means prompt injection (an attack that alters the model's behavior through malicious input) could smuggle in write queries.

This project puts a read-only gateway in chat.py:_tool_neptune. It blocks CREATE, DELETE, SET, MERGE, DROP and similar via a regex denylist (ADR-002), and passes user-supplied labels only through a 22-class allowlist. If you build the same structure and omit this layer, you leave open a path for the agent to mutate the graph.

3.2 Hybrid search: BM25 + k-NN + RRF

Semantic search (scenario A) runs two searches in parallel and merges them. One is Korean Nori-analyzer-based BM25 (classic keyword search that scores documents by word matches). The other is k-NN (search that finds the documents whose vectors are closest) over Titan 1,024-dimension embeddings (a sentence's meaning encoded as a numeric vector).

How are the two result sets combined? Each fetches 50 hits, and Reciprocal Rank Fusion, or RRF (k=60), which scores documents purely by their rank in each list, fuses the rankings to return the top 10. OpenSearch Serverless has no search pipeline module, so the RRF fusion is performed directly in Python.

api/services/search.py - RRF fusion (excerpt)
@staticmethod
def rrf(hit_lists: list[list[dict]], k: int = 60) -> list[tuple[str, float]]:
    scores: dict[str, float] = {}
    for hits in hit_lists:
        for rank, h in enumerate(hits, start=1):
            doc_id = h["_id"]
            scores[doc_id] = scores.get(doc_id, 0.0) + 1.0 / (k + rank)
    return sorted(scores.items(), key=lambda kv: kv[1], reverse=True)

The design intent is complementarity. BM25 is strong on exact tokens like part numbers and standard names. k-NN is strong on differently-worded queries like "capacitor for automotive high-temperature environments".

A reranker (a stage that re-orders search results with a more precise model) is prepared in the code, backed by Bedrock. It is disabled in the current deployment, however, because it is not available in ap-northeast-2.

3.3 Per-persona framing

Same screen, same question - but each viewer has different KPIs. This project treats its five personas (Buyer, Engineer, Quality, SCM, Plant - user role types) as runtime context, not routing.

On the web, a single useActivePersona() context changes the framing of all 12 scenario screens. In the API, the system prompt is formatted with the persona value. CLAUDE.md records that per-persona route directories were built and then removed in v0.5.2.

At the end of every turn, api/services/followups.py uses Haiku (300-token budget) to generate three Korean follow-up questions. They are emitted as an SSE suggested_followups event, and a per-persona tone map goes in at this point.

For example, Buyer questions lean toward unit cost, lead time, and MOQ. Engineer leans toward specs and AEC-Q/JEDEC certification, Quality toward 8D and REACH-SVHC, SCM toward TradeLane, IRA, and CBAM, and Plant toward OEE and telemetry. On generation failure it quietly falls back to an empty array.

3.4 A representative scenario pattern: 8D / RCA

The 8D report scenario (J) best illustrates how this architecture composes. The graph holds the quality chain from QualityIncident through EightDReport and RootCause to Supplier. api/services/eight_d_writer.py drafts the report.

How is the output format guaranteed? Haiku is forced to call the emit_eight_d tool exactly once, and the tool schema requires 8 mandatory string fields (D1-D8), so the format is guaranteed by the schema, not the prompt. maxTokens=1500 keeps it inside the 25-second budget.

Principle: structured output goes to a small model plus a tool-use schema. Free-form reasoning goes to a large model plus a tool loop. This separation runs through the whole project (ADR-001).

04The 12 Scenarios at a Glance

This section lays out the demo's 12 screens in a single table. The key point is which of them use an LLM and which do not.

Scenarios A through L cover the manufacturing lifecycle. Each scenario maps to one router in api/routers/ and one web page. The LLM is involved only in the B and J family; most of the rest are combinations of graph queries and deterministic domain engines.

What to look for in the table below: the router and core engine behind each scenario, where the core-engine column reflects the services each router actually imports.

Table 4. The 12 scenarios A-L (based on api/routers/)
CodeScenarioRouterCore engine
ASemantic searchsearch.pyHybrid search (BM25 + k-NN + RRF) + Neptune
BConversational agentchat.pyAgentRunner (Sonnet 4.6) + 5 tools, SSE
CInsightsinsights.pyNeptune aggregation + deterministic templates (no LLM, plain POST)
DSpec matchspec_match.pyHybrid search + reranker interface
ECompliance verificationcompliance.pycompliance_engine + Neptune
FSubstitute partssubstitute.pyNeptune graph queries
GPrice/inventory comparisonprice.pyNeptune graph queries
HGlobal SCM lane reroutingscm_lane.pylane_router simulation + carbon_calc
ISupplier RFMsupplier_rfm.pyrfm_scorer + Neptune
J8D / RCAeight_d.pyeight_d_writer (Haiku 4.5, 8-field tool use), SSE
KESG / CBAMesg_cbam.pycarbon_calc + Neptune
LPdM / IoTpdm.pyTelemetry, MaintenanceEvent graph queries

The patterns compress into three. Search-type (A, D): hybrid search generates candidates and the graph attaches context. Deterministic (C, E, F, G, H, I, K, L): openCypher queries and domain engines (tariff lane simulation, RFM scoring, carbon calculation) compute values without an LLM.

Only the generative pair (B, J) involves Bedrock, and all of them have SSE streaming and timeout fallbacks. Reading the 12 as combinations of these three patterns is more useful for understanding the structure than reading them as a list.

One caveat exists. For insights (C), the repository documentation (ADR-001) describes LLM narrative generation. The current code, however, uses only Neptune aggregation and deterministic templates - a point where docs and code diverge.

05Running It: Deployment, Auth, Live Demo

This section covers how the system is actually deployed and protected. It also points to where you can see it running.

5.1 Deployment pipeline

CI (the build and tests that run automatically on every push) is three parallel GitHub Actions jobs. api runs pytest, web runs tsc + next build, and cdk runs Jest invariant tests. How large is the test suite? As of v0.5.6 the pytest suite passes 175 tests.

Image deployment is manual. An ARM64 image is built, pushed to ECR, then the ECS service is force-redeployed.

Deployment - run from the dev host (procedure from CLAUDE.md)
docker build --platform linux/arm64 -f api/Dockerfile -t <ecr>/ontology-mfg-dev-api:latest .
docker push <ecr>/ontology-mfg-dev-api:latest
aws ecs update-service --cluster ontology-mfg-dev-cluster \
  --service ontology-mfg-dev-api --force-new-deployment   # rolling redeploy, ~3-5 min

5.2 Auth and guardrails

The whole site is protected by an Amazon Cognito User Pool (us-east-1). API middleware validates JWTs (signed tokens that carry proof of login), and only paths like /healthz are exempt.

On top of this, Bedrock Guardrails (a policy filter over the LLM's inputs and outputs) screens four manufacturing-specific topics (confidential IP, competitor disparagement, regulatory violations, hazardous chemicals). Intervention records surface in the ops console. Neptune and OpenSearch are VPC-internal only - unreachable from outside and accessible only via the API task role.

5.3 Live demo and ops console

The live demo runs at https://mfg-ontology.whchoi.net and requires a Cognito login (accounts are issued through the project owner). The ops console includes two observability tools.

One is an evaluation board (/api/ops/eval) that replays 30 manufacturing-domain queries and scores them. The other is a trace ring buffer (/api/ops/trace) showing the last 200 tool_call events. You can see in the deployed environment exactly which tools the agent called and with which arguments.

Note - how SSE and CloudFront get along

Token streaming collapses if any intermediate layer buffers. This project disables CloudFront origin compression on the SSE path (ADR-007). Lambda@Edge is attached only to viewer request (auth), avoiding buffering at the origin response stage.

If SSE arrives as one lump only in the deployed environment, these are the two places to check first.

06Limitations

This section lists the boundaries you should know before judging anything based on this project. It exists so the picture is not only the good parts.

This project is a PoC (proof of concept), and the repository says so itself. Before making an adoption decision, check the following.

  • The data is synthetic. The roughly 10,644 nodes in the graph were produced by a generator and contain no real supplier or component information. Only the standards/regulation data is a subset of real frameworks. Neptune query performance at real-data scale (millions of nodes) has not been validated.
  • The reranker is disabled. Because it is not available in ap-northeast-2, search quality reflects only up to RRF fusion. The rerank stage in the code is currently a pass-through in the deployment.
  • Image deployment is manual. CI runs tests only; ECR push and ECS redeploy are executed by a human.
  • The read-only Cypher gateway is based on a regex denylist. It is a valid defensive layer, but in production it would be safer to pair it with privilege separation (a read-only endpoint or IAM-policy-level constraints).
  • The demo is locked behind Cognito, so the screens cannot be verified from documentation alone. The code and the docs/ descriptions are the primary evidence.
  • No documentation/code mismatches were found while verifying the numbers. The 22 classes, 5 tools, 5 personas, and 12 scenarios all match the README, schema.ttl, and the code. One nuance: the "16 routers" statement in docs/architecture.md only adds up if you count the 15 router files plus the /healthz endpoint in main.py.

07Conclusion

Finally, here is what this project teaches. To sum it up in one sentence: keep knowledge in the graph, keep exact computation in deterministic engines, and give only interpretation and narration to the LLM - that role separation is the core of this project.

What ontology-for-mfg demonstrates is not the generic idea of "attaching manufacturing data to an LLM" but a concrete arrangement of separated roles. Domain knowledge lives in the 22-class schema and the graph, exact computation lives in deterministic engines, and only ambiguous query interpretation and narration go to the LLM. As a result, only 2 of the 12 scenarios (B, J) need an LLM; the rest answer with reproducible graph queries.

If you are evaluating an ontology-backed agent for a manufacturing domain, four patterns here are reusable. They are a schema design that promotes BOM and regulations to classes, a read-only Cypher gateway, the Sonnet/Haiku role split with a 25-second timeout plus deterministic fallback, and a framing structure that treats personas as runtime context rather than routing.

The code is public on GitHub. A good starting point is to read schema.ttl and api/services/agent.py first.

Full image of the interactive architecture map showing the system components and flows in one view
Figure 2. Full view of the interactive architecture map. Click the image to open the interactive version ↗ with node search, route tracing, and dark/light themes.

--References

These are the repository and official documents this analysis is grounded in.

Primary sources

Official documentation