8000 agent/README.ko.md at main Β· hmmhmmhm/agent Β· GitHub
[go: up one dir, main page]

Skip to content

Latest commit

Β 

History

History
495 lines (413 loc) Β· 23.2 KB

README.ko.md

File metadata and controls

495 lines (413 loc) Β· 23.2 KB

@wrtnlabs/agent

λ‹€λ₯Έ μ–Έμ–΄λ‘œ 읽기: English, ζ—₯本θͺž

Key Concept Gear Diagram

GitHub license npm version Downloads Build Status

LLM ν•¨μˆ˜ ν˜ΈμΆœμ— νŠΉν™”λœ κ°€μž₯ κ°„λ‹¨ν•œ AI μ—μ΄μ „νŠΈ λΌμ΄λΈŒλŸ¬λ¦¬μ˜ˆμš”.

@wrtnlabs/agentλŠ” LLM(λŒ€κ·œλͺ¨ μ–Έμ–΄ λͺ¨λΈ) ν•¨μˆ˜ ν˜ΈμΆœμ— νŠΉν™”λœ κ°€μž₯ κ°„λ‹¨ν•œ AI μ—μ΄μ „νŠΈ λΌμ΄λΈŒλŸ¬λ¦¬μ—μš”. Swagger/OpenAPI λ¬Έμ„œλ‚˜ TypeScript 클래슀 νƒ€μž…μ„ 톡해 ν˜ΈμΆœν•  ν•¨μˆ˜λ₯Ό μ œκ³΅ν•˜λ©΄ λͺ¨λ“  κΈ°λŠ₯이 κ°€λŠ₯ν•΄μ Έμš”. 슈퍼 AI 챗봇 κ°œλ°œμ΄λ‚˜ λ©€ν‹° μ—μ΄μ „νŠΈ μ˜€μΌ€μŠ€νŠΈλ ˆμ΄μ…˜, λͺ¨λ“  것을 ν•¨μˆ˜ ν˜ΈμΆœμ„ 톡해 μ‹€ν˜„ν•  수 μžˆμ–΄μš”.

예λ₯Ό λ“€μ–΄, μ‡Όν•‘λͺ° μ„œλ²„μ˜ Swagger λ¬Έμ„œλ₯Ό μ œκ³΅ν•˜λ©΄ @wrtnlabs/agentλŠ” 슈퍼 AI 챗봇 μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„ κ΅¬μ„±ν•΄μš”. 이 챗봇 μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œ 고객은 λŒ€ν™” ν…μŠ€νŠΈλ§ŒμœΌλ‘œ μ œν’ˆμ„ ꡬ맀할 수 μžˆμ–΄μš”. μƒλ‹΄μ΄λ‚˜ ν™˜λΆˆ ν”„λ‘œμ„ΈμŠ€λ₯Ό μžλ™ν™”ν•˜κ³  μ‹Άλ‹€λ©΄ Swagger λ¬Έμ„œλ§Œ μ „λ‹¬ν•˜λ©΄ λΌμš”.

λ˜ν•œ, LLM ν•¨μˆ˜ 호좜 μ „λž΅μ€ λ©€ν‹° μ—μ΄μ „νŠΈ μ˜€μΌ€μŠ€νŠΈλ ˆμ΄μ…˜μ— νš¨κ³Όμ μ΄μ—μš”. 더 λ³΅μž‘ν•œ ν”„λ ˆμž„μ›Œν¬λ₯Ό 배우고 νŠΉμ • νŒ¨λŸ¬λ‹€μž„μ΄λ‚˜ νŒ¨ν„΄μ„ λ”°λ₯΄λŠ” 것보닀 훨씬 μ‰½κ²Œ κ°œλ°œν•  수 μžˆμ–΄μš”. 클래슀 μ—°κ²°λ§Œ ν•˜λ©΄ 되고 TypeScript 클래슀 νƒ€μž…μ„ μ „λ‹¬ν•˜μ„Έμš”. @wrtnlabs/agentκ°€ ν•¨μˆ˜ ν˜ΈμΆœμ„ 톡해 λ©€ν‹° μ—μ΄μ „νŠΈ μ˜€μΌ€μŠ€νŠΈλ ˆμ΄μ…˜μ„ 쀑앙 μ§‘μ€‘ν™”ν•˜κ³  μ‹€ν˜„ν•  κ±°μ˜ˆμš”.

shopping-chat.mp4

μ‡Όν•‘ AI μ±—λ΄‡μ˜ μ‹œμ—° λ™μ˜μƒμ΄μ—μš”.

μ‚¬μš© 방법

μ…‹μ—…

npm install @wrtnlabs/agent @samchon/openapi typia
npx typia setup

@wrtnlabs/agent뿐만 μ•„λ‹ˆλΌ @samchon/openapi와 typia도 μ„€μΉ˜ν•΄μ•Ό ν•΄μš”.

@samchon/openapiλŠ” Swagger/OpenAPI λ¬Έμ„œλ₯Ό LLM ν•¨μˆ˜ 호좜 μŠ€ν‚€λ§ˆλ‘œ λ³€ν™˜ν•  수 μžˆλŠ” OpenAPI 사양 λΌμ΄λΈŒλŸ¬λ¦¬μ—μš”. typiaλŠ” TypeScript 클래슀 νƒ€μž…μ—μ„œ LLM ν•¨μˆ˜ 호좜 μŠ€ν‚€λ§ˆλ₯Ό ꡬ성할 수 μžˆλŠ” λ³€ν™˜κΈ°(컴파일러) λΌμ΄λΈŒλŸ¬λ¦¬μ—μš”.

참고둜, typiaλŠ” 컴파일 μˆ˜μ€€μ—μ„œ TypeScript μ†ŒμŠ€ μ½”λ“œμ™€ νƒ€μž…μ„ λΆ„μ„ν•˜λŠ” λ³€ν™˜κΈ° λΌμ΄λΈŒλŸ¬λ¦¬μ΄λ―€λ‘œ μΆ”κ°€ μ„€μ • λͺ…령인 npx typia setup이 ν•„μš”ν•΄μš”. ν‘œμ€€μ΄ μ•„λ‹Œ TypeScript 컴파일러(tsc)λ₯Ό μ‚¬μš©ν•˜μ§€ μ•Šκ±°λ‚˜ ν”„λ‘ νŠΈμ—”λ“œ ν™˜κ²½μ—μ„œ μ—μ΄μ „νŠΈλ₯Ό κ°œλ°œν•˜λŠ” 경우 @ryoppippi/unplugin-typia도 μ„€μ •ν•΄μ•Ό ν•΄μš”.

λ°±μ•€λ“œ μ„œλ²„μ™€ λŒ€ν™”ν•˜κΈ°

import { IHttpLlmApplication } from "@samchon/openapi";
import { WrtnAgent, createHttpApplication } from "@wrtnlabs/agent";
import OpenAI from "openai";
import { IValidation } from "typia";

const main = async (): Promise<void> => {
  // SWAGGER λ¬Έμ„œλ₯Ό λ‘œλ“œν•˜κ³  LLM μ‘μš© μŠ€ν‚€λ§ˆλ‘œ λ³€ν™˜
  const application: IValidation<IHttpLlmApplication<"chatgpt">> =
    createHttpApplication({
      model: "chatgpt",
      document: OpenApi.convert(
        await fetch("https://shopping-be.wrtn.ai/editor/swagger.json").then(
          (r) => r.json()
        )
      ),
    });
  if (application.success === false) {
    console.error(application.errors);
    throw new Error("λŒ€μƒ swagger λ¬Έμ„œμ— μœ ν˜• 였λ₯˜ λ°œμƒ");
  }

  // μ—μ΄μ „νŠΈλ₯Ό μ• ν”Œλ¦¬μΌ€μ΄μ…˜κ³Ό ν•¨κ»˜ 생성
  const agent: WrtnAgent = new WrtnAgent({
    provider: {
      type: "chatgpt",
      model: "gpt-4o-mini",
      api: new OpenAI({
        apiKey: "YOUR_OPENAI_API_KEY",
      }),
    },
    controllers: [
      {
        protocol: "http",
        name: "shopping",
        application: application.data,
        connection: {
          host: "https://shopping-be.wrtn.ai",
        },
      },
    ],
    config: {
      locale: "en-US",
    },
  });

  // 이벀트 λ¦¬μŠ€λ„ˆ μΆ”κ°€
  agent.on("select", async (<
8000
/span>select) => {
    console.log("μ„ νƒλœ ν•¨μˆ˜", select.operation.function.name);
  });
  agent.on("execute", async (execute) => {
    consoe.log("μ‹€ν–‰λœ ν•¨μˆ˜", {
      function: execute.operation.function.name,
      arguments: execute.arguments,
      value: execute.value,
    });
  });

  // AI 챗봇과 λŒ€ν™”
  await agent.conversate("What you can do?");
};
main().catch(console.error);

Swagger λ¬Έμ„œλ₯Ό λ‘œλ“œν•˜κ³  그것을 @wrtnlabs/agent에 μ „λ‹¬ν•˜κΈ°λ§Œ ν•˜λ©΄ λΌμš”.

그러면 λ°±μ—”λ“œ μ„œλ²„μ™€μ˜ λŒ€ν™”κ°€ μ‹œμž‘λ˜κ³ , λ°±μ—”λ“œ μ„œλ²„μ˜ API ν•¨μˆ˜κ°€ μžλ™μœΌλ‘œ 호좜될 κ±°μ˜ˆμš”. AI 챗봇은 λŒ€ν™” ν…μŠ€νŠΈλ₯Ό λΆ„μ„ν•˜κ³  LLM ν•¨μˆ˜ 호좜 κΈ°λŠ₯을 톡해 μ μ ˆν•œ API ν•¨μˆ˜λ₯Ό μ‹€ν–‰ν•΄μš”.

μ΄μ œλΆ€ν„° λͺ¨λ“  λ°±μ—”λ“œ κ°œλ°œμžλŠ” λ™μ‹œμ— AI κ°œλ°œμžμ—μš”.

TypeScript ν΄λž˜μŠ€μ™€ λŒ€ν™”ν•˜κΈ°

import { WrtnAgent } from "@wrtnlabs/agent";
import typia, { tags } from "typia";
import OpenAI from "openai";

class BbsArticleService {
  /**
   * μƒˆλ‘œμš΄ 기사λ₯Ό μž‘μ„±ν•˜μ„Έμš”.
   *
   * μƒˆ 기사λ₯Ό μž‘μ„±ν•˜κ³  DB에 λ³΄κ΄€ν•˜μ„Έμš”.
   *
   * @param props μž‘μ„± ν•¨μˆ˜μ˜ 속성
   * @returns μƒˆλ‘œ μž‘μ„±λœ 기사
   */
  public async create(props: {
    /**
     * μž‘μ„±ν•  κΈ°μ‚¬μ˜ 정보
     */
    input: IBbsArticle.ICreate;
  }): Promise<IBbsArticle>;

  /**
   * 기사λ₯Ό μ—…λ°μ΄νŠΈν•˜μ„Έμš”.
   *
   * 기사λ₯Ό μƒˆλ‘œμš΄ μ½˜ν…μΈ λ‘œ μ—…λ°μ΄νŠΈν•˜μ„Έμš”.
   *
   * @param props μ—…λ°μ΄νŠΈ ν•¨μˆ˜μ˜ 속성
   * @param input μ—…λ°μ΄νŠΈν•  μƒˆλ‘œμš΄ μ½˜ν…μΈ 
   */
  public async update(props: {
    /**
     * νƒ€κ²Ÿ κΈ°μ‚¬μ˜ {@link IBbsArticle.id}.
     */
    id: string & tags.Format<"uuid">;

    /**
     * μ—…λ°μ΄νŠΈν•  μƒˆλ‘œμš΄ μ½˜ν…μΈ .
     */
    input: IBbsArticle.IUpdate;
  }): Promise<void>;
}

const main = async (): Promise<void> => {
  const api: OpenAI = new OpenAI({
    apiKey: "YOUR_OPENAI_API_KEY",
  });
  const agent: WrtnAgent = new WrtnAgent({
    provider: {
      type: "chatgpt",
      model: "gpt-4o-mini",
      api: new OpenAI({
        apiKey: "YOUR_OPENAI_API_KEY",
      }),
    },
    controllers: [
      {
        protocol: "class",
        name: "vectorStore",
        application: typia.llm.applicationOfValidate<
          BbsArticleService,
          "chatgpt"
        >(),
        execute: new BbsArticleService(),
      },
    ],
  });
  await agent.conversate("I wanna write an article.");
};
main().catch(console.error);

TypeScript ν΄λž˜μŠ€μ™€λ„ λŒ€ν™”ν•  수 μžˆμ–΄μš”.

TypeScript νƒ€μž…μ„ @wrtnlabs/agent에 μ „λ‹¬ν•˜κ³  λŒ€ν™”λ₯Ό μ‹œμž‘ν•΄ λ³΄μ„Έμš”. 그러면 @wrtnlabs/agentκ°€ LLM ν•¨μˆ˜ 호좜 κΈ°λŠ₯을 톡해 λŒ€ν™” ν…μŠ€νŠΈλ₯Ό λΆ„μ„ν•˜μ—¬ μ μ ˆν•œ 클래슀 ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•  κ±°μ˜ˆμš”.

μ΄μ œλΆ€ν„° μ—¬λŸ¬λΆ„μ΄ κ°œλ°œν•œ λͺ¨λ“  TypeScript ν΄λž˜μŠ€κ°€ AI 챗봇이 될 수 μžˆμ–΄μš”.

λ©€ν‹° μ—μ΄μ „νŠΈ μ˜€μΌ€μŠ€νŠΈλ ˆμ΄μ…˜

import { WrtnAgent } from "@wrtnlabs/agent";
import typia from "typia";
import OpenAI from "openai";

class OpenAIVectorStoreAgent {
  /**
   * RAG둜 벑터 DBλ₯Ό κ²€μƒ‰ν•˜μ„Έμš”.
   *
   * @param props 벑터 DB 검색 속성
   */
  public async query(props: {
    /**
     * μ‘°νšŒν•  ν‚€μ›Œλ“œ.
     *
     * μ‘°νšŒν•˜κ³  싢은 λͺ¨λ“  ν‚€μ›Œλ“œλ₯Ό λ„£μœΌμ„Έμš”. κ·ΈλŸ¬λ‚˜ ν•΅μ‹¬λ§Œ ν¬ν•¨μ‹œν‚€κ³ 
     * 뢈λͺ…ν™•ν•œ λ‚΄μš©μ„ μ œμ™Έν•˜μ—¬ μ •ν™•ν•œ κ²°κ³Όλ₯Ό μ–»μœΌμ„Έμš”.
     */
    keywords: string;
  }): Promise<IVectorStoreQueryResult>;
}

const main = async (): Promise<void> => {
  const api: OpenAI = new OpenAI({
    apiKey: "YOUR_OPENAI_API_KEY",
  });
  const agent: WrtnAgent = new WrtnAgent({
    provider: {
      type: "chatgpt",
      model: "gpt-4o-mini",
      api: new OpenAI({
        apiKey: "YOUR_OPENAI_API_KEY",
      }),
    },
    controllers: [
      {
        protocol: "class",
        name: "vectorStore",
        application: typia.llm.applicationOfValidate<
          OpenAIVectorStoreAgent,
          "chatgpt"
        >(),
        execute: new OpenAIVectorStoreAgent({
          api,
          id: "YOUR_OPENAI_VECTOR_STORE_ID",
        }),
      },
    ],
  });
  await agent.conversate("I wanna research economic articles");
};
main().catch(console.error);

@wrtnlabs/agentμ—μ„œλŠ” λ©€ν‹° μ—μ΄μ „νŠΈ μ˜€μΌ€μŠ€νŠΈλ ˆμ΄μ…˜μ„ μ•„μ£Ό μ‰½κ²Œ κ΅¬ν˜„ν•  수 μžˆμ–΄μš”.

Vector Store와 같은 μ—μ΄μ „νŠΈ κΈ°λŠ₯을 κ°–μΆ˜ TypeScript 클래슀λ₯Ό κ°œλ°œν•˜κ³ , μœ„μ™€ 같이 TypeScript 클래슀 νƒ€μž…μ„ @wrtnlabs/agent에 μ „λ‹¬ν•˜μ„Έμš”. @wrtnlabs/agentλŠ” TypeScript 클래슀둜 LLM ν•¨μˆ˜ 호좜 μ „λž΅μ„ 톡해 λ©€ν‹° μ—μ΄μ „νŠΈ μ˜€μΌ€μŠ€νŠΈλ ˆμ΄μ…˜μ„ 쀑앙 μ§‘μ€‘ν™”ν•˜κ³  μ‹€ν˜„ν•  κ±°μ˜ˆμš”.

원리

μ—μ΄μ „νŠΈ μ „λž΅

sequenceDiagram
actor User
actor Agent
participant Selector
participant Executor
participant Describer
activate User
User-->>Agent: λŒ€ν™”:<br/>μ‚¬μš©μž λ°œμ–Έ
activate Agent
Agent->>Selector: λŒ€ν™” ν…μŠ€νŠΈ 전달
activate Selector
deactivate User
Note over Selector: 후보 κΈ°λŠ₯ 선택 λ˜λŠ” 제거
alt 후보 μ—†μŒ
  Selector->>Agent: 일반 ChatGPT λŒ€ν™”
  deactivate Selector
  Agent->>User: λŒ€ν™”:<br/>μ—μ΄μ „νŠΈ λ°œμ–Έ
  activate User
  deactivate User
end
deactivate Agent
loop 후보 κΈ°λŠ₯ 쑴재
  activate Agent
  Agent->>Executor: λŒ€ν™” ν…μŠ€νŠΈ 전달
  activate Executor
  alt μ»¨ν…μŠ€νŠΈ μΆ©λΆ„
    Note over Executor: 좩쑱된 ν•¨μˆ˜ 호좜
    Executor->>Describer: ν•¨μˆ˜ 호좜 기둝
    deactivate Executor
    activate Describer
    Describer->>Agent: ν•¨μˆ˜ 호좜 μ„€λͺ…
    deactivate Describer
    Agent->>User: λŒ€ν™”:<br/>μ—μ΄μ „νŠΈ μ„€λͺ…
    activate User
    deactivate User
  else μ»¨ν…μŠ€νŠΈ λΆˆμΆ©λΆ„
    break
      Executor->>Agent: μΆ”κ°€ 정보 μš”μ²­
    end
    Agent->>User: λŒ€ν™”:<br/>μ—μ΄μ „νŠΈ μš”μ²­
    activate User
    deactivate User
  end
  deactivate Agent
end
Loading

μ‚¬μš©μžκ°€ λ°œμ–Έμ„ ν•˜λ©΄, @wrtnlabs/agentλŠ” λŒ€ν™” ν…μŠ€νŠΈλ₯Ό selector μ—μ΄μ „νŠΈμ— μ „λ‹¬ν•˜κ³ , selector μ—μ΄μ „νŠΈκ°€ μ»¨ν…μŠ€νŠΈμ—μ„œ 후보 ν•¨μˆ˜λ₯Ό μ°Ύκ±°λ‚˜ μ·¨μ†Œν•˜λ„λ‘ ν•©λ‹ˆλ‹€. selector μ—μ΄μ „νŠΈκ°€ ν˜ΈμΆœν•  후보 ν•¨μˆ˜λ₯Ό 찾을 수 μ—†κ³  이전에 μ„ νƒλœ 후보 ν•¨μˆ˜λ„ μ—†λ‹€λ©΄, selector μ—μ΄μ „νŠΈλŠ” 일반 ChatGPT처럼 μž‘λ™ν•©λ‹ˆλ‹€.

그리고 @wrtnlabs/agentλŠ” 후보 ν•¨μˆ˜κ°€ λΉ„μ–΄μ§ˆ λ•ŒκΉŒμ§€ λ°˜λ³΅λ¬Έμ— λ“€μ–΄κ°‘λ‹ˆλ‹€. 이 λ°˜λ³΅λ¬Έμ—μ„œ executor μ—μ΄μ „νŠΈλŠ” μ‚¬μš©μžμ˜ λŒ€ν™” ν…μŠ€νŠΈλ₯Ό 뢄석해 LLM ν•¨μˆ˜ ν˜ΈμΆœμ„ μ‹œλ„ν•©λ‹ˆλ‹€. λ§Œμ•½ μ»¨ν…μŠ€νŠΈκ°€ 후보 ν•¨μˆ˜μ˜ 인수λ₯Ό κ΅¬μ„±ν•˜κΈ°μ— μΆ©λΆ„ν•˜λ‹€λ©΄, executor μ—μ΄μ „νŠΈλŠ” μ‹€μ œλ‘œ λŒ€μƒ ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜κ³ , describer μ—μ΄μ „νŠΈκ°€ ν•¨μˆ˜ 호좜 κ²°κ³Όλ₯Ό μ„€λͺ…ν•˜λ„λ‘ ν•©λ‹ˆλ‹€. λ°˜λŒ€λ‘œ μ»¨ν…μŠ€νŠΈκ°€ μΆ©λΆ„ν•˜μ§€ μ•Šλ‹€λ©΄ executor μ—μ΄μ „νŠΈλŠ” μ‚¬μš©μžμ—κ²Œ μΆ”κ°€ 정보λ₯Ό μš”μ²­ν•©λ‹ˆλ‹€.

μ΄λŸ¬ν•œ LLM(λŒ€κ·œλͺ¨ μ–Έμ–΄ λͺ¨λΈ) ν•¨μˆ˜ 호좜 μ „λž΅μ—μ„œ selector, executor, describerλ₯Ό λΆ„λ¦¬ν•˜λŠ” 것이 @wrtnlabs/agent의 핡심 λ‘œμ§μž…λ‹ˆλ‹€.

검증 ν”Όλ“œλ°±

import { FunctionCall } from "pseudo";
import { ILlmFunctionOfValidate, IValidation } from "typia";

export const correctFunctionCall = (p: {
  call: FunctionCall;
  functions: Array<ILlmFunctionOfValidate<"chatgpt">>;
  retry: (reason: string, errors?: IValidation.IError[]) => Promise<unknown>;
}): Promise<unknown> => {
  // FIND FUNCTION
  const func: ILlmFunctionOfValidate<"chatgpt"> | undefined =
    p.functions.find(f => f.name === p.call.name);
  if (func === undefined) {
    // never happened in my experience
    return p.retry(
      "Unable to find the matched function name. Try it again.",
    );
  }

  // VALIDATE
  const result: IValidation<unknown> = func.validate(p.call.arguments);
  if (result.success === false) {
    // 1st trial: 50% (gpt-4o-mini in shopping mall chatbot)
    // 2nd trial with validation feedback: 99%
    // 3nd trial with validation feedback again: never have failed
    return p.retry(
      "Type errors are detected. Correct it through validation errors",
      {
        errors: result.errors,
      },
    );
  }
  return result.data;
}

LLM ν•¨μˆ˜ 호좜이 μ™„λ²½ν• κΉŒμš”?

정닡은 μ•„λ‹ˆμ—μš”. OpenAI와 같은 LLM(λŒ€κ·œλͺ¨ μ–Έμ–΄ λͺ¨λΈ) μ œκ³΅μžλŠ” λŒ€μƒ ν•¨μˆ˜ 호좜의 인수λ₯Ό ꡬ성할 λ•Œ λ§Žμ€ νƒ€μž… 였λ₯˜λ₯Ό μ €μ§ˆλŸ¬μš”. LLM ν•¨μˆ˜ 호좜 μŠ€ν‚€λ§ˆκ°€ Array<string> νƒ€μž…μœΌλ‘œ μ •μ˜λ˜μ–΄ μžˆμ–΄λ„, LLM은 μ’…μ’… 단일 string κ°’λ§ŒμœΌλ‘œ ꡬ성을 ν•˜κ³€ ν•΄μš”.

λ”°λΌμ„œ LLM ν•¨μˆ˜ 호좜 μ—μ΄μ „νŠΈλ₯Ό κ°œλ°œν•  λ•Œ, 검증 ν”Όλ“œλ°± ν”„λ‘œμ„ΈμŠ€κ°€ ν•„μˆ˜μ μœΌλ‘œ μš”κ΅¬λ©λ‹ˆλ‹€. LLM이 인수 ꡬ성을 ν•  λ•Œ νƒ€μž… 였λ₯˜λ₯Ό λ²”ν•˜λ©΄, μ—μ΄μ „νŠΈλŠ” κ°€μž₯ μƒμ„Έν•œ 검증 였λ₯˜λ₯Ό ν”Όλ“œλ°± ν•˜κ³ , LLM이 검증 였λ₯˜λ₯Ό μ°Έκ³ ν•˜μ—¬ ν•¨μˆ˜ ν˜ΈμΆœμ„ μž¬μ‹œλ„ ν•˜λ„λ‘ ν•΄μ•Ό λΌμš”.

검증 ν”Όλ“œλ°± κ΄€λ ¨ν•˜μ—¬, @wrtnlabs/agentλŠ” typia.validate<T>()와 typia.llm.applicationOfValidate<Class, Model>() κΈ°λŠ₯을 ν™œμš©ν•΄μš”. 이듀은 컴파일 μˆ˜μ€€μ—μ„œ TypeScript μ†ŒμŠ€ μ½”λ“œλ₯Ό λΆ„μ„ν•˜μ—¬ 검증 논리λ₯Ό κ΅¬μΆ•ν•˜κΈ° λ•Œλ¬Έμ— λ‹€λ₯Έ μ–΄λŠ 검증기 보닀도 μƒμ„Έν•˜κ³  μ •ν™•ν•΄μš”. κ·ΈλŸ¬λ―€λ‘œ κ°€μž₯ 이상적인 LLM ν•¨μˆ˜ ν˜ΈμΆœμ„ μ‹€ν˜„ν•˜κ²Œ λ˜μ—ˆμ–΄μš”. 제 κ²½ν—˜μ—μ„œ OpenAI의 gpt-4o-mini λͺ¨λΈμ„ μ‚¬μš©ν•  λ•Œ, 처음 μ‹œλ„μ— μ•½ 50% μ •λ„λŠ” μœ νš¨ν•˜μ§€ μ•Šμ€ ν•¨μˆ˜ 호좜 인수λ₯Ό κ΅¬μ„±ν•˜λŠ” κ²½ν–₯을 λ³΄μ˜€μ–΄μš”. ν•˜μ§€λ§Œ typia의 검증 ν”Όλ“œλ°±μ„ 톡해 μˆ˜μ •ν•˜κ²Œ 되면 성곡λ₯ μ΄ 99%둜 κΈ‰κ²©νžˆ μƒμŠΉν•΄μš”. 그리고 검증 ν”Όλ“œλ°±μ„ 두 번 μ‹œλ„ν•˜λ©΄ μ‹€νŒ¨ν•œ 적이 μ—†μ–΄μš”.

μ»΄ν¬λ„ŒνŠΈ typia TypeBox ajv io-ts zod C.V.
μ‚¬μš©ν•˜κΈ° 쉬움 βœ… ❌ ❌ ❌ ❌ ❌
객체 (간단) βœ” βœ” βœ” βœ” βœ” βœ”
객체 (계측) βœ” βœ” βœ” βœ” βœ” βœ”
객체 (μž¬κ·€) βœ” ❌ βœ” βœ” βœ” βœ”
객체 (μœ λ‹ˆμ˜¨, μ•”μ‹œ) βœ… ❌ ❌ ❌ ❌ ❌
객체 (μœ λ‹ˆμ˜¨, λͺ…μ‹œ) βœ” βœ” βœ” βœ” βœ” ❌
객체 (μΆ”κ°€ νƒœκ·Έ) βœ” βœ” βœ” βœ” βœ” βœ”
객체 (ν…œν”Œλ¦Ώ λ¦¬ν„°λŸ΄ νƒ€μž…) βœ” βœ” βœ” ❌ ❌ ❌
객체 (동적 속성) βœ” βœ” βœ” ❌ ❌ ❌
λ°°μ—΄ (ν›„ν–‰ νŠœν”Œ) βœ… ❌ ❌ ❌ ❌ ❌
λ°°μ—΄ (계측) βœ” βœ” βœ” βœ” βœ” βœ”
λ°°μ—΄ (μž¬κ·€) βœ” βœ” βœ” βœ” βœ” ❌
λ°°μ—΄ (μž¬κ·€, μœ λ‹ˆμ˜¨) βœ” βœ” ❌ βœ” βœ” ❌
λ°°μ—΄ (R+U, μ•”μ‹œ) βœ… ❌ ❌ ❌ ❌ ❌
λ°°μ—΄ (쀑볡) βœ… ❌ ❌ ❌ ❌ ❌
λ°°μ—΄ (쀑볡, μœ λ‹ˆμ˜¨) βœ… ❌ ❌ ❌ ❌ ❌
ꢁ극의 μœ λ‹ˆμ˜¨ νƒ€μž… βœ… ❌ ❌ ❌ ❌ ❌

C.V.λŠ” class-validatorλ₯Ό μ˜λ―Έν•΄μš”

OpenAPI λͺ…μ„Έ

flowchart
  subgraph "OpenAPI λͺ…μ„Έ"
    v20("Swagger v2.0") --μ—…κ·Έλ ˆμ΄λ“œ--> emended[["OpenAPI v3.1 (μˆ˜μ •λ¨)"]]
    v30("OpenAPI v3.0") --μ—…κ·Έλ ˆμ΄λ“œ--> emended
    v31("OpenAPI v3.1") --μˆ˜μ •--> emended
  end
  subgraph "OpenAPI λ³€ν™˜κΈ°"
    emended --μ •κ·œν™”--> migration[["λ§ˆμ΄κ·Έλ ˆμ΄μ…˜ μŠ€ν‚€λ§ˆ"]]
    migration --"인곡지λŠ₯"--> lfc{{"LLM ν•¨μˆ˜ 호좜"}}
    lfc --"OpenAI"--> chatgpt("ChatGPT")
    lfc --"Anthropic"--> claude("Claude")
    lfc --"Google"--> gemini("Gemini")
    lfc --"Meta"--> llama("Llama")
  end
Loading

@wrtnlabs/agentλŠ” Swagger/OpenAPI λ¬Έμ„œμ™€ TypeScript 클래슀 νƒ€μž…μ—μ„œ LLM ν•¨μˆ˜ 호좜 μŠ€ν‚€λ§ˆλ₯Ό μ–»μ–΄μš”. TypeScript 클래슀 νƒ€μž…μ€ typia.llm.applicationOfValidate<Class, Model>() ν•¨μˆ˜λ₯Ό 톡해 LLM ν•¨μˆ˜ 호좜 μŠ€ν‚€λ§ˆλ‘œ λ³€ν™˜λ  수 μžˆμ–΄μš”. κ·Έλ ‡λ‹€λ©΄ OpenAPI λ¬Έμ„œλŠ” μ–΄λ–»κ²Œ LLM ν•¨μˆ˜ 호좜 μŠ€ν‚€λ§ˆκ°€ 될 수 μžˆμ„κΉŒμš”?

비밀은 μœ„μ˜ λ‹€μ΄μ–΄κ·Έλž¨μ— μžˆμŠ΅λ‹ˆλ‹€.

OpenAPI λͺ…μ„Έμ—λŠ” μ„œλ‘œ λ‹€λ₯Έ μ •μ˜λ₯Ό κ°€μ§„ μ„Έ κ°€μ§€ 버전이 μžˆμ–΄μš”. 심지어 같은 λ²„μ „μ—μ„œλ„ λ„ˆλ¬΄ λ§Žμ€ λͺ¨ν˜Έν•˜κ³  μ€‘λ³΅λœ ν‘œν˜„μ΄ ν¬ν•¨λ˜μ–΄ μžˆμ–΄μš”. 이 문제λ₯Ό ν•΄κ²°ν•˜κΈ° μœ„ν•΄ @samchon/openapiλŠ” λͺ¨λ“  OpenAPI λ¬Έμ„œλ₯Ό v3.1의 μˆ˜μ •λœ λͺ…μ„Έλ‘œ λ³€ν™˜ν•˜κ³  μžˆμ–΄μš”. @samchon/openapi의 μˆ˜μ •λœ v3.1 λͺ…μ„ΈλŠ” λͺ¨ν˜Έν•˜κ³  μ€‘λ³΅λœ λͺ¨λ“  ν‘œν˜„μ„ μ œκ±°ν•˜μ—¬ λͺ…확함을 μΆ”κ΅¬ν•΄μš”.

μˆ˜μ •λœ v3.1 OpenAPI λ¬Έμ„œλ₯Ό 톡해, @samchon/openapiλŠ” 이λ₯Ό ν•¨μˆ˜ ꡬ쑰에 κ°€κΉŒμš΄ λ§ˆμ΄κ·Έλ ˆμ΄μ…˜ μŠ€ν‚€λ§ˆλ‘œ λ³€ν™˜ν•©λ‹ˆλ‹€. 그리고 λ§ˆμ§€λ§‰ λ‹¨κ³„μ—μ„œλŠ” λ§ˆμ΄κ·Έλ ˆμ΄μ…˜ μŠ€ν‚€λ§ˆκ°€ νŠΉμ • LLM 제곡자의 ν•¨μˆ˜ 호좜 μŠ€ν‚€λ§ˆλ‘œ λ³€ν™˜λ©λ‹ˆλ‹€. LLM ν•¨μˆ˜ 호좜 μŠ€ν‚€λ§ˆλŠ” μ΄λ ‡κ²Œ κ΅¬μ„±λ©λ‹ˆλ‹€.

μ™œ 직접 λ³€ν™˜ν•˜μ§€ μ•Šκ³ , 쀑간 단계λ₯Ό κ±°μΉ˜λ‚˜μš”?

각 λ²„μ „μ˜ OpenAPI λͺ…μ„Έμ—μ„œ νŠΉμ • LLM의 ν•¨μˆ˜ 호좜 μŠ€ν‚€λ§ˆλ‘œ 직접 λ³€ν™˜ν•œλ‹€λ©΄ 데카λ₯΄νŠΈ 곱에 μ˜ν•΄ 훨씬 더 λ§Žμ€ λ³€ν™˜κΈ°λ₯Ό λ§Œλ“€μ–΄μ•Ό ν•΄μš”. ν˜„μž¬ λͺ¨λΈμ—μ„œλŠ” λ³€ν™˜κΈ°μ˜ μˆ˜κ°€ 12 = 3 x 4 κ°€ λ©λ‹ˆλ‹€.

ν•˜μ§€λ§Œ 쀑간 μŠ€ν‚€λ§ˆλ₯Ό μ •μ˜ν•˜λ©΄ λ³€ν™˜κΈ°μ˜ μˆ«μžλŠ” λ§μ…ˆ μ—°μ‚°μœΌλ‘œ μ€„μ–΄λ“€μ–΄μš”. ν˜„μž¬ λͺ¨λΈμ—μ„œλŠ” 7 = 3 + 4 만 있으면 되고, 이것이 쀑간 λͺ…μ„Έλ₯Ό μ •μ˜ν•œ μ΄μœ μž…λ‹ˆλ‹€. 이 방법은 κ²½μ œμ μ΄μ—μš”.

λ‘œλ“œλ§΅

κ°€μ΄λ“œ λ¬Έμ„œ

μ—¬κΈ° README λ¬Έμ„œμ—μ„œ @wrtnlabs/agentλŠ” μ£Όμš” κ°œλ…κ³Ό 원칙을 μ†Œκ°œν•˜κ³  일뢀 μ˜ˆμ‹œλ₯Ό 보여주고 μžˆμ–΄μš”.

ν•˜μ§€λ§Œ, AI 챗봇 개발의 뉴 μ»€λ¨Έλ“€μ—κ²ŒλŠ” 이 λ‚΄μš©λ§ŒμœΌλ‘œλŠ” μΆ©λΆ„ν•˜μ§€ μ•Šμ•„μš”. κ°€μ΄λ“œ λ¬Έμ„œμ™€ 예제 ν”„λ‘œμ νŠΈκ°€ κ΅μœ‘μ„ μœ„ν•΄ 많이 ν•„μš”ν•΄μš”. μš°λ¦¬λŠ” LLM ν•¨μˆ˜ ν˜ΈμΆœμ— μ΅œμ ν™”λœ μ˜¬λ°”λ₯Έ μ •μ˜λ₯Ό μž‘μ„±ν•˜λŠ” 방법을 λ°±μ—”λ“œ κ°œλ°œμžμ—κ²Œ μ•ˆλ‚΄ν•˜κ³ , λ©€ν‹° μ—μ΄μ „νŠΈ μ˜€μΌ€μŠ€νŠΈλ ˆμ΄μ…˜ κ΅¬ν˜„μ— μžˆμ–΄μ„œ μ΅œμƒμ˜ 방법을 μ†Œκ°œν•  ν•„μš”κ°€ μžˆμ–΄μš”.

2025λ…„ 3μ›” 31μΌκΉŒμ§€ μ΄λŸ¬ν•œ μƒμ„Έν•œ κ°€μ΄λ“œ λ¬Έμ„œλ₯Ό μž‘μ„±ν•  μ˜ˆμ •μ΄κ³ , μ™„μ„±λ˜κΈ°κΉŒμ§€ κ³„μ†ν•΄μ„œ λ¬Έμ„œλ₯Ό λ°œν‘œν•  μ˜ˆμ •μ΄μ—μš”.

ν”Œλ ˆμ΄κ·ΈλΌμš΄λ“œ

https://nestia.io/chat/playground

μ €λŠ” μ˜ˆμ „μ— Swagger AI 챗봇 ν”Œλ ˆμ΄κ·ΈλΌμš΄λ“œ μ›Ήμ‚¬μ΄νŠΈλ₯Ό κ°œλ°œν•œ 적이 μžˆμ–΄μš”.

κ·ΈλŸ¬λ‚˜ TypeScript 클래슀 νƒ€μž…μ—μ„œ ν•¨μˆ˜ μŠ€ν‚€λ§ˆλ₯Ό μ–»λŠ” λ‹€λ₯Έ 뢀뢄은 아직 μ€€λΉ„λ˜μ§€ μ•Šμ•˜μ–΄μš”. TypeScript 컴파일러(tsc)λ₯Ό λ‚΄μž₯ν•˜μ—¬ TypeScript 클래슀 νƒ€μž… 기반의 ν”Œλ ˆμ΄κ·ΈλΌμš΄λ“œ μ›Ήμ‚¬μ΄νŠΈλ₯Ό λ§Œλ“€ κ±°μ˜ˆμš”.

μƒˆλ‘œμš΄ ν”Œλ ˆμ΄κ·ΈλΌμš΄λ“œ μ›Ήμ‚¬μ΄νŠΈλŠ” 2025λ…„ 3μ›” 15μΌκΉŒμ§€ 곡개될 μ˜ˆμ •μ΄μ—μš”.

μ΅œμ ν™”

μ΄ˆκΈ°μ—λŠ” POC(κ°œλ… 증λͺ…) κ°œλ°œμ— μ§‘μ€‘ν–ˆκΈ° λ•Œλ¬Έμ—, @wrtnlabs/agentλ₯Ό κ΅¬μ„±ν•˜λŠ” λ‚΄λΆ€ μ—μ΄μ „νŠΈλ“€μ΄ 아직 λΉ„μš© μ΅œμ ν™”λ˜μ§€ μ•Šμ•˜μ–΄μš”. 특히, selector μ—μ΄μ „νŠΈλŠ” LLM 토큰을 κ³Όλ„ν•˜κ²Œ 반볡 μ†ŒλΉ„ν•˜κ³  μžˆμ–΄μš”. selector μ—μ΄μ „νŠΈλ₯Ό RAG(검색 증강 생성을 ν†΅ν•œ μ΅œμ ν™”) κΈ°μˆ μ„ 톡해 μ΅œμ ν™”ν•  μ˜ˆμ •μ΄μ—μš”.

λ˜ν•œ, @wrtnlabs/agent에 μ—°κ²°ν•  수 μžˆλŠ” λ‹€μˆ˜μ˜ μœ μš©ν•œ μ• λ“œμ˜¨ μ—μ΄μ „νŠΈλ₯Ό 지원할 μ˜ˆμ •μ΄μ—μš”. κ·Έ 쀑 ν•˜λ‚˜μΈ @wrtnlabs/hiveλŠ” selector μ—μ΄μ „νŠΈλ₯Ό μ΅œμ ν™”ν•˜μ—¬ LLM λΉ„μš©μ„ 크게 μ€„μ—¬μ€λ‹ˆλ‹€. κ·Έ 외에도 OpenAI 벑터 μŠ€ν† μ–΄ ν•Έλ“€λŸ¬μ™€ Postgres 기반 RAG 엔진도 제곡될 μ˜ˆμ •μ΄μ—μš”.

μ΄λŸ¬ν•œ @wrtnlabs/agentκ°€ μ œκ³΅ν•˜λŠ” μ• λ“œμ˜¨ μ—μ΄μ „νŠΈλ₯Ό 톡해 TypeScript 클래슀 ν•¨μˆ˜ ν˜ΈμΆœμ„ ν†΅ν•œ λ©€ν‹° μ—μ΄μ „νŠΈ μ˜€μΌ€μŠ€νŠΈλ ˆμ΄μ…˜ κ΅¬ν˜„ 방법을 배울 수 있고, @wrtnlabs/agentκ°€ λ©€ν‹° μ—μ΄μ „νŠΈ μ‹œμŠ€ν…œ μƒν˜Έμž‘μš©μ„ μ–Όλ§ˆλ‚˜ μ‰½κ²Œ λ§Œλ“œλŠ”μ§€ 이해할 수 μžˆμ–΄μš”.

μ›Ήμ†ŒμΌ“ λͺ¨λ“ˆ

import { 
  IWrtnAgentEvent,
  IWrtnAgentHeader,
  IWrtnAgentListener,
  IWrtnAgentService 
} from "@wrtnlabs/agent";
import { Driver, WebSocketConnector } from "tgrid";

const main = async (): Promise<void> => {
  const connector: WebSocketConnector<
    IWrtnAgentHeader,
    IWrtnAgentListener,
    IWrtnAgentService
  > = new WebSocketConnector(
    {
      locale: "en-US",
    } satisfies IWrtnAgentHeader,
    {
      // EVENT LISTENERS
      conversate: async (event: IWrtnAgentEvent.IConversate) => {},
      select: async (event: IWrtnAgentEvent.ISelect) => {},
      execute: async (event: IWrtnAgentEvent.IExecute) => {},
      describe: async (event: IWrtnAgentEvent.IDescribe) => {},
    } satisfies IWrtnAgentService,
  );
  await connector.connect("http://localhost:3000/chat");

  // CALL SERVER'S FUNCTION
  const service: Driver<IWrtnAgentService> = connector.getDriver();
  await service.conversate("Hello, what you can do?");
};
main().catch(console.error);

@wrtnlabs/agentλŠ” RPC(원격 ν”„λ‘œμ‹œμ € 호좜) νŒ¨λŸ¬λ‹€μž„μ˜ μ›Ήμ†ŒμΌ“ λͺ¨λ“ˆμ„ μ œκ³΅ν•  μ˜ˆμ •μ΄μ—μš”.

이 μ›Ήμ†ŒμΌ“ λͺ¨λ“ˆμ€ μ—μ΄μ „νŠΈ λ°±μ—”λ“œ μ„œλ²„μ™€ AI 챗봇 ν”„λ‘ νŠΈμ—”λ“œ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„ μ‰½κ²Œ 톡합할 수 있게 도와쀄 κ±°μ˜ˆμš”.

이 κΈ°λŠ₯은 2025λ…„ 2μ›” 28μΌκΉŒμ§€ 지원할 μ˜ˆμ •μ΄μ—μš”.

LLM 제곡자

flowchart
Agent["<code>@wrtnlabs/agent</code>"]
OpenAI("<b><u>OpenAI</u></b>")
Claude
Llama
Gemini
Agent==supports==>OpenAI
Agent-.not yet.->Claude
Agent-.not yet.->Llama
Agent-.not yet.->Gemini
Loading

ν˜„μž¬ @wrtnlabs/agentλŠ” OpenAI만 μ§€μ›ν•΄μš”.

μ΄ˆκΈ°μ—λŠ” POC(κ°œλ… 증λͺ…) 및 데λͺ¨ 단계이기 λ•Œλ¬Έμ— OpenAI만 μ§€μ›ν–ˆμ§€λ§Œ, AI μ„Έμƒμ—μ„œ κ°€μž₯ 유λͺ…ν•œ λͺ¨λΈμΈ OpenAI 외에도, @wrtnlabs/agentλŠ” 더 넓은 μ‚¬μš©μžμΈ΅μ„ μœ„ν•΄ λ§Žμ€ λͺ¨λΈμ„ 지원해야 ν•΄μš”.

2025λ…„ 4μ›” 30μΌκΉŒμ§€ 더 λ§Žμ€ λͺ¨λΈμ„ 지원할 μ˜ˆμ •μ΄μ—μš”.

0