Para aparecer no ChatGPT em 2027, uma empresa precisa ser tecnicamente acessível aos sistemas de IA, apresentar informações claras sobre quem é e o que oferece, responder às perguntas que potenciais clientes realmente fazem e construir sinais externos que confirmem a sua autoridade. Não existe um botão que coloque automaticamente uma empresa nas respostas do ChatGPT. A visibilidade depende de vários elementos trabalhando em conjunto: rastreamento, conteúdo, clareza semântica, autoridade, consistência de informações, relevância para perguntas específicas e presença em fontes externas. Durante muitos anos, empresas otimizaram páginas quase exclusivamente para posições no Google. Agora existe uma segunda camada. Além de aparecer nos mecanismos de pesquisa tradicionais, a empresa precisa aumentar a probabilidade de ser encontrada, compreendida e selecionada por sistemas como ChatGPT, Perplexity, Gemini e outros motores de resposta baseados em inteligência artificial. É neste cenário que entra o GEO, ou Generative Engine Optimization. O que significa aparecer no ChatGPT? A expressão “aparecer no ChatGPT” pode significar diferentes coisas. Uma empresa pode aparecer: como marca mencionada numa resposta; como empresa sugerida numa recomendação; como opção numa comparação; como fonte utilizada para sustentar uma resposta; através de uma página apresentada numa pesquisa; como produto recomendado numa consulta comercial; como referência associada a uma determinada categoria. Esses cenários não são exatamente iguais. Uma página pode ser encontrada e citada sem que a empresa seja recomendada. Da mesma forma, uma marca pode aparecer numa recomendação porque existe um forte conjunto de sinais externos associados a ela, mesmo quando o próprio domínio não ocupa a primeira posição no Google. É por isso que acompanhar apenas rankings tradicionais já não oferece uma visão completa da presença digital de uma empresa. Como o ChatGPT encontra empresas? Quando o ChatGPT utiliza pesquisa na web, ele pode consultar páginas públicas e diferentes fontes para construir uma resposta. Isso significa que três perguntas se tornam essenciais: O ChatGPT consegue encontrar a sua empresa? O ChatGPT consegue entender claramente o que a empresa oferece? Existem sinais suficientes para associar a empresa à pergunta feita pelo utilizador? Muitas empresas resolvem apenas a primeira parte. Possuem um website indexável, mas a proposta comercial é vaga, as páginas não respondem diretamente às perguntas dos clientes e existem poucas referências externas confirmando o posicionamento da marca. Ser tecnicamente acessível é importante. Mas ser compreensível e relevante é igualmente importante. GEO não é simplesmente SEO com outro nome SEO continua importante. Boa arquitetura do site, páginas rastreáveis, conteúdo relevante, autoridade, links internos e clareza semântica continuam a contribuir para a descoberta de uma empresa. Mas uma resposta generativa funciona de forma diferente de uma página tradicional de resultados. Num mecanismo de pesquisa, a competição normalmente acontece por posições numa lista. Num sistema generativo, a competição pode acontecer para se tornar: uma entidade reconhecida; uma fonte relevante; uma opção numa shortlist; uma empresa associada a uma categoria; uma recomendação para determinada situação. Imagine uma empresa que vende software de faturação. Ela pode tentar posicionar uma página para: “software de faturação” Mas potenciais clientes podem perguntar ao ChatGPT: “Qual software de faturação é melhor para uma pequena agência?” “Que ferramenta permite faturação recorrente para freelancers?” “Quais são as melhores alternativas ao software que utilizo atualmente?” “Que solução funciona melhor para empresas com clientes internacionais?” Cada pergunta possui uma intenção diferente. O objetivo deixa de ser otimizar uma página para uma única palavra-chave e passa a incluir uma rede de perguntas, problemas, comparações, entidades e situações comerciais. Os principais fatores para melhorar a visibilidade no ChatGPT Não existe uma fórmula pública que garanta uma menção. Também não existe uma lista oficial completa de fatores de classificação para respostas do ChatGPT. Por isso, empresas devem trabalhar diferentes áreas simultaneamente. As principais áreas são: rastreamento; posicionamento; conteúdo; evidências; presença externa; estrutura; atualização; monitorização. Nenhum desses elementos isoladamente garante resultados. A vantagem aparece quando trabalham em conjunto. 1. Certifique-se de que o seu site pode ser descoberto O primeiro passo é técnico. Verifique se páginas importantes podem ser rastreadas e acessadas corretamente. Analise: robots.txt; configurações da CDN; firewall; sistemas anti-bot; páginas carregadas exclusivamente por JavaScript; erros 403; redirecionamentos; meta tags noindex; páginas protegidas por login. Uma empresa pode possuir excelente conteúdo, mas se páginas importantes estiverem bloqueadas ou inacessíveis, a sua capacidade de descoberta diminui. Também vale a pena separar o conceito de descoberta em pesquisa do conceito de utilização de conteúdo para outros fins. Para empresas interessadas em visibilidade, o foco deve estar inicialmente em permitir que as páginas públicas importantes sejam descobertas corretamente. 2. Explique claramente quem é a empresa Muitos websites são escritos como campanhas publicitárias. Isso pode produzir páginas visualmente impressionantes, mas semanticamente vagas. Compare: “Transformamos o futuro através de experiências inteligentes.” com: “Plataforma de contabilidade online para pequenas empresas e freelancers.” A segunda frase comunica muito mais informação. Uma máquina precisa conseguir identificar rapidamente: nome da empresa; categoria; produto; serviço; público-alvo; mercado; problema resolvido; principais funcionalidades; diferenças em relação a alternativas. Slogans podem continuar a existir. O problema acontece quando substituem completamente explicações concretas. 3. Crie conteúdo baseado em perguntas reais Uma estratégia de conteúdo para inteligência artificial não deve começar apenas com uma lista de palavras-chave. Comece pelas perguntas. Uma empresa de software de recursos humanos, por exemplo, pode mapear perguntas como: “Qual software de RH é melhor para empresas com 50 funcionários?” “Como automatizar o onboarding de novos colaboradores?” “Software de RH funciona para equipas remotas?” “Quais são as melhores alternativas ao concorrente X?” “Quanto custa implementar um sistema de RH?” “Como controlar férias e ausências numa pequena empresa?” Essas perguntas aproximam o conteúdo da forma como as pessoas utilizam ferramentas conversacionais. Cada página deve resolver uma intenção específica. 4. Cubra o tema em profundidade Publicar cinco artigos muito semelhantes sobre a mesma palavra-chave raramente cria autoridade real. É melhor desenvolver cobertura temática. Uma plataforma de gestão de projetos, por exemplo, poderia produzir conteúdo sobre: gestão de tarefas; planeamento de projetos; colaboração remota; metodologias; cronogramas; gestão de recursos; templates; relatórios; integrações; automação; comparação de ferramentas. Esta abordagem ajuda a criar uma relação mais clara entre a empresa e o tema que deseja dominar. Em vez de tentar “ranquear para tudo”, a empresa constrói profundidade dentro de uma área específica. 5. Escreva respostas que sejam fáceis de entender Conteúdo excessivamente abstrato pode dificultar a extração de respostas. Quando uma página responde a uma pergunta importante, faça isso rapidamente. O que é GEO? GEO, ou Generative Engine Optimization, é o processo de melhorar o conteúdo, as entidades e os sinais digitais de uma empresa para aumentar a sua probabilidade de ser encontrada e mencionada por motores de resposta baseados em inteligência artificial. Depois dessa definição, o artigo pode aprofundar o tema. Esse formato funciona melhor do que esconder a resposta depois de uma longa introdução. Utilize: perguntas como subtítulos; parágrafos focados; definições diretas; listas quando forem úteis; exemplos; FAQs. A clareza não significa escrever como um robô. O conteúdo ainda deve ser natural e agradável para leitores humanos. 6. Trabalhe a entidade da empresa Para sistemas de IA, uma empresa não é apenas um domínio. Ela pode ser entendida como uma entidade conectada a várias outras informações. Por exemplo: empresa → fundador → produto → categoria → mercado → clientes → integrações → avaliações → publicações. Quanto mais consistente essa rede, mais fácil se torna compreender o posicionamento da marca. Verifique se informações importantes permanecem consistentes em diferentes plataformas. Isso inclui: nome da empresa; descrição; categoria; website; produtos; localização; mercado atendido; perfis sociais; páginas de parceiros. Contradições podem criar incerteza. 7. Construa referências fora do próprio website Uma empresa afirmar no próprio site que é a melhor da categoria é apenas uma afirmação interna. Quando outras fontes independentes mencionam a marca, surge uma camada adicional de validação. Dependendo do setor, essas referências podem aparecer em: publicações especializadas; diretórios relevantes; entrevistas; podcasts; páginas de parceiros; avaliações; estudos; comunidades; artigos comparativos; bases de dados públicas. O objetivo não deve ser simplesmente conseguir o maior número possível de menções. Contexto e relevância importam. Uma menção dentro de uma página diretamente relacionada ao seu setor pode ter muito mais valor estratégico do que dezenas de referências aleatórias. 8. Produza comparações realmente úteis Consultas comparativas são comuns em ferramentas de IA. Por exemplo: “X ou Y?” “Quais são as alternativas a X?” “Qual ferramenta é melhor para pequenas empresas?” “Que solução devo escolher para uma equipa remota?” Uma empresa pode criar páginas que expliquem essas diferenças de forma objetiva. Compare critérios reais, como
마찬가지로 제대 날짜가 다가오기때문에 알고리즘을 풀어 보고자 한다. 앞으로는 풀이에 앞서 핵심 아이디어, 시간복잡도, 알고리즘과 자료구조를 먼저 정리할 것이다. 그리고 마지막에 해당 문제의 유형을 스스로 생각해서 정의해볼것이다. 문제 링크 : https://school.programmers.co.kr/learn/courses/30/lessons/468373 문제 설명 edge는 A,B,C 타입이 존재하고 매 행동마다 A,B,C 중 하나를 선택하는 것을 K번 반복해서 최대한 많은 배양체를 감염시킬 수를 구하는 문제다. 아이디어 처음 해야할 일은 주어진 edges를 바탕으로 그래프를 만들어내야한다. 각 노드가 어떤 타입의 edge로 연결되어있는지로 데이터를 구성하고, DFS로 A,B,C 중 하나의 타입을 선택하면서 K의 길이를 가지는 중복순열을 만들어내면된다. 순서는 다음과 같다. 타입을 정한다. 감염된 모든 배양체를 기준으로 인근에 같은 타입을 가진 Node를 그래프 순회하면서 감염시킨다. 이걸 K번 반복한다. 여기서 오픈할 edge 타입을 중복순열 배열로 먼저 만들어두고, 각각 그래프를 순회해서 완전 탐색해도 되지만 DFS를 이용해 하나씩 선택하면서 완전탐색 할 수도있다. 단, 여기서 중요한건 한번 열때 시작으로부터 감염된 노드의 인근에 같은 타입을 가지는 노드가 있다면 그것도 한번에 감염시켜줘야 한다는것이다. 시간복잡도 여기서 K의 길이는 최대 10이므로 각 순열의 최대 수는 3^k 엄밀히 따지면 특정 타입이 연달아 나올수는 없으므로 3*2^(k-1)가 된다. DFS의 비용은 O(V) + O(E)이 므로 시간복잡도는 3* 2^(k-1) * (V+ E)가 된다. 문제 유형 그래프 탐색과 DFS 구현하면 쉽게 풀릴 문제이다. 문제의 유형은 그래프 탐색 + DFS 기반 완전탐색 문제가 되겠다. 전체 코드 const TYPE_A = 1; const TYPE_B = 2; const TYPE_C = 3; const buildGraph = (edges,n) => { const nodes = Array.from({ length : n+1 }, () => []); for (const [parent,child,type] of edges) { nodes[parent] = { ...nodes[parent], [type] : [ ...nodes[parent][type] ?? [], child ] } // 쌍방향이기때문에 그래프를 제대로 완성시켜줘야 nodes[child] = { ...nodes[child], [type] : [ ...nodes[child][type] ?? [], parent ] } } return nodes; } function solution(n, infection, edges, k) { let answer =0; const nodes = buildGraph(edges,n); const infected = Array(n+1).fill(false); const spread = (infected,type) => { const newInfected = [...infected]; const queue = []; // 1~부터 n까지 값이 들어가기때문에 부등호처리 제대로 해야한다. 이걸로 1시간날렸다 for(let i=1; i<=n; i++){ if(newInfected[i] && nodes[i][type]){ for(const nIndex of nodes[i][type]){ if(!newInfected[nIndex]){ newInfected[nIndex]= true queue.push(nIndex); } } } } while(queue.length){ const nextNode = queue.pop(); if(nextNode && nodes[nextNode][type]){ for(const nIndex of nodes[nextNode][type]){ if(!newInfected[nIndex]){ newInfected[nIndex] = true; queue.push(nIndex); } } } } return newInfected; } const dfs = (depth,infected,prevType,logType) => { let count = 0; // 1~부터 n까지 값이 들어가기때문에 부등호처리 제대로 해야한다. 이걸로 1시간날렸다 for(let i =1; i<=n; i++){ if(infected[i]){ count++; } } answer= Math.max(answer,count); if(depth === k){ return } for(const type of [TYPE_A,TYPE_B,TYPE_C]){ if(type === prevType) continue const nextInfected = spread(infected,type) dfs(depth+1,nextInfected,type) } } infected[infection]= true; dfs(0,infected,null) return answer ; }
이 글은 개인 프로젝트 'Dungeon Adventure'을 만들며 겪은 이슈 기록입니다. Dungeon Adventure [Github] 문제 상황 게임을 재시작하면 던전은 새로 생성되지만, 이전 판의 몬스터, 드랍 아이템, 날아가던 투사체가 그대로 남아 있음 원인 확인 재시작할 때 호출되는 ClearDungeon()은 던전이 직접 생성한 오브젝트(방 콜라이더, 문, 장식, 타일)만 정리하고 있었음 // 수정 전 private void ClearDungeon() { foreach (RoomRuntimeData data in runData.Values) { // 방 콜라이더 제거 Destroy(data.roomObject); // 문 각각 제거 foreach (var door in data.doors) { Destroy(door); } foreach (var decoration in data.decorations) { Destroy(decoration); } } // 타일맵 제거 tilemap.ClearAllTiles(); // RunData 제거 runData.Clear(); } 하지만 몬스터, 드랍 아이템, 투사체는 다른 시스템이 오브젝트 풀에서 꺼낸 것이라 정리 대상에서 빠져 있었음 오브젝트 생성 주체 수정 전 정리 여부 방 / 문 / 장식 / 타일 DungeonRenderer O 드랍 아이템 DropSpawner (풀) X 몬스터 MonsterSpawner (풀) X(목록은 있었으나 정리 안 함) 투사체 공격 로직 (풀) X → 누가 오브젝트를 정리할 책임이 있는지 정해져 있지 않은 상황 해결 1. 몬스터: 이미 있던 목록 활용 방별로 관리하던 spawnedMonsters를 순회하며 풀에 반납 2. 드랍 아이템 / 투사체: 오브젝트가 스스로 등록 생성한 쪽이 목록을 관리하는 대신, 오브젝트가 활성화/비활성화될 때 스스로 목록에 등록하고 해제하도록 변경 public static readonly List<Projectile> Active = new List<Projectile>(); private void OnEnable() { // (기존 초기화 코드 생략) Active.Add(this); // 풀에서 꺼내지면 등록 } private void OnDisable() { Active.Remove(this); // 풀에 반납되면 해제 } DroppedItem도 같은 방식으로 적용 3. ClearDungeon()에서 일괄 반납 // 수정 후 private void ClearDungeon() { // 드랍된 아이템 전부 제거 foreach (var item in new List<DroppedItem>(DroppedItem.Active)) { ObjectPoolManager.Instance.Release<DroppedItem>(item.SourcePrefab, item); } // 투사체 전부 제거 foreach (var projectile in new List<Projectile>(Projectile.Active)) { ObjectPoolManager.Instance.Release<Projectile>(projectile.SourcePrefab, projectile); } foreach (RoomRuntimeData data in runData.Values) { // 몬스터 제거 foreach (Monster monster in data.spawnedMonsters) { monster.spawner.ReleaseMonster(monster.sourcePrefab, monster); } Destroy(data.roomObject); foreach (var door in data.doors) Destroy(door); foreach (var decoration in data.decorations) Destroy(decoration); } tilemap.ClearAllTiles(); runData.Clear(); } 복사본을 순회하는 이유 풀에 반납하면 SetActive(false) → OnDisable()이 즉시 호출되어 Active에서 자신을 제거하는데 원본 리스트를 그대로 foreach로 돌면 순회 중에 리스트가 바뀌어 InvalidOperationException이 발생하게됨 따라서 new List<>(Active)로 복사본을 만들어 순회 결과 재시작 후 이전 판의 오브젝트가 남지 않음. 아쉬운 점 및 배운 점 오브젝트를 만드는 쪽과 정리하는 쪽이 다르면, 정리하는 쪽이 목록을 알 방법이 필요하다. 결과적으로 정리 누락은 해결했지만 던전을 그리는 역할인 DungeonRenderer가 투사체와 드랍 아이템의 정리까지 맡게 되었다. 원인으로 짚었던 정리 책임 문제를 해결했다기보다는 책임을 한곳에 몰아넣은 셈이다. 프로젝트에서 이미 SO 이벤트 채널을 쓰고 있는데 재시작 이벤트를 발행하면 각 Spawner가 자신이 만든 오브젝트를 스스로 반납하는 구조가 더 적절할 것 같다는 생각이 들었다. 이렇게 하면 DungeonRenderer는 던전 오브젝트만 정리하고 새로운 풀링 오브젝트가 추가되어도 DungeonRenderer를 수정할 필요가 없다. 추후 리팩토링에 해당 부분을 반영해야 할 것으로 보인다.
Come rendere il tuo brand più facile da trovare, comprendere e citare nelle risposte generate dall’intelligenza artificiale Essere visibili su Google non significa automaticamente essere visibili su ChatGPT. Nel 2026 sempre più persone utilizzano strumenti di intelligenza artificiale per trovare aziende, confrontare prodotti, scegliere software, valutare servizi e ottenere raccomandazioni. Le ricerche stanno diventando sempre più conversazionali. Invece di digitare semplicemente: software CRM un utente può chiedere: Qual è il miglior CRM per una piccola azienda italiana? Oppure: Quali sono le migliori alternative a Salesforce per un team di 10 persone? Oppure ancora: Quale agenzia può aiutarmi ad aumentare la visibilità della mia azienda su ChatGPT? Per le aziende questo crea una nuova sfida. Non basta più essere presenti nei risultati tradizionali di Google. Bisogna anche fare in modo che il proprio brand sia comprensibile, rilevante e abbastanza autorevole da essere preso in considerazione dai sistemi di intelligenza artificiale. Questa disciplina viene spesso chiamata GEO, Generative Engine Optimization . In questa guida vedremo come aumentare concretamente la visibilità del tuo brand su ChatGPT nel 2026. Cosa significa apparire su ChatGPT? Apparire su ChatGPT non significa necessariamente occupare una posizione fissa come accade in una pagina di risultati di Google. Un brand può comparire in modi diversi. Può essere: menzionato in una risposta consigliato insieme ad altri brand utilizzato come esempio inserito in una comparazione associato a una categoria specifica suggerito come soluzione a un problema citato come fonte presentato come alternativa a un concorrente La differenza fondamentale rispetto alla SEO tradizionale è semplice. Google restituisce principalmente una lista di risultati. ChatGPT genera una risposta. Per questo motivo, l'obiettivo non è soltanto ottenere un buon ranking per una keyword. L'obiettivo è fare in modo che il sistema comprenda chiaramente: chi sei cosa offri per chi è adatta la tua soluzione quali problemi risolvi per quali argomenti sei rilevante perché il tuo brand dovrebbe essere preso in considerazione ChatGPT può trovare il tuo sito? Prima di pensare ai contenuti, è importante verificare che il sito sia tecnicamente accessibile. Se le pagine importanti del tuo sito non possono essere correttamente visitate o interpretate dai sistemi automatici, aumentare la visibilità diventa molto più difficile. Controlla quindi: robots.txt eventuali blocchi ai crawler pagine impostate come noindex contenuti accessibili soltanto tramite JavaScript complesso errori di scansione pagine duplicate canonical errati sitemap XML L'accessibilità tecnica non garantisce che il tuo brand venga citato. È però una condizione di base. Se una pagina non può essere scoperta o interpretata correttamente, difficilmente potrà contribuire alla tua visibilità AI. SEO e GEO non sono la stessa cosa SEO e GEO sono strettamente collegate, ma hanno obiettivi differenti. SEO tradizionale GEO Ottimizza la visibilità nei motori di ricerca Ottimizza la presenza nelle risposte AI Si concentra sul ranking delle pagine Si concentra su menzioni e citazioni Lavora soprattutto con keyword e query Lavora con domande, entità e intenti Misura clic, impression e posizioni Misura presenza AI, citazioni e share of voice Punta alla SERP Punta alla risposta generata Ottimizza principalmente pagine Ottimizza anche la comprensione del brand Una buona strategia nel 2026 dovrebbe utilizzare entrambe. La SEO aiuta il tuo sito a essere scoperto. La GEO aiuta il tuo brand a essere compreso e considerato nelle risposte generate dall'intelligenza artificiale. 1. Parti dalle domande reali dei clienti Uno degli errori più comuni è partire soltanto dalle keyword. Le conversazioni su ChatGPT sono spesso molto più specifiche. Un utente non chiede necessariamente: software email marketing Potrebbe chiedere: Qual è un software di email marketing semplice per un piccolo ecommerce Shopify? Oppure: Qual è una buona alternativa economica a Klaviyo? Oppure: Quale piattaforma email è più facile da usare per un negozio con meno di 1.000 clienti? Queste domande contengono molto più contesto rispetto a una keyword tradizionale. Per questo motivo è utile creare una vera e propria mappa delle domande che i potenziali clienti potrebbero fare. Dividile per categorie. Domande informative Esempi: cos'è questo prodotto? come funziona? a cosa serve? quali problemi risolve? Domande commerciali Esempi: qual è il miglior strumento per X? quali aziende offrono Y? quali soluzioni sono adatte a una piccola impresa? Domande comparative Esempi: X o Y? quali sono le differenze tra X e Y? qual è un'alternativa a X? Domande transazionali Esempi: quanto costa? quale piano devo scegliere? dove posso acquistarlo? Domande specifiche per settore Esempi: miglior software per ecommerce migliore agenzia GEO per SaaS migliore piattaforma per ristoranti software CRM per studi professionali Questa mappa dovrebbe diventare la base della tua strategia editoriale. 2. Crea contenuti che rispondano direttamente alle domande Dopo aver individuato le domande, devi creare contenuti che forniscano risposte chiare. Non significa pubblicare centinaia di articoli quasi identici. Significa coprire in modo approfondito gli argomenti per cui vuoi che il tuo brand venga riconosciuto. Se vendi un software di email marketing, potresti creare contenuti su: migliori software di email marketing per ecommerce email marketing per Shopify alternative a Mailchimp alternative a Klaviyo email automatiche per carrelli abbandonati email marketing per piccoli ecommerce software email marketing con AI confronto tra diverse piattaforme Il principio è semplice. Se vuoi essere considerato nelle risposte relative a un argomento, devi creare una presenza digitale forte attorno a quell'argomento. 3. Rispondi velocemente alla domanda principale Molti articoli SEO tradizionali iniziano con introduzioni estremamente lunghe. Per la visibilità AI è spesso meglio arrivare velocemente al punto. Se il titolo della sezione è: Quanto costa un servizio GEO? il primo paragrafo dovrebbe rispondere direttamente. Per esempio: Il costo di un servizio GEO dipende principalmente dal numero di mercati, dal volume di contenuti, dal livello di concorrenza e dalla quantità di query AI che vengono monitorate. Il lettore comprende immediatamente la risposta. Anche un sistema automatico può interpretare più facilmente quella sezione. 4. Rendi ogni sezione comprensibile anche da sola Una pagina può contenere migliaia di parole, ma non è detto che un sistema AI utilizzi l'intero documento. Per questo motivo le singole sezioni devono essere chiare anche prese separatamente. Un buon blocco di contenuto dovrebbe includere: una domanda o un argomento preciso una risposta diretta il contesto necessario termini espliciti esempi quando utili dati quando disponibili Evita riferimenti vaghi come: come abbiamo visto prima oppure: questa soluzione senza specificare a cosa ti riferisci. La chiarezza semantica è importante. 5. Spiega chiaramente cosa fa la tua azienda Molti siti hanno un problema sorprendentemente semplice. Non spiegano chiaramente cosa vende l'azienda. Headline come: Costruiamo il futuro del tuo business oppure: Portiamo la tua crescita al livello successivo possono sembrare accattivanti, ma comunicano pochissime informazioni concrete. È meglio utilizzare messaggi più espliciti. Per esempio: Software di gestione inventario per ecommerce Shopify oppure: Agenzia GEO specializzata nella visibilità dei brand su ChatGPT, Gemini e Perplexity Queste frasi aiutano immediatamente a capire: la categoria il prodotto il pubblico il problema risolto La stessa chiarezza dovrebbe essere presente in: homepage pagina About pagine servizi pagine prodotto case study articoli descrizioni aziendali 6. Costruisci un'identità digitale coerente Il tuo brand deve essere descritto in modo coerente. Se la homepage definisce l'azienda come una piattaforma software, LinkedIn la descrive come un'agenzia e altri siti la presentano come una società di consulenza, possono nascere ambiguità. Naturalmente un'azienda può offrire più servizi. L'importante è che la relazione tra questi servizi sia chiara. Mantieni coerenza su: nome del brand descrizione settore prodotti servizi target località fondatori categorie principali casi d'uso L'obiettivo è costruire un'entità facilmente riconoscibile. 7. Non concentrarti soltanto sul tuo sito La visibilità AI non dipende esclusivamente dai contenuti proprietari. Se soltanto il tuo sito sostiene che sei una delle migliori soluzioni del mercato, quella dichiarazione ha un peso limitato. È più interessante quando altre fonti parlano del tuo brand. Queste fonti possono includere: siti di settore portali specializzati media directory community forum recensioni comparatori podcast interviste partner associazioni blog indipendenti Più il brand compare naturalmente in contesti rilevanti, più forte diventa la sua presenza digitale. 8. Collega il brand agli argomenti giusti Non basta ottenere una semplice menzione del nome. È molto più utile essere menzionati in relazione alla categoria per cui vuoi essere riconosciuto. Immaginiamo una piattaforma chiamata ExampleCRM. Una semplice menzione: ExampleCRM fornisce poco contesto. Una frase come: ExampleCRM è un CRM pensato per piccoli team commerciali B2B crea invece associazioni chiare. Collega il tuo brand a: categoria settore prodotto problema pubblico caso d'uso città o paese concorrenti alternative Questo aiuta a costruire una maggiore rilevanza semantica. 9. Crea contenuti comparativi Le query comparative sono estremamente importanti nelle piattaforme AI. Gli utenti chiedono continuamente: qual è meglio? X o Y? quali sono le alternative a X? quale prodotto è più conveniente? quale soluzione è adatta a una piccola azienda? Per questo motivo può essere utile creare articoli come: HubSpot vs Salesf
Kubernetes 기초 개념과 핵심 리소스 총정리 도커를 접하게 되며 생각했다. *"도커로 컨테이너 띄우는 거 엄청 편한데, 굳이 왜 쿠버네티스(k8s)까지 배워서 써야 하지?"* 하지만 서비스 규모가 커져서 컨테이너가 10개, 50개, 100개로 늘어나고 서버가 여러 대로 쪼개지는 순간 현실적인 지옥이 시작된다. 어느 서버에 여유 공간(CPU/메모리)이 있는지 일일이 확인해서 띄워야 하고, 새벽에 특정 서버의 컨테이너가 죽으면 자다 깨서 수동으로 재기동해야 하며, 트래픽이 몰릴 때마다 수동으로 컨테이너를 늘리고 로드밸런서에 붙여줘야 한다. 이 모든 반복적이고 귀찮은 운영 작업을 "자동화된 시스템" 에 맡기기 위해 탄생한 것이 바로 쿠버네티스(Kubernetes) 다. 쿠버네티스의 기본 아키텍처와 실무에서 다루는 핵심 리소스들을 정리해 본다. 1. 클러스터 아키텍처: 두뇌와 일꾼 쿠버네티스는 여러 대의 물리/가상 서버를 묶어 마치 "하나의 거대한 컴퓨터" 처럼 동작하게 만든다. 컨트롤 플레인 : 클러스터의 관리자이자 두뇌. 직접 앱을 실행하지 않고, 명령을 받고 워커 노드들을 감시하고 스케줄링한다. (AWS EKS를 쓰면 이 부분을 AWS가 돈 받고 완전 관리해 준다.) 워커 노드 : 실제 컨테이너들이 배포되어 사용자 트래픽을 처리하는 일꾼 서버. (AWS EC2 인스턴스) 2. 쿠버네티스의 핵심 : "선언적 상태" 쿠버네티스를 이해하는 가장 중요한 핵심은 "선언적" 이라는 말이다. 명령형 (과거 방식) : *"지금 당장 컨테이너 1개 더 띄워라."* 선언형 (쿠버네티스 방식) : *"내가 원하는 상태는 웹 서버 파드가 항상 3개 유지되는 것이다."* YAML 파일로 "원하는 상태"를 선언해 두면, 쿠버네티스는 24시간 루프를 돌며 "현재 상태"가 "원하는 상태"와 일치하는지 감시 한다. 서버가 다운되거나 컨테이너가 에러로 꺼져서 파드가 2개로 줄어들면, 관리자가 개입하지 않아도 쿠버네티스가 즉시 빈 서버를 찾아 새 파드를 띄워 3개로 맞춘다. 이것이 바로 셀프 힐링 이다. 3. 실무 쿠버네티스 핵심 리소스 맵 (5대 분류) 쿠버네티스는 모든 대상을 리소스 라는 단위로 다룬다. 자주 사용하는 리소스들은 목적에 따라 크게 5가지로 나뉜다. [쿠버네티스 리소스 생태계] ├── 1. 워크로드 (Workload) : 컨테이너를 어떤 형태로 띄울 건지? ├── 2. 설정 & 보안 (Config) : 환경변수와 비밀번호 분리 ├── 3. 스토리지 (Storage) : 영구 데이터 보존 ├── 4. 네트워크 (Network) : 내부 통신 및 외부 노출 └── 5. 운영 & 격리 (Governance) : 구획 분리 및 권한 1 워크로드 (Workload) 리소스 설명 주요 사용처 Pod 쿠버네티스의 가장 작은 배포 단위 . 1개 이상의 컨테이너를 감싼 캡슐. 직접 띄우기보다는 상위 리소스에 의해 관리됨 Deployment 파드의 수량 유지와 무중단 롤링 업데이트 를 보장하는 관리자. 일반적인 백엔드 API, 프론트엔드 웹 서버 (Stateless) StatefulSet 파드의 고유 이름(순번)과 고유 디스크 를 영구 보장하는 관리자. DB(MySQL, PostgreSQL), Kafka, Redis (Stateful) DaemonSet "모든 노드에 무조건 1개씩 띄워라!" Fluent Bit(로그 수집), Prometheus Node Exporter Job / CronJob 계속 켜두는 게 아니라 "한 번 실행되고 끝나면 종료" 되는 작업. DB 마이그레이션, 일일 정산 배치 스크립트 2 설정 및 보안 (Config & Secret) 도커 이미지 안에 DB 비밀번호나 설정값을 하드코딩하지 않고 외부에 주입하기 위해 사용한다. ConfigMap : 일반 텍스트 설정값을 저장하는 상자 (포트 번호, 프로필 dev / prd , 로그 레벨 등) Secret : Base64로 인코딩된 민감한 값을 저장하는 상자 (DB 접속 비밀번호, JWT 시크릿 키, 인증서 등) 3 스토리지 (Storage) 파드는 기본적으로 일회성이라 파드가 죽으면 내부 파일이 모두 증발한다. 데이터를 영구 저장하려면 외부 스토리지를 붙여야 한다. PV (Persistent Volume) : 실제 연결할 물리/클라우드 디스크 (e.g. AWS EBS 100GB 볼륨) PVC (Persistent Volume Claim) : 개발자가 파드에 디스크를 달기 위해 제출하는 "스토리지 신청서" (*"나 20GB SSD 볼륨 줘"*) StorageClass : 개발자가 PVC를 제출했을 때, 백그라운드에서 클라우드(AWS EBS 등)에 가서 디스크를 동적으로 자동 생성해 주는 공장 4 네트워크 (Network) Service : 파드는 죽었다 살아나면 IP가 매번 바뀐다. 서비스는 파드들 앞단에 고정 가상 IP(단일 진입점) 를 제공하고 로드밸런싱을 수행한다. (ClusterIP, NodePort, LoadBalancer) Ingress : 클러스터 외부(인터넷)에서 들어오는 HTTP/HTTPS 트래픽을 도메인이나 URL 경로에 따라 적절한 서비스로 연결해 주는 L7 관문. NetworkPolicy : 쿠버네티스 내부 방화벽. 특정 파드 간의 트래픽만 허용하고 나머지는 차단. 5 운영 및 격리 (Governance) Namespace : 거대한 클러스터를 논리적인 '가상의 방' 으로 나누는 단위 ( dev , prod , monitoring , kube-system ) HPA (Horizontal Pod Autoscaler) : CPU나 메모리 부하에 따라 파드 개수를 자동으로 늘리고 줄이는 오토스케일러. RBAC (Role, RoleBinding, ServiceAccount) : 누가 어떤 리소스에 접근할 수 있는지 제어하는 권한 체계. 4. 확장 리소스: CRD (Custom Resource Definition) 쿠버네티스의 진정한 강력함은 확장성 에 있다. 기본 제공되는 Deployment나 Service 외에도, 개발자가 새로운 리소스 문법을 직접 정의해서 클러스터에 추가할 수 있는데 이를 CRD 라고 부른다. 실무에서 자주 쓰는 KEDA의 ScaledObject 나 Karpenter의 NodePool , Cert-Manager의 Certificate 등이 모두 이 CRD를 통해 쿠버네티스 생태계에 플러그인처럼 붙여서 사용하는 확장 리소스들이다. 5. 마치며 정리하자면: 쿠버네티스는 수많은 컨테이너의 배치, 확장, 장애 복구를 사람 대신 24시간 수행해 주는 컨테이너 오케스트레이션 시스템 이다. 시스템은 두뇌(Control Plane) 와 일꾼(Worker Node) 으로 나뉘며, EKS는 두뇌 영역을 완전 관리형으로 제공한다. 명령이 아니라 원하는 상태(Desired State) 를 선언하면 시스템이 스스로 상태를 맞추는 선언적 방식 으로 동작한다. 실무에서는 워크로드(Deployment/StatefulSet), 설정(ConfigMap/Secret), 스토리지(PVC), 네트워크(Service/Ingress) 리소스를 조합하여 완전한 애플리케이션 플랫폼을 구축한다. 이상.
Die Suche verändert sich auch in der Schweiz. Nutzer verwenden längst nicht mehr nur Google, sondern zunehmend auch ChatGPT, Perplexity, Gemini und andere KI-Systeme, um Unternehmen zu finden, Produkte zu vergleichen und Entscheidungen vorzubereiten. Für Schweizer Unternehmen entsteht dadurch eine neue Aufgabe: SearchGPT SEO beziehungsweise die Optimierung für ChatGPT Search . Dabei geht es nicht darum, klassische SEO zu ersetzen. Entscheidend ist vielmehr die Frage: Wie schaffen Sie es, dass Ihr Unternehmen von ChatGPT gefunden, verstanden und bei relevanten Fragen berücksichtigt wird? Genau hier setzen Generative Engine Optimization, kurz GEO, und moderne AI-Search-Optimierung an. Was ist SearchGPT SEO? SearchGPT war ursprünglich die Bezeichnung für OpenAIs KI-basierte Suchtechnologie. Heute wird in der Praxis häufiger von ChatGPT Search gesprochen. Der Begriff SearchGPT SEO wird dennoch weiterhin genutzt, wenn es darum geht, Websites und Marken für die Suche innerhalb von ChatGPT zu optimieren. Das Ziel unterscheidet sich teilweise von klassischer Google-SEO. Bei Google möchten Unternehmen möglichst weit oben in den Suchergebnissen erscheinen. Bei ChatGPT lautet das Ziel häufiger: Teil der eigentlichen Antwort zu werden. Eine Schweizer Treuhandfirma möchte beispielsweise nicht nur für „Treuhänder Zürich“ ranken. Sie möchte auch bei Fragen berücksichtigt werden wie: „Welche Treuhandfirma in Zürich eignet sich für ein wachsendes SaaS-Unternehmen?“ Oder: „Welche Schweizer Treuhänder haben Erfahrung mit internationalen Firmen?“ Solche Fragen sind länger, spezifischer und häufig näher an einer Kaufentscheidung. Warum ChatGPT Search für Schweizer Unternehmen wichtig wird Google bleibt auch 2026 ein zentraler Bestandteil der Online-Suche. Gleichzeitig verändert sich das Verhalten der Nutzer. Statt mehrere Websites zu öffnen und Informationen selbst zusammenzutragen, können Menschen ihre Situation direkt in ChatGPT beschreiben und eine zusammengefasste Antwort erhalten. Typische Fragen sind zum Beispiel: Welche Software eignet sich für Schweizer KMU? Welche Agentur kann bei GEO und AI Visibility helfen? Welche Anbieter gibt es in Zürich? Welches Produkt passt zu einem bestimmten Anwendungsfall? Was sind gute Alternativen zu einem bekannten Anbieter? Welche Lösung ist für ein kleines Schweizer Unternehmen geeignet? Diese Art von Suchanfragen kann besonders wertvoll sein, weil sie oft deutlich näher an einer Entscheidung liegt als ein allgemeines Informationskeyword. Jemand, der nach „SEO Erklärung“ sucht, hat eine andere Absicht als jemand, der fragt: „Welche GEO-Agentur in der Schweiz kann unseren Shopify-Shop für ChatGPT optimieren?“ SearchGPT SEO ist nicht dasselbe wie klassische SEO Klassische SEO konzentriert sich stark auf Rankings in Suchmaschinen. SearchGPT SEO und GEO konzentrieren sich zusätzlich darauf, ob eine Marke in KI-generierten Antworten verstanden, erwähnt oder als Quelle verwendet wird. Bei klassischer SEO spielen unter anderem Keywords, interne Verlinkung, Backlinks, technische Optimierung und Content-Qualität eine wichtige Rolle. Bei GEO kommen weitere Fragen hinzu: Ist klar, wofür Ihre Marke steht? Wird Ihr Unternehmen auch ausserhalb der eigenen Website erwähnt? Beantworten Ihre Inhalte konkrete Nutzerfragen? Sind Informationen einfach zu extrahieren? Sind Unternehmensdaten konsistent? Kann ein KI-System Ihre Produkte, Leistungen und Zielgruppen eindeutig einordnen? Beide Disziplinen ergänzen sich. Eine technisch saubere Website mit hochwertigen Inhalten bleibt die Grundlage. Wie ChatGPT Informationen über Schweizer Unternehmen versteht ChatGPT bewertet ein Unternehmen nicht nur anhand einer einzelnen Seite. Vielmehr entsteht ein Gesamtbild aus verschiedenen öffentlich zugänglichen Signalen. Dazu können gehören: Informationen auf der eigenen Website Produkt- und Leistungsseiten Fachartikel Unternehmensprofile Rezensionen Erwähnungen in Fachmedien Vergleichsseiten Branchenportale Podcasts Interviews Community-Diskussionen Je konsistenter diese Informationen sind, desto leichter kann eine Marke eingeordnet werden. Wenn ein Unternehmen sich selbst als führenden Anbieter bezeichnet, reicht das allein nicht aus. Wenn jedoch mehrere unabhängige Quellen dieselbe Marke mit einem bestimmten Thema, Produkt oder Anwendungsfall verbinden, entsteht ein stärkeres Signal. Optimieren Sie Inhalte für echte Fragen Viele Websites arbeiten weiterhin hauptsächlich mit einzelnen Keywords. Für ChatGPT Search sollten Unternehmen stärker in vollständigen Fragen denken. Ein Schweizer Anbieter für Photovoltaik könnte beispielsweise nicht nur für: „Solaranlage Schweiz“ optimieren. Interessanter sind Fragen wie: „Lohnt sich eine Solaranlage für ein Einfamilienhaus in der Schweiz?“ „Was kostet eine Photovoltaikanlage in Zürich?“ „Welche Solaranlage eignet sich für wenig Dachfläche?“ „Welche Solaranbieter gibt es in der Schweiz?“ „Welche Fördermöglichkeiten gibt es für Solaranlagen in der Schweiz?“ Diese Suchanfragen spiegeln besser wider, wie Menschen mit KI-Assistenten kommunizieren. Geben Sie die Antwort möglichst früh Ein häufiger Fehler bei SEO-Texten ist eine zu lange Einleitung. Die eigentliche Antwort kommt erst nach mehreren Absätzen. Für ChatGPT Search ist eine direkte Struktur meist sinnvoller. Wenn eine Überschrift lautet: Was kostet SEO in der Schweiz? Dann sollte der erste Absatz direkt erklären, wovon die Kosten abhängen. Danach können zusätzliche Details, Beispiele und Ausnahmen folgen. Diese Struktur hilft nicht nur KI-Systemen. Auch menschliche Leser finden schneller die Information, die sie suchen. Erstellen Sie thematische Content-Cluster Eine einzelne Seite reicht selten aus, um ein Thema vollständig abzudecken. Unternehmen sollten wichtige Themen in mehreren miteinander verbundenen Artikeln behandeln. Eine Schweizer Digitalagentur könnte beispielsweise Inhalte zu folgenden Themen veröffentlichen: Generative Engine Optimization Wie funktioniert GEO? ChatGPT Sichtbarkeit Wie erscheint ein Unternehmen in ChatGPT? AI Visibility Wie lässt sich die Sichtbarkeit in KI-Suchmaschinen messen? E-Commerce Wie können Shopify-Shops in ChatGPT gefunden werden? Lokale Suche Wie optimiert man ein Schweizer Unternehmen für lokale KI-Suchen? Gemeinsam ergeben diese Inhalte ein viel klareres thematisches Profil als ein einzelner allgemeiner Artikel über AI SEO. Machen Sie Ihre Marke eindeutig verständlich ChatGPT sollte möglichst einfach erkennen können: Wer sind Sie? Was bieten Sie an? Für wen ist Ihr Angebot gedacht? In welcher Region arbeiten Sie? Welche Probleme lösen Sie? Was unterscheidet Sie von Alternativen? Viele Unternehmen verwenden sehr kreative Marketingformulierungen, ohne konkret zu erklären, was sie eigentlich tun. Eine Aussage wie: „Wir gestalten gemeinsam die digitale Zukunft“ klingt gut, ist aber unpräzise. Eine Formulierung wie: „Wir entwickeln B2B-SaaS-Plattformen für Schweizer Finanzunternehmen“ ist deutlich eindeutiger. Für AI Search ist Klarheit oft wichtiger als Marketing-Sprache. Lokalisieren Sie Ihre Inhalte für die Schweiz Eine deutschsprachige Website ist nicht automatisch optimal auf die Schweiz ausgerichtet. Schweizer Unternehmen sollten regionale Unterschiede berücksichtigen. Dazu gehören beispielsweise: Schweizer Franken statt Euro Schweizer Begriffe und Schreibweisen Lokale Städte und Kantone Regionale Beispiele Schweizer Gesetze oder Vorschriften, wenn sie relevant sind Schweizer Anbieter und Wettbewerber Lokale Kaufgewohnheiten Ein Nutzer aus Zürich erwartet bei bestimmten Fragen andere Antworten als ein Nutzer aus Berlin. Berücksichtigen Sie die Mehrsprachigkeit der Schweiz Die Schweiz besteht nicht nur aus einem deutschsprachigen Markt. Je nach Zielgruppe können deutsche, französische, italienische und teilweise englische Inhalte relevant sein. Unternehmen, die in mehreren Sprachregionen aktiv sind, sollten nicht einfach alle Inhalte automatisch übersetzen. Besser ist es, pro Markt zu prüfen: Welche Fragen stellen Nutzer? Welche Begriffe verwenden sie? Welche Anbieter kennen sie? Welche lokalen Unterschiede sind wichtig? Die zentrale Positionierung der Marke sollte dabei über alle Sprachversionen hinweg konsistent bleiben. Erhöhen Sie Ihre externe Markenpräsenz GEO endet nicht auf der eigenen Website. Externe Erwähnungen können entscheidend dafür sein, wie eindeutig eine Marke im Web wahrgenommen wird. Hilfreich können sein: Fachmedien Branchenportale Interviews Gastbeiträge Podcasts Events Unternehmensverzeichnisse Kundenreferenzen Vergleichsseiten Community-Diskussionen Dabei geht es nicht darum, möglichst viele beliebige Erwähnungen zu sammeln. Wichtiger sind relevante Erwähnungen im richtigen thematischen Kontext. Veröffentlichen Sie konkrete Fakten KI-Systeme können strukturierte und eindeutige Informationen leichter verarbeiten. Unternehmen sollten deshalb konkrete Angaben bereitstellen. Dazu können gehören: Leistungsumfang Standorte Zielgruppen Branchen Produktfunktionen Integrationen Preise Sprachen Liefergebiete Zertifizierungen Anwendungsfälle Je weniger ein KI-System über Ihr Angebot erraten muss, desto besser. Welche Inhalte funktionieren für ChatGPT Search besonders gut? Besonders hilfreich sind Inhalte, die konkrete Fragen beantworten. Dazu gehören ausführliche Ratgeber, Vergleichsartikel, FAQ-Seiten, Produktseiten, Leistungsseiten, Fallstudien, Glossare und lokale Landingpages. Entscheidend ist jedoch nicht allein das Format. Ein oberflächlicher 2.000-Wörter-Artikel ist nicht automatisch besser als ein präziser Text mit 800 Wörtern. Der Inhalt muss eine echte Nutzerfrage zuverlässig beantworten. Schreiben Sie für Themen statt nur für Keywords Keyword-Recherche bleibt wichtig. Für AI Search sollten Unternehmen zusätzlich komplette Themenwelten abdecken. Ein Schweizer ERP-Anbieter könnte beispielsweise nicht nur auf: „ERP Schweiz“ optimieren. Weitere relevante Fragen wären: „Welches ERP eignet sich für Schweizer KMU?“ „Welche ERP-Software ist für Produktionsunternehmen
오늘은 최근에 알게된 프로젝트에 대해서 분석해보는 글을 작성해 보려고 한다. 다만 프로젝트의 익명성을 위하여 프로젝트에 관한 내용은 일절 다루지 않고, 오로지 프로젝트의 구조와 규칙에 대해서 조사해봤다. 즉, 이번 보고서의 분석 대상은 서비스가 무엇을 하는가 가 아니라, 프로젝트를 어떤 구조로 나누고 어떤 규칙으로 개발하는가 이다. 이 구조를 무엇이라고 부를 수 있을까? 내가 참고한 이 프로젝트는 크게 두 구조가 결합되어 있다. 1. 기능 중심 레이어드 모놀리스 Feature-first Layered Monolith 2. 문서·테스트·AI를 이용한 개발 하네스 Documentation-driven AI Development Harness 첫 번째 구조는 코드를 정리한다. 기능 └── Controller └── Service └── Repository └── Database / External API 두 번째 구조는 개발 과정을 정리한다. 작업 규칙 ├── 문서 ├── AI 역할 ├── 테스트 ├── Git Hook └── CI 즉, 하나는 코드가 엉키지 않게 하는 구조 이고, 다른 하나는 개발 과정이 엉키지 않게 하는 구조 다. 질문 1. 우리가 공부하려는 것은 서비스일까, 구조일까? 프로젝트를 분석할 때 다음 두 가지를 혼동하기 쉽다. 서비스 분석 └── 어떤 기능을 제공하는가? 구조 분석 └── 기능이 늘어나도 어떻게 정리하고 관리하는가? 예를 들어 주문 기능 , 회원 기능 , 검색 기능 이 있다는 사실은 서비스 분석이다. 반면 다음은 구조 분석이다. 기능별로 패키지를 나누는가? Controller와 Service의 책임은 무엇인가? 공통 규칙은 어디에 기록하는가? AI가 코드를 수정할 수 있는가? 변경이 안전한지 어떻게 검증하는가? 누가 최종 책임을 가지는가? 해결 방법 서비스 이름과 도메인 용어를 제거하고도 남는 규칙을 본다. order member catalog 위 이름을 다른 것으로 바꿔도 구조가 유지된다면 재사용 가능한 구조다. payment reservation notification 이 문서에서는 기능 이름이 아니라 다음 요소를 중심으로 본다. 코드 경계 의존 방향 문서 체계 개발 순서 검증 방식 AI 역할 전체 구조에서 담당하는 부분 이 구분은 앞으로 분석의 기준점이다. 기능은 프로젝트마다 바뀌지만, 안전하게 기능을 추가하는 구조는 다른 프로젝트에도 재사용할 수 있다. 질문 2. 처음부터 안전한 프로젝트를 만들려면 거대한 구조를 먼저 만들어야 할까? 안전한 프로젝트를 만들고 싶으면 처음부터 다음을 모두 준비해야 할 것처럼 느껴진다. 멀티모듈 클린 아키텍처 포트와 어댑터 이벤트 시스템 공통 라이브러리 여러 AI 에이전트 복잡한 CI 하지만 분석 대상 프로젝트는 그렇게 시작하지 않았다. 해결 방법 가장 작은 실행 가능한 프로젝트에서 출발했다. backend/ ├── build.gradle ├── BackendApplication.java ├── application.properties └── BackendApplicationTests.java 그 뒤 실제 필요가 생긴 순서대로 추가했다. 최소 Spring Boot 프로젝트 ↓ Docker 실행 환경 ↓ Git·코드 컨벤션 ↓ 개발 하네스 ↓ 도메인 모델 ↓ 외부 데이터 연동 ↓ PostgreSQL 통합 테스트 ↓ API·인증·검색 왜 필요한가? 초기부터 완성형 구조를 만들면 아직 존재하지 않는 문제를 예상해 코드를 작성하게 된다. 그 결과 다음 문제가 생긴다. 구현체가 하나뿐인 인터페이스 사용하지 않는 공통 모듈 필요하지 않은 이벤트 시스템 실제 변경보다 구조 유지 비용이 더 큰 프로젝트 팀원이 이해하지 못하는 추상화 실제 적용 방법 처음에는 다음 정도면 충분하다. my-project/ ├── backend/ │ ├── build.gradle │ └── src/ │ ├── main/ │ └── test/ ├── README.md └── compose.yaml 첫 번째 기능이 생겼을 때 해당 기능 패키지를 추가한다. src/main/java/com/example/ └── order/ ├── controller/ ├── service/ ├── repository/ └── domain/ 전체 구조에서 담당하는 부분 이 단계는 프로젝트의 기술적 출발점 을 담당한다. 유의 사항 빈 계층을 미리 만들지 않는다. 실제 코드가 생길 때 패키지를 만든다. 미래 확장을 위한 인터페이스를 먼저 만들지 않는다. 단일 모듈로 해결되는 동안에는 멀티모듈로 나누지 않는다. 질문 3. 코드는 기술별로 나눠야 할까, 기능별로 나눠야 할까? 가장 단순한 레이어드 구조는 다음과 같다. controller/ ├── OrderController ├── MemberController └── CatalogController service/ ├── OrderService ├── MemberService └── CatalogService 처음에는 깔끔해 보이지만 기능이 늘어나면 하나의 기능을 이해하기 위해 여러 디렉터리를 이동해야 한다. 해결 방법 최상위는 기능으로 나누고, 기능 내부를 계층으로 나눈다. order/ ├── controller/ ├── service/ ├── repository/ ├── domain/ ├── dto/ └── exception/ member/ ├── controller/ ├── service/ ├── repository/ ├── domain/ └── dto/ 이를 기능 중심 패키지 구조 라고 볼 수 있다. 어디서 어떻게 사용되는가? 새로운 주문 요구사항을 조사한다면 order 안에서 대부분의 흐름을 찾을 수 있다. OrderController ↓ OrderService ↓ OrderRepository ↓ Order 기능의 API, 유스케이스, 데이터 접근, 도메인 규칙이 가까운 위치에 모인다. 왜 필요한가? 프로젝트의 실제 변경은 대개 기술 단위가 아니라 기능 단위로 발생한다. “Service를 변경한다” 보다는 다음과 같은 요청이 많다. “주문 취소 기능을 변경한다” “회원 탈퇴 규칙을 수정한다” 따라서 변경 이유가 같은 코드를 가까이 두는 편이 이해하기 쉽다. 실제 적용 방법 com.example.backend/ ├── order/ ├── member/ ├── catalog/ ├── notification/ └── global/ 각 기능 안에는 필요한 계층만 둔다. notification/ ├── service/ └── repository/ Controller나 Domain이 없다면 빈 디렉터리를 만들 필요도 없다. 전체 구조에서 담당하는 부분 이 구조는 기능 간 경계와 코드 탐색 범위 를 담당한다. 유의 사항 기능 패키지를 너무 잘게 나누지 않는다. 단순 클래스 종류를 기능으로 착각하지 않는다. common , util , shared 에 코드를 성급히 모으지 않는다. 두 기능에서 실제로 안정적으로 공유될 때만 공통 영역으로 이동한다. 질문 4. 각 계층은 무엇을 담당해야 안전할까? 기능별 패키지를 만들었더라도 모든 로직을 Service에 넣으면 결국 거대한 Service가 된다. 그러면 각 계층이 맡아야 하는 책임을 정해야 한다. 해결 방법 의존 방향을 한 방향으로 제한한다. Controller ↓ Service ↓ Repository ↓ Database / External API Service ↓ Domain Controller는 무엇을 하는가? Controller는 외부 요청과 애플리케이션 사이의 경계다. 담당 ├── HTTP 요청 수신 ├── 요청 값 검증 ├── DTO 변환 ├── Service 호출 └── HTTP 응답 생성 Controller가 직접 Repository를 호출하지 않는다. // 피해야 하는 형태 orderRepository.findById(id); Controller는 유스케이스를 Service에 요청한다. orderService.findOrder(id); Service는 무엇을 하는가? Service는 하나의 사용자 작업을 완성하는 흐름을 담당한다. 담당 ├── 유스케이스 순서 ├── 트랜잭션 범위 ├── 여러 Repository 협력 ├── Domain 객체 호출 └── 실패 전파 Service가 모든 비즈니스 규칙을 계산할 필요는 없다. 상태와 직접 관련된 규칙은 Domain 객체가 소유하는 편이 좋다. Repository는 무엇을 하는가? Repository는 데이터가 어디서 오는지 숨긴다. 담당 ├── 데이터베이스 조회·저장 ├── 쿼리 ├── 외부 API 접근 └── 영속성 변환 분석 대상 구조에서는 DB와 외부 API 접근 모두 Repository 계층에 포함한다. 이것은 실용적인 레이어드 구조이며, 엄격한 포트·어댑터 구조는 아니다. Domain은 무엇을 하는가? Domain은 상태와 그 상태를 지키는 규칙을 담당한다. 담당 ├── 상태 ├── 상태 변경 행위 ├── 불변식 ├── 값 검증 └── 도메인 계산 Domain은 다음을 알지 못해야 한다. HTTP Controller DTO JSON 응답 형식 Service 화면 구조 전체 구조에서 담당하는 부분 계층 규칙은 책임 혼합과 순환 의존을 방지 한다. 유의 사항 Controller에서 Repository를 직접 호출하지 않는다. Repository가 Service를 호출하지 않는다. Domain이 DTO나 Web 기술에 의존하지 않는다. JPA Entity를 API 응답으로 직접 반환하지 않는다. Service가 단순 전달만 한다면 정말 필요한 계층인지 검토한다. 질문 5. 모든 Controller 옆에 지침 문서를 두면 관리하기 쉬울까? 다음처럼 파일마다 설명서를 두고 싶을 수 있다. OrderController.java OrderController.md MemberController.java MemberController.md 하지만 코드가 바뀔 때 문서가 함께 수정되지 않으면 서로 다른 설명이 남는다. 해결 방법 문서는 클래스별이 아니라 질문과 규칙별로 중앙화 한다. docs/ ├── README.md ├── architecture.md ├── layer-boundaries.md ├── development-cycle.md ├── api-conventions.md ├── persistence.md ├── testing.md ├── security.md └── quality-gates.md 어디서 어떻게 사용되는가? docs/README.md 가 문서 지도 역할을 한다. API를 변경한다 └── api-conventions.md DB를 변경한다 └── persistence.md 구조를 변경한다 ├── architecture.md └── layer-boundaries.md 작업을 완료한다 └── quality-gates.md 왜 필요한가? 동일 규칙이 여러 문서에 복제되면 서로 다른 내용으로 변한다. 예를 들어 모든 Controller 문서에 오류 응답 규칙이 들어 있으면, 규칙을 변경할 때 모든 문서를 수정해야 한다. 대신 다음처럼 하나의 원본만 둔다. 오류 응답 규칙의 원본 └── exception-handling.md 실제 적용 방법 문서를 세 단계로 구성할 수 있다. 루트 AGENTS.md └── 프로젝트 전체 작업 지도 backend/AGENTS.md └── 백엔드 작업 규칙 backend/docs/README.md └── 상황별 상세 문서 라우터 전체 구조에서 담당하는 부분 이 문서 구조는 사람과 AI가 어떤 규칙을 읽어야 하는지 안내하는 내비게이션 이다. 유의 사항 같은 규칙을 여러 문서에 복사하지 않는다. 문서의 원본 위치를 명확히 한다. 코드만 보면 알 수 있는 내용을 문서로 반복하지 않는다. 클래스의 실제 동작은 테스트로 설명한다. 복잡한 업무 흐름만 별도 문서로 승격한다. 질문 6. 개발 하네스란 무엇이고 왜 필요한가? 문서에 규칙을 적어도 아무도 읽지 않으면 규칙은 지켜지지 않는다. 그렇다면 문서를 실제 개발 과정과 어떻게 연결할 수 있을까? 해결 방법 문서, AI 역할, 자동 검사를 하나의 흐름으로 연결한다. 개발 하네스 ├── AGENTS.md ├── 작업별 문서 ├── AI 역할 정의 ├── 검증 스크립트 ├── Git Hook ├── 테스트 └── CI 하네스는 특정 프레임워크가 아니다. 개발자가 안전한 순서에서 벗어나지 않도록 둘러싼 작업 환경 전체다. 어디서 어떻게 사용되는가? 작업 시작 └── AGENTS.md가 읽을 문서를 안내 코드 작성 전 └── 개발 절차와 계층 경계 확인 커밋 전 └── Git Hook으로 규칙 검사 PR 생성 후 └── CI에서 테스트와 문서 구조 검사 완료 전 └── Quality Gate 확인 왜 필요한가? 문서만 있으면 권고 사항에 머문다. 자동 검사를 연결하면 일부 규칙이 실행 가능한 계약이 된다. “필수 문서가 있어야 한다” → 스크립트로 파일 존재 검사 “에이전트는 읽기 전용이어야 한다” → 설정 파일 검사 “커밋 제목은 일정한 형식이어야 한다” → commit-msg hook 검사 “백엔드는 DB 통합 테스트를 통과해야 한다” → CI에서 PostgreSQL 실행 후 Gradle check 전체 구조에서 담당하는 부분 하네스는 코드 구조 자체가 아니라 코드를 변경하는 과정을 보호 한다. 유의 사항 모든 규칙을 문서 검사로 해결할 수는 없다. 예를 들어 다음 규칙은 별도의 구조 테스트가 없다면 문서와 리뷰에 의존한다. Controller가 Repository를 직접 호출하지 않는다. 이 규칙이 자주 깨진다면 ArchUnit 같은 자동 검사를 추가할 수 있다. 한 번도 깨지지 않았다면 미리 추가할 필요는 없다. 질문 7. 여러 AI가 동시에 코드를 작성하면 더 빠르지 않을까? AI가 여러 대라면 기능을 나눠 동시에 구현하는 것이 빠르게 보인다. 하지만 같은 코드베이스를 여러 AI가 수정하면 다음 문제가 생길 수 있다. 동일 파일 충돌 서로 다른 설계 도입 중복 구현 최종 책임 불명확 한 AI의 전제를 다른 AI가 모름 해결 방법 Single Writer, Multiple Readers 구조를 사용한다. 메인 작업자 ├── 요구사항 판단 ├── 코드 작성 ├── 결과 통합 └── 최종 검증 책임 읽기 전용 보조 AI ├── Explorer ├── Architect └── Reviewer 메인 작업자는 사람일 수도 있고 AI일 수도 있다. Explorer는 무엇을 하는가? Controller ↓ Service ↓ Repository ↓ Domain 이 흐름을 추적해 변경 영향 범위를 조사한다. 직접 수정하지 않고 다음을 보고한다. 관련 파일 호출 흐름 데이터 흐름 기존 테스트 미확인 사항 Architect는 무엇을 하는가? 다음을 검토한다. 기능 경계 계층 의존 API 계약 트랜잭션 범위 데이터 일관성 마이그레이션 영향 Architect도 코드를 수정하지 않는다. Reviewer는 무엇을 하는가? 구현이 끝난 뒤 독립적인 관점에서 다음을 본다. 정확성 회귀 인증·인가 입력 검증 동시성 성능 테스트 누락 비밀 노출 왜 필요한가? 구현한 주체는 자신의 전제를 당연하다고 생각하기 쉽다. 읽기 전용 Reviewer는 구현 과정에 참여하지 않았기 때문에 다른 관점에서 볼 수 있다. 전체 구조에서 담당하는 부분 AI 역할 분리는 병렬 구현 보다 독립적인 조사와 검증 을 담당한다. 유의 사항 모든 변경에 여러 AI를 사용하지 않는다. 단순 변경은 메인 작업자 하나로 충분하다. 구조·보안·DB 변경처럼 위험한 작업에만 보조 역할을 추가한다. AI 리뷰를 테스트 통과로 간주하지 않는다. 최종 책임은 항상 메인 작업자에게 둔다. 질문 8. 기능 하나를 실제로 어떤 순서로 개발해야 할까? 바로 코드를 작성하면 빠르지만, 중간에 요구사항이나 영향 범위를 잘못 이해했다는 사실을 발견할 수 있다. 해결 방법 작업을 다음 흐름으로 고정한다. 계약 → 탐색 → 설계 → Red → Green → Refactor → Verify → Review 1단계: 작업 계약 코드를 작성하기 전에 네 가지를 적는다. Goal 사용자가 얻을 결과는 무엇인가? Context 관련 코드와 테스트는 어디에 있는가? Constraints 기술·범위·안전 제한은 무엇인가? Done 무엇을 실행해 완료를 증명할 것인가? 2단계: 탐색 Controller ↓ Service ↓ Repository ↓ Domain 운영 코드만 보지 않고 가까운 테스트를 함께 읽는다. 또한 다음을 찾는다. 공개 API 계약 트랜잭션 경계 외부 시스템 실패 경로 기존 사용자 영향 3단계: 설계 게이트 변경할 객체마다 한 문장으로 책임을 설명한다. OrderController → 주문 취소 HTTP 요청을 검증하고 Service에 전달한다. OrderService → 주문 취소 유스케이스와 트랜잭션을 관리한다. Order → 현재 상태에서 취소 가능한지 판단한다. 설명이 어렵다면 책임이 섞였을 가능성이 있다. 4단계: Red → Green → Refactor Red └── 필요한 행동을 보여주는 실패 테스트 Green └── 테스트를 통과하는 최소 구현 Refactor └── 행동을 유지하면서 이름·책임·중복 개선 5단계: Verify → Review 가장 가까운 테스트 ↓ 기능 전체 테스트 ↓ DB 통합 테스트 ↓ 전체 검사 ↓ 최종 diff 리뷰 전체 구조에서 담당하는 부분 이 순서는 잘못된 요구사항을 큰 코드로 확장하기 전에 멈추게 하는 역할 을 한다. 유의 사항 컴파일 오류를 Red 단계의 성공으로 보지 않는다. 테스트만 통과하도록 값을 하드코딩하지 않는다. 하나의 작업에서 여러 행동을 한꺼번에 변경하지 않는다. 실행하지 못한 검사는 통과했다고 기록하지 않는다. 질문 9. 테스트는 어느 계층에 얼마나 작성해야 할까? 모든 클래스를 단위 테스트하면 테스트 수는 많아지지만 실제 서비스 동작을 보장하지 못할 수 있다. 반대로 통합 테스트만 작성하면 느리고 실패 원인을 찾기 어렵다. 해결 방법 계층별 위험에 맞는 테스트를 둔다. Domain └── 빠른 단위 테스트 행위, 불변식, 경계값 Service └── 유스케이스 테스트 흐름, 협력, 실패 전파 Controller └── HTTP 계약 테스트 검증, 상태 코드, 오류 응답 Repository └── DB 통합 테스트 매핑, 쿼리, 제약조건 External API └── 계약·통합 테스트 요청, 응답, timeout, 변환 왜 필요한가? 각 계층에서 발생하는 문제의 성격이 다르기 때문이다. Domain 오류 → 잘못된 비즈니스 판단 Controller 오류 → 잘못된 HTTP 계약 Repository 오류 → 실제 DB와 다른 동작 외부 API 오류 → timeout이나 응답 형식 변화 실제 적용 방법 테스트 디렉터리가 운영 코드 구조를 따라가도록 한다. src/main/java/com/example/order/ ├── controller/ ├── service/ ├── repository/ └── domain/ src/test/java/com/example/order/ ├── controller/ ├── service/ ├── repository/ └── domain/ 전체 구조에서 담당하는 부분 테스트는 문서보다 더 정확하게 현재 코드가 실제로 보장하는 동작 을 설명한다. 유의 사항 구현 세부사항보다 외부 행동을 검증한다. 테스트 하나는 행동 하나를 검증한다. 실제 DB 경계가 중요하면 mock으로 대체하지 않는다. 버그 수정은 실제 증상을 재현하는 테스트에서 시작한다. flaky 테스트는 재실행 성공만으로 통과시키지 않는다. 질문 10. 언제 별도의 업무 문서를 만들어야 할까? 모든 기능에 상세 설계 문서를 만들면 관리 비용이 커진다. 반대로 아무 문서도 없으면 복잡한 업무 흐름을 코드만 보고 이해해야 한다. 해결 방법 코드만으로 파악하기 어려운 흐름에만 별도 문서를 둔다. 별도 문서가 유용한 경우는 다음과 같다. 여러 단계로 이어지는 데이터 파이프라인 중단과 재시작이 있는 작업 외부 데이터 동기화 데이터 수명주기 마이그레이션 순서 장애 복구 절차 운영자가 직접 실행하는 작업 예시 docs/ ├── data-pipeline-execution.md ├── source-data-lifecycle.md └── address-reference-import.md 이 문서들은 클래스 설명서가 아니다. 어떤 순서로 실행되는가? 중간에 실패하면 어떻게 되는가? 재실행해
Z Yuan et al, AET5: A transcriptome-guided molecular generation framework with contrastive selfsupervised learning, PLOS Computational Biology Introduction 초기 de novo molecular generation 연구 는 방대한 chemical space를 효율적으로 탐색하기 위해 시작되었다. 기존의 high-throughput screening은 비용이 높고 탐색 가능한 화학 공간이 제한적이기 때문에, VAE, GAN, RNN, graph-based model과 같은 딥러닝 기반 생성 모델이 등장하였다. 이후 Transformer와 molecular language model 이 도입되면서 MolT5, MolGPT, Chemformer와 같이 분자의 SMILES 표현이나 구조적 패턴을 학습하여 보다 효과적으로 새로운 분자를 생성하는 방향으로 발전하였다. 그러나 이러한 초기 생성 모델의 주된 목표는 화학적으로 유효한 분자를 생성 하거나 특정 physicochemical property를 만족 시키는 것이었으며, 생성된 분자가 실제 세포에서 어떤 생물학적 반응을 유도하는지는 직접적으로 고려하지 않는 경우가 많았다. 이러한 한계를 보완하기 위해 최근에는 단순한 화학적 특성을 넘어 생물학적 정보를 조건으로 사용하는 molecular generation이 연구되기 시작했다. 특히 gene expression profile 은 세포의 전체적인 상태를 나타내며, 질병 상태와 약물 처리 이후의 세포 반응을 직접적으로 연결할 수 있다는 장점이 있다. 따라서 disease-associated expression state를 정상 상태로 되돌릴 수 있는 분자를 생성한다는 관점에서 transcriptomic information은 유용한 conditioning signal 이 될 수 있다. 하지만 기존 연구에는 두 가지 중요한 문제가 남아 있다. 첫째, 많은 방법들이 여전히 chemical syntax, molecular property , 또는 기존 약물의 prioritization과 repurposing 에 집중하고 있으며, 생성 과정에서 gene regulatory response와 같은 downstream biological effect를 명시적인 생성 제약으로 충분히 활용하지 못하고 있다 . 기존의 biological modeling 역시 protein target이나 protein–ligand interaction과 같은 비교적 직접적인 분자 수준의 관계에 집중 해 왔기 때문에, 특정 분자가 세포 전체의 regulatory state를 어떻게 변화시키는지를 고려한 생성은 상대적으로 부족 하다. 즉, “어떤 target에 결합하는가”를 넘어 “세포 상태를 원하는 방향으로 변화시키는가”라는 biological-effect-oriented generation이 충분히 다뤄지지 않았다는 것이다. 둘째, 기존 expression-conditioned generation에서 gene expression을 표현하는 방법 자체에도 한계가 있다. 많은 연구가 raw expression vector를 직접 molecular representation과 concatenate하거나, linear projection을 적용하거나, VAE를 통해 저차원 latent representation으로 변환한다. 그러나 transcriptomic data는 본질적으로 high-dimensional하고 noisy하며 gene–gene dependency가 복잡 하기 때문에 단순한 linear transformation만으로는 중요한 biological pattern을 충분히 포착하기 어렵다. 또한 VAE는 smooth하고 continuous한 latent space를 만드는 데 최적화되어 있기 때문에, expression encoder로 사용할 경우 disease-specific 또는 perturbation-specific signal이 지나치게 smoothing되거나 distributional regularization에 의해 약화 될 가능성이 있다. 결과적으로 기존 embedding 방식은 gene expression이 포함하고 있는 세포 상태의 biological semantics를 충분히 보존하지 못하고, molecular generation의 biological controllability를 제한 할 수 있다. 이 문제는 질병에 따라 더욱 복잡해진다. 예를 들어 바이러스 감염은 데이터가 적고 noise가 크며 빠르게 변화하는 cellular background를 갖는 반면, cancer는 매우 높은 cellular heterogeneity와 강한 gene–gene correlation을 가진다. 따라서 서로 다른 disease context에 동일한 단순 conditioning mechanism을 적용하면 중요한 질병 특이적 biological signal을 안정적으로 추출하기 어렵다 . 결국 expression-conditioned molecular generation의 핵심 문제는 단순히 gene expression을 generator에 입력하는 것이 아니라, noise를 억제하면서도 disease와 cellular context에 관련된 정보를 보존 하고, 이를 molecular representation과 효과적으로 연결할 수 있는 transcriptomic representation을 학습 하는 것이라고 볼 수 있다. Method Transcriptome conditional encoder 다양한 교란 하에서도 일관성을 유지하는 강건한 잠재 표현을 추출하기 위해 sef-supervised contrastive learning을 통해 사전학습된다. 유전자 간의 맥락적 의존성을 명시적으로 모델링하기 위해 각 유전자를 하나의 토큰으로 간주하고, 각 샘플 내의 모든 유전자에 대해 특징별 어텐션을 적용한다. 유전자들은 의존 관계를 가지지만 본질적인 순차적 순서가 존재하지 않는다. transformer는 고차원 embedding을 입력으로 받기 때문에 scalar를 FNN으로 projection한다. 각 유전자의 두 개의 증강 뷰는 네 가지 증강 연산자, feature dropout $D$, random scaling $S$, adaptive Gaussian noise $G_{adap}$, structured Gaussian noise $G_{struct}$의 확률적 조합을 사용하여 생성된다. $$ \tilde{x}^{(i)} = A_i(x) = D_i \circ S_i \circ G_{adap,i} \circ G_{struct,i}(x) $$ 각 연산자는 다양한 교란을 생성하도록 무작위로 파라미터화되며, 연산자의 조합 순서는 특정한 모델링 의미를 갖지 않는다. feature dropout : 유전자 특징을 무작위로 마스킹 random scaling : 유전자 수준에서 발현값을 교란 adaptive Gaussian noise : 학습 세트에서 추정된 분산을 사용하여 특징별 노이즈 주입 structured Gaussian noise : 다변량 가우시안 분포 $N(0,\sum)$에서 샘플링 각 증강 뷰는 이후 유전자 수준 transformer $f_{\theta}(\cdot)$에 의해 인코딩되어 문맥화된 유전자 표현을 생성하고, projection head에 의해 샘플 수준 잠재 벡터로 압축 $$ h_1 = f_{\theta}(\tilde{x}^{(1)}), h_2 = f_{\theta}(\tilde{x}^{(2)}) $$ $$ c_1 = g(h_1), c_2 = g(h_2) $$ 모델은 InfoNCE loss를 사용하여 샘플 수준에서 최적화된다. 동일한 발현 프로파일의 두 증강 뷰는 positive pair, 동일한 배치 내 다른 샘플의 표현은 negative pair로 사용된다. $$ \mathcal{L} {InfoNCE} = -\frac{1}{B}\sum^B {i=1}log\frac{exp(\frac{sim(c^i_1,c^i_2)}{\tau})}{\sum^B_{j=1}exp(\frac{sim(c^i_1,c^i_2)}{\tau})} $$ 사전학습 이후 전사체 조건 인코더는 동결되어, 입력 약물 유도 발현 프로파일 $x$를 잠재 조건 벡터 $c = g(f_{\theta}(x))$로 매핑하는 데 사용된다. Molecule generation module Transcriptome conditional encoder가 생성한 $c$를 MolT5의 hidden state에 호환되도록 하기 위해, feed-forward condition-mapping network를 통해 고정 길이의 조건 토큰 시퀀스로 변환된다. $$ C = Reshape(FFN_{cond}(c)) \in \mathbb{R}^{K_C \times d_T} $$ $K_C$ : 조건 토큰의 수 $d_T$ : MolT5의 hidden state 생성되 조건 토큰 $C$는 MolT5 인코더의 입력으로 사용된다. 인코더에서는 self-attention을 통해 각 condition token 사이의 관계를 학습하고, 최종적으로 transcriptomic condition을 표현하는 contextualized representation $H_{enc}$를 생성한다. 이 과정을 통해 원래의 gene expression 기반 조건 정보가 MolT5가 활용할 수 있는 latent representation으로 변환된다. $$ H^l_{enc} = FFN^l_{enc}(SelfAttn(H^{l-1} {enc})) \ H^l {enc} = Adapter^l_{enc}(H^l_{enc}) $$ 반면 decoder는 이전까지 생성된 SMILES token을 입력으로 받아 다음 token을 순차적으로 예측한다. 먼저 masked self-attention을 통해 기존에 생성된 SMIELS sequence의 문맥을 반영하고, 이후 cross-attention을 통해 encoder가 생성한 transcriptomic condition representation $H_{enc}$를 참조한다. 따라서 다음 SMILES token을 결정할 때 단순히 앞선 molecular sequence만 고려하는 것이 아니라, 입력으로 주어진 biological condition도 함께 반영하게 된다. $$ H^l_{dec} = SelfAttn^l_{dec}(H^{l-1} {dec}) \ E^l = CrossAttn^l {dec}(H^l_{dec},H_{enc}) \ H^l_{dec} = Adapter^l_{dec}(FFN^l_{dec}(E^l)) $$ 이 과정에서 MolT5 전체를 처음부터 학습하지 않고, pretrained MolT5가 이미 가지고 있는 molecular language knowledge를 최대한 유지하기 위해 parameter-efficient fine-tuning 전략을 사용한다. 대부분의 pretrained parameter는 freeze하고, Transformer block 내부에 lightweight adapter를 추가하여 해당 adapter와 condition-mapping network, 그리고 일부 상위 layer만 학습한다. 이를 통해 제한된 transcriptomic-molecule pair 데이터에서도 전체 모델을 fine-tuning하는 것보다 적은 수의 parameter만 업데이트하면서 새로운 biological condition에 적응할 수 있다. 학습 단계에서는 teacher forcing을 사용한다. 즉, $n$번째 SMILES token을 예측할 때 모델이 이전에 생성한 token을 다시 입력하는 것이 아니라 실제 정답 sequence인 ($s_1,\ldots,s_{n-1}$)를 decoder의 입력으로 제공한다. 모델은 주어진 transcriptomic condition $C$와 이전 SMILES token들을 바탕으로 다음 token의 확률을 최대화하도록 학습된다. $$ -\sum_{n=1}^{N} \log p_{\psi} \left( s_n \mid s_1,\ldots,s_{n-1},C \right) $$ 추론 과정에서는 분자 다양성을 향상시키기 위해 stochastic decoding을 사용하여 전사체 조건하에서 후보 SMILES 시퀀스를 자기회귀적으로 생성한다. 결국 molecular generation module의 핵심은 transcriptome-derived embedding을 MolT5의 condition token으로 변환한 뒤, 이를 encoder에 입력하고 decoder가 cross-attention을 통해 해당 biological condition을 지속적으로 참조하면서 SMILES를 autoregressive하게 생성하는 것 Results 저자들은 실제 질병 transcriptome에서도 AET5가 작동하는지 살펴보았다. SARS-CoV-2 infection : 데이터가 제한적이고 noisy하며, 서로 다른 source에서 수집되어 heterogeneous한 transcriptome 환경 Prostate cancer(PC) : 데이터는 비교적 풍부하지만 disease mechanism이 복잡한 환경 이 실험의 목적은 크게 3개이다. noisy하고 heterogeneous한 transcriptome에서도 AET5가 안정적으로 작동하는지 모델이 학습한 disease-conditional signal이 실제 disease-related gene/target과 연결되는지 서로 다른 질환에서도 하나의 expression-conditioned generation framework가 유효한 후보 분자를 생성할 수 있는지 SARS-CoV-2 서로 다른 출처의 transcriptome을 사용하였다. 한쪽은 collective sample, 다른 쪽은 individual-level sample이었으며 두 source 사이에는 상당한 expression pattern 차이가 있었다. 저자들은 이를 그대로 하나의 조건으로 쓰기보다 mixed-sample strategy를 사용해 여러 개의 potential disease expression profile을 구성하고, 각각을 조건으로 AET5가 candidate molecule을 생성하도록 하였다. 생성된 molecule은 다음 순서로 필터링 되었다. AET5-generated molecules ↓ RDKit validity check ↓ Canonical SMILES 기반 duplicate 제거 ↓ SA score < 4인 molecule만 유지 ↓ DeepCE 기반 disease-reversal 평가 DeepCE를 통해 각 generated molecule이 유도할 것으로 예측되는 transcriptomic perturbation을 계산하고, 이를 실제 SARS-CoV-2 disease expression signature와 비교하였다. 핵심 아이디어는 다음과 같다 Disease expression Gene A ↑ Gene B ↓ Gene C ↑ Drug-induced expression Gene A ↓ Gene B ↑ Gene C ↓ 이 처럼 두 profile이 반대 방향일수록 negative correlation이 강해진다. 따라서 저자들은 disease-specific expression과 가장 강한 negative correlation을 보이는 molecule을 우선 후보로 선택했다. 선정된 후보에 대해 SwissADME, QED, BOILED-Egg 등을 사용해 drug-likeness와 pharmacokinetic property를 평가했다. 대부분의 SARS-CoV-2-conditioned molecule은: SA score < 4 QED > 0.5 BOILED-Egg의 absorbable region 또는 그 주변 에 위치했다. 또한 일부 molecule은 known compound와 TPSA–WLOGP 공간에서는 가까우면서도 구조적 유사도는 낮아, 기존 compound를 단순히 복제하지 않고 유사한 pharmacokinetic property를 가진 새로운 구조를 생성할 수 있음을 보여주었다. Prostate cancer 이전과 달리 여기서는 AET5가 molecule을 생성할 때 실제 PC-related gene signal을 참고하고 있는지를 확인하려 한다. 저자들은 molecular generator의 attention score를 이용해 각 gene locus가 token-level molecular decision에 얼마나 기여했는지 계산했다. 그 다음 attention score가 높은 gene들을 Open Targets와 비교했다. 그 결과 978개 loci 중 25개가 confidence score > 0.5인 PC-related target과 연결되었다. 이는 AET5가 transcriptome condition을 단순한 numerical control signal로 사용하는 것이 아니라, disease-relevant biological signal을 어느 정도 포착하고 있을 가능성을 보여주는 결과로 해석된다. Attention ranking 상위 50개 gene 중에서 다음 조건을 만족하는 target을 선정했다. complete protein structure가 존재 known binding pocket이 존재 reference molecule이 존재 그 결과: CHEK2 — PDB ID: 2YCF TUBB6 — PDB ID: 6AB2 가 PC-related candidate target으로 선택되었다 동시에 PC-conditioned generated molecule에 대해서도 ADME, SA, QED를 평가했다. 대부분의 molecule은 낮은 SA score 범위에 있었고, QED는 약 0.5를 중심으로 비교적 넓게 분포했다. 마지막으로 generated molecule의 target-binding potential을 평가했다. 사용한 target은 총 4개였다. Disease Target PDB ID SARS-CoV-2 Nsp3 7LMD SARS-CoV-2 RdRp 9I1S Prostate cancer CHEK2 2YCF Prostate cancer TUBB6 6AB2 SARS-CoV-2의 Nsp3와 RdRp는 각각 viral polyprotein processing/immune evasion과 viral RNA replication에 중요한 protein이다. Molecular Docking Generated molecule이 target protein의 binding pocket에 실제로 들어갈 수 있는지를 AutoDock Vina를 이용해 평가했다. 특히 SARS-CoV-2의 Nsp3 target인 7LMD에서 generated molecule은 control molecule과 유사한 binding pocket을 차지하면서도 구조적으로는 분명한 차이를 보였다. 또한 docking score 기준으로 generated molecule이 control보다 favorable한 binding profile을 보였다. Molecular dynamics simulation Docking은 정적인 binding pose만 보여주기 때문에, 저자들은 추가로 molecular dynamics simulation을 수행했다. 주요 평가 지표는: RMSD hydrogen bond number radius of gyration 이다. 7LMD에 대해 generated ligand–protein complex는 simulation 동안 비교적 안정적인 conformational behavior를 보였다. 저자들은 두 case study를 종합해 AET5가: 서로 다른 disease context에서 적용 가능하고 disease-conditioned biological signal을 반영할 가능성이 있으며 generated molecule이 favorable한 predicted pharmacokinetic property와 target-binding potential을 가질 수 있다고 주장한다 Limitations 실험적 검증 부족 현재 검증은 molecular similarity, ADME prediction, dockin
들어가기에 앞서 정보 엔트로피(information entropy) step1. 정보량 어떤 사건이 자주 일어나면 별로 놀랍지 않고, 거의 안 일어나는 사건이 발생하면 놀라움 정보이론에서는 이 “놀라움의 정도”를 정보량이라고 봄 어떤 사건의 확률이 0.5라면 정보량은 비교적 작고, 확률이 0.01이라면 정보량은 훨씬 큼 그러면 아래와 같이 step2. 왜 -(log P(x))를 사용할까? 확룰이 작을수록 정보량이 커져야함 100% 일어나는 사건은 새로운 정보가 없음을 의미 하지만 드문 사건일수록 정보량이 커짐 step3. 왜 로그를 쓰는가? 로그 성질때문에 이렇게 진행이 됨 step4. 그러면 엔트로피는 무엇인가? -> 정보량의 평균값 각 사건마다 정보량이 다르기 때문에 전체 시스템이 평균적으로 얼마나 많은 정보를 가지는지를 계산함 발생 확률 × 그 사건의 정보량 step5. 주사위로 보면 해당 부분에서 머신러닝을 진행할때 softmax가 확률을 출력함 모델이 얼마나 확신하고 있는지 판단하는 데 사용할 수 있음 bit를 사용한 것은 log_{2}를 사용했을 떄의 정보량 단위임 크로스 엔트로피(cross entropy) 실제 분포 (P)를 기준으로 봤을 때, 모델이 예측한 분포 (Q)가 얼마나 잘못되었는지를 나타내는 값 -> 예측과 달라서 생기는 깜놀도(즉 정보량)을 의미함 핵심은 정답이 실제로 발생했는데, 모델이 그 정답에 낮은 확률을 줬다면 큰 손실을 준다는 것 정답이 0 또는 1인 이진 분류에서는 다음과 같이 씀 여기서 보이듯이 정답이 높은 확률을 부여하면 -> cross entropy가 작음 정답에 낮은 확률을 부여하면 -> cross entropy 큼 Entropy와 Cross Entropy의 차이 -> 실제 분포 (P) 자체가 얼마나 불확실한가 = entropy -> 실제는 (P)인데 모델이 (Q)라고 생각했을 때 필요한 평균 정보량 = Cross Entropy KL Divergence는? KL Divergence는 두 확률분포 (P)와 (Q)가 얼마나 다른지를 정보량 관점에서 나타낸 값 즉 해당 것은 모델 떄문에 추가로 발생한 차이임
이번 주차에서는 1주차에 설계했던 ERD를 MySQL 테이블과 더미 데이터로 구현하고, SELECT , WHERE , JOIN , ORDER BY , LIMIT 등을 사용해 화면에 필요한 데이터를 직접 조회해보았다. 그중 가장 궁금했던 부분은 JOIN 이었다. 미션 3에서 특정 책의 태그 목록을 조회하기 위해 book , book_tag , tag 테이블을 JOIN했는데, 책은 하나인데 같은 책 제목이 여러 줄 나타났다. 처음에는 JOIN을 잘못해서 데이터가 중복된 건가? 라고 생각했다. 하지만 ERD의 관계를 다시 확인해보니, 이 결과는 오류가 아니라 1:N 관계가 JOIN 결과에 그대로 펼쳐진 것 이었다. 그래서 이번 글에서는 단순히 JOIN 문법을 정리하기보다, JOIN하면 왜 행의 개수가 늘어날 수 있는지 1:N, N:M 관계가 결과 행 수에 어떤 영향을 주는지 정상적인 반복과 잘못된 중복은 어떻게 다른지 DISTINCT 로 중복을 제거하면 항상 해결되는지 단순한 존재 여부를 확인할 때는 왜 EXISTS 를 사용할 수 있는지 를 중심으로 정리해보려고 한다. 1. JOIN은 단순히 테이블을 옆으로 붙이는 걸까? JOIN은 서로 다른 테이블에 나누어 저장된 데이터를 관계를 기준으로 하나의 결과로 조회할 때 사용한다. 이번 실습의 도서 상세 화면에서는 다음과 같은 정보가 필요했다. 책 제목 태그 이름 현재 사용자의 좋아요 여부 하지만 이 값들은 하나의 테이블에 모두 들어 있지 않았다. book → 책 정보 tag → 태그 정보 book_tag → 책과 태그의 관계 book_like → 사용자와 책의 좋아요 관계 특히 책과 태그는 다음과 같이 연결되어 있다. book ↓ book_tag ↓ tag book_tag 는 책과 태그 사이의 관계를 저장하는 중간 테이블이다. 예를 들어 book_id = 1 인 책에 tag_id = 1 , tag_id = 2 가 연결되어 있다면 book_tag 에는 다음과 같은 데이터가 존재할 수 있다. book_id | tag_id --------|------- 1 | 1 1 | 2 즉 책 한 권에 여러 태그가 연결될 수 있다. 이 관계가 JOIN 결과의 행 수를 결정하는 중요한 요소가 된다. 2. 책은 하나인데 왜 JOIN 결과는 두 줄일까? 미션 3에서 태그 정보를 조회하기 위해 다음과 같은 SQL을 작성했다. SELECT b.title, t.name AS tag_name FROM book b JOIN book_tag bt ON b.book_id = bt.book_id JOIN tag t ON bt.tag_id = t.tag_id WHERE b.book_id = 1; 실행 결과는 다음과 같이 나타났다. 달빛 도서관 | 소설 달빛 도서관 | 추천 달빛 도서관 이라는 책은 한 권인데 결과에서는 두 번 등장한다. 하지만 실제 관계를 보면 이유는 단순하다. 달빛 도서관 ├─ 소설 └─ 추천 책 자체는 하나지만 책과 태그 사이의 관계가 두 개 존재한다. JOIN은 이 두 관계를 각각 하나의 행으로 표현한다. 따라서 책 1개 + 연결된 태그 2개 = JOIN 결과 2행 이 된다. 즉 JOIN 결과에서 기준 테이블의 데이터가 반복되는 것은 항상 중복 오류를 의미하지 않는다. 하나의 데이터가 여러 데이터와 관계를 맺고 있다면 그 관계의 수만큼 기준 데이터가 반복될 수 있다. 3. 카디널리티에 따라 JOIN 결과는 어떻게 달라질까? ERD에서 자주 보는 1:1 , 1:N , N:M 은 단순히 다이어그램에 표시하는 관계가 아니다. 이 관계는 실제 JOIN 결과의 형태에도 영향을 준다. 1:1 관계 한 행이 상대 테이블의 한 행과만 연결된다. A 1 : 1 B A의 한 행에 B의 한 행만 연결된다면 JOIN 이후에도 일반적으로 한 관계가 한 행으로 표현된다. 1:N 관계 한 행이 상대 테이블의 여러 행과 연결된다. book 1 : N book_tag 예를 들어 책 한 권에 태그 연결 정보가 세 개 있다면 JOIN 결과에서는 같은 책 정보가 세 번 나타날 수 있다. 책 A | 태그 1 책 A | 태그 2 책 A | 태그 3 N:M 관계 양쪽 데이터가 모두 여러 개의 상대 데이터와 연결될 수 있다. 관계형 데이터베이스에서는 보통 중간 테이블을 이용해 두 개의 1:N 관계로 풀어서 표현한다. 이번 실습의 책과 태그도 사실상 다음 구조다. book 1 : N book_tag tag 1 : N book_tag 이를 전체적으로 보면 book N : M tag 관계가 된다. 이처럼 N:M 관계에서는 하나의 데이터에 여러 관계가 연결되기 때문에 JOIN 결과의 행 수가 더 쉽게 늘어날 수 있다. 결국 JOIN 결과의 행 수를 이해하려면 단순히 테이블에 몇 행이 있는지만 볼 것이 아니라, 각 행이 상대 테이블에서 몇 개의 행과 매칭되는지 를 함께 봐야 한다. 4. 같은 값이 반복되면 무조건 중복일까? JOIN 결과에서 같은 값이 여러 번 보이면 가장 먼저 중복 이라는 생각이 들기 쉽다. 하지만 다음 두 결과를 비교해보면 차이를 알 수 있다. 달빛 도서관 | 소설 달빛 도서관 | 추천 책 제목은 반복되지만 태그가 다르다. 각 행은 서로 다른 관계를 표현하기 때문에 두 행 모두 의미가 있다. 이것은 정상적인 반복 이다. 반대로 JOIN의 ON 조건을 잘못 작성하면 실제 관계와 맞지 않는 데이터까지 연결될 수 있다. JOIN에서 중요한 것은 다음과 같이 ERD의 PK·FK 관계에 맞는 조건을 사용하는 것이다. JOIN book_tag bt ON b.book_id = bt.book_id 그리고 다시 tag 와 연결할 때도 실제 FK 관계를 따른다. JOIN tag t ON bt.tag_id = t.tag_id 만약 이러한 관계를 무시하고 잘못된 조건으로 JOIN하면 의도하지 않은 행 조합이 생성되고, 결과 행 수가 예상보다 크게 증가할 수 있다. 따라서 JOIN 결과가 예상보다 많다면 바로 데이터를 지우거나 중복 제거부터 하기보다 다음 순서로 확인하는 것이 좋다. ERD 관계 확인 ↓ PK / FK 확인 ↓ ON 조건 확인 ↓ 각 결과 행이 어떤 관계를 표현하는지 확인 5. 중복처럼 보인다고 DISTINCT부터 쓰면 될까? 여기부터는 이번 실습에서 더 궁금해져 추가로 정리한 내용이다. SQL에는 중복 행을 제거할 수 있는 DISTINCT 가 있다. 예를 들어 다음처럼 작성할 수 있다. SELECT DISTINCT b.title FROM book b JOIN book_tag bt ON b.book_id = bt.book_id JOIN tag t ON bt.tag_id = t.tag_id WHERE b.book_id = 1; 이렇게 하면 결과는 책 제목 하나만 남는다. 달빛 도서관 겉으로 보면 깔끔해 보인다. 하지만 원래 알고 싶었던 것이 책의 태그 목록이라면 문제가 생긴다. 기존 결과는 달빛 도서관 | 소설 달빛 도서관 | 추천 처럼 각각의 태그 관계를 표현하고 있었다. 그런데 단순히 중복처럼 보인다는 이유로 필요한 컬럼을 빼거나 DISTINCT 를 사용해 결과를 줄여버리면, 실제로 필요한 관계 정보까지 사라질 수 있다. 따라서 DISTINCT 는 중복이 보이니까 일단 제거하는 도구 로 사용하기보다, 최종 결과에서 정말 동일한 행을 하나만 남기는 것이 요구사항에 맞는가? 를 먼저 판단한 뒤 사용하는 것이 중요하다. 즉 JOIN 결과가 많다고 해서 항상 DISTINCT 가 해결책인 것은 아니다. 6. 좋아요 여부를 JOIN하지 않고 EXISTS로 확인한 이유 이번 미션 3에서는 태그뿐만 아니라 현재 사용자가 해당 책에 좋아요를 눌렀는지도 함께 조회했다. 실제 쿼리는 다음과 같이 작성했다. SELECT b.title, t.name AS tag_name, EXISTS ( SELECT 1 FROM book_like bl WHERE bl.book_id = b.book_id AND bl.user_id = 1 ) AS is_liked FROM book b JOIN book_tag bt ON b.book_id = bt.book_id JOIN tag t ON bt.tag_id = t.tag_id WHERE b.book_id = 1; 여기서 태그 정보는 JOIN을 사용했지만 좋아요 여부는 EXISTS 를 사용했다. EXISTS 는 조건을 만족하는 행이 존재하는지를 확인한다. 이번 요구사항에서 필요한 것은 좋아요 데이터 자체를 여러 건 조회하는 것 이 아니라 현재 사용자가 이 책을 좋아요 했는가? 라는 존재 여부다. 따라서 book_like 의 행 자체를 결과에 펼치기보다 해당 관계가 존재하는지만 확인하는 방식이 자연스럽다. 좋아요 기록 존재 → 1 좋아요 기록 없음 → 0 실제 결과는 다음과 같이 나타났다. 달빛 도서관 | 소설 | 1 달빛 도서관 | 추천 | 1 여기서 좋아요 여부가 두 번 보이는 이유 역시 태그 관계가 두 개이기 때문이다. EXISTS 가 두 개의 좋아요 데이터를 만든 것이 아니라, 이미 태그 JOIN으로 두 행이 만들어졌고 각 행에서 같은 좋아요 존재 여부를 확인한 것이다. 이 부분을 통해 JOIN을 사용할지 다른 방식으로 관계를 확인할지는 최종적으로 어떤 데이터를 결과 행으로 펼치고 싶은가 에 따라 달라질 수 있다는 점도 알게 되었다. 7. JOIN을 볼 때는 결과보다 관계를 먼저 보자 1주차에서는 ERD를 설계하며 테이블 사이의 관계를 정리했다. 2주차에는 그 관계를 실제 SQL로 조회하면서 ERD의 카디널리티가 실제 SQL 결과의 형태로 나타난다. 는 것을 확인할 수 있었다. 처음에는 다음 결과만 보고 달빛 도서관 | 소설 달빛 도서관 | 추천 책 제목이 중복되었다고 생각했다. 하지만 ERD를 함께 보면 book 1 : N book_tag 관계이기 때문에 같은 책이 여러 행에 나타나는 것이 자연스럽다는 것을 바로 이해할 수 있다. 그래서 앞으로 JOIN 쿼리를 작성하거나 결과를 확인할 때는 쿼리만 보지 않고 다음을 먼저 확인하려고 한다. 기준 테이블은 무엇인가? 어떤 PK와 FK가 연결되어 있는가? 관계가 1:1, 1:N, N:M 중 무엇인가? 기준 행 하나에 몇 개의 상대 행이 매칭될 수 있는가? 현재 결과의 한 행은 어떤 관계를 의미하는가? 이 과정을 먼저 생각하면 결과 행이 예상보다 많을 때도 단순히 중복 오류 라고 판단하지 않고 원인을 더 정확하게 찾을 수 있다. 마무리 이번 주차에서 JOIN을 직접 사용하기 전에는 JOIN을 단순히 여러 테이블을 하나로 연결하는 SQL 문법 정도로 생각했다. 하지만 실제로 조회 결과를 확인하면서 JOIN은 단순히 테이블을 옆으로 붙이는 것이 아니라, 테이블 사이에 존재하는 관계를 결과 행으로 펼쳐 보여주는 과정 에 더 가깝다고 느꼈다. 특히 1:N 관계에서는 하나의 기준 데이터가 여러 데이터와 연결되어 있기 때문에 같은 값이 여러 행에 반복될 수 있다. 이 반복은 항상 잘못된 중복이 아니다. 중요한 것은 각 행이 실제로 서로 다른 관계를 나타내고 있는지를 확인하는 것이다. 또한 결과가 많다고 바로 DISTINCT 로 제거하기보다, ERD의 관계와 ON 조건을 먼저 확인해야 한다는 점도 알게 되었다. 이번 실습을 통해 가장 기억에 남은 내용을 한 문장으로 정리하면 다음과 같다. JOIN 결과의 행 수는 단순히 원본 테이블의 행 수가 아니라, 데이터 사이에 존재하는 관계의 수와 카디널리티에 의해 결정될 수 있다. 앞으로 JOIN 결과가 예상과 다르게 나온다면 ERD 관계 → PK/FK → 카디널리티 → ON 조건 → 결과 행의 의미 순서로 확인해보려고 한다.