SDK로 컨텍스트 관리하기

SDK로 컨텍스트 관리하기

LangSmith SDK를 사용해 Context Hub의 에이전트 및 스킬 저장소(repo)를 프로그래매틱하게 푸시, 풀, 나열, 삭제하는 방법을 알려드릴게요.

LangSmith PythonTypeScript SDK를 사용해 Context Hub에이전트 저장소스킬 저장소를 프로그래매틱하게 관리합니다. CI에서 새 버전을 푸시하고, 실행 시 최신 또는 고정된 커밋을 풀해 에이전트에 컨텍스트를 주입하며, 존재 확인, 저장소 나열·검색, 더 이상 필요 없는 것 삭제에 추가 메서드를 사용합니다.

참고: Context Hub 메서드는 langsmith>=0.7.35(Python)와 langsmith>=0.5.23(TypeScript)이 필요합니다.

출처: 문서

본문

설정

  1. 패키지 설치:

    pip install -U langsmith
    
    uv add langsmith
    
    yarn add langsmith
    
  2. 환경 변수 구성. 환경에 LANGSMITH_API_KEY가 이미 설정되어 있다면 이 단계를 건너뜁니다. 그렇지 않으면 LangSmith에서 Settings > API Keys > Create API Key로 하나 만든 뒤 환경 변수로 설정합니다:

    export LANGSMITH_API_KEY="lsv2_..."
    

참고: Python async: 이 페이지에 표시된 모든 메서드는 AsyncClient(langsmith에서 import)에서도 동일한 시그니처로 사용할 수 있습니다 — 각 호출을 await하면 됩니다. TypeScript SDK는 기본적으로 async입니다. 별도 async 클라이언트는 없습니다.

에이전트 푸시

새 에이전트 저장소를 만들거나 기존 저장소의 새 버전을 커밋합니다. 저장소가 아직 없으면 제공한 메타데이터(description, readme, tags, is_public)로 생성됩니다. 이미 존재하면 해당 필드는 명시적으로 전달될 때만 패치됩니다.

메서드는 LangSmith UI의 새 커밋을 가리키는 URL을 반환합니다:

from langsmith import Client
from langsmith.schemas import FileEntry

client = Client()

url = client.push_agent(
    "email-assistant",
    files={
        "AGENTS.md": FileEntry(
            content="You are an email triage assistant.",
        ),
        "tools.json": FileEntry(content='{"tools": []}'),
    },
    description="Triages and drafts replies to incoming email.",
    tags=["email", "productivity"],
    is_public=False,
)
print(url)
import { Client } from "langsmith";

const client = new Client();

const url = await client.pushAgent("email-assistant", {
  files: {
    "AGENTS.md": {
      type: "file",
      content: "You are an email triage assistant.",
    },
    "tools.json": { type: "file", content: '{"tools": []}' },
  },
  description: "Triages and drafts replies to incoming email.",
  tags: ["email", "productivity"],
  isPublic: false,
});
console.log(url);

스킬 푸시

push_agent와 동일한 표면이지만 스킬 저장소에 커밋합니다. 다른 에이전트가 의존할 수 있는 재사용 가능한 기능에 사용하세요:

from langsmith import Client
from langsmith.schemas import FileEntry

client = Client()

url = client.push_skill(
    "deep-research",
    files={
        "SKILL.md": FileEntry(content="Conduct deep multi-step research."),
    },
    description="Multi-step web research with citations.",
    tags=["research"],
)
print(url)
import { Client } from "langsmith";

const client = new Client();

const url = await client.pushSkill("deep-research", {
  files: {
    "SKILL.md": {
      type: "file",
      content: "Conduct deep multi-step research.",
    },
  },
  description: "Multi-step web research with citations.",
  tags: ["research"],
});
console.log(url);

다른 저장소에 연결

파일 내용을 인라인하는 대신 files의 항목은 다른 에이전트 또는 스킬 저장소에 대한 링크가 될 수 있습니다. 이를 통해 저장소 간에 내용을 복제하지 않고 컨텍스트를 구성할 수 있습니다. 예를 들어 공유 스킬에 위임하는 에이전트.

commit_id를 생략하면 LangSmith는 이 커밋을 푸시할 때 해당 저장소의 최신 커밋에 연결합니다. 연결된 저장소가 나중에 업데이트되면 LangSmith는 그 업데이트를 참조하는 부모 저장소에 전파합니다.

from langsmith import Client
from langsmith.schemas import AgentEntry, FileEntry, SkillEntry

client = Client()

url = client.push_agent(
    "email-assistant",
    files={
        "AGENTS.md": FileEntry(content="You are an email triage assistant."),
        # Link to the deep-research skill repo. Omit commit_id to always
        # resolve to the latest version, or pin it for reproducibility.
        "skills/research": SkillEntry(repo_handle="deep-research"),
        # Link to another agent repo.
        "agents/scheduler": AgentEntry(repo_handle="calendar-agent"),
    },
)
print(url)
import { Client } from "langsmith";

const client = new Client();

const url = await client.pushAgent("email-assistant", {
  files: {
    "AGENTS.md": { type: "file", content: "You are an email triage assistant." },
    // Link to the deep-research skill repo. Omit commit_id to always
    // resolve to the latest version, or pin it for reproducibility.
    "skills/research": { type: "skill", repo_handle: "deep-research" },
    // Link to another agent repo.
    "agents/scheduler": { type: "agent", repo_handle: "calendar-agent" },
  },
});
console.log(url);

푸시 파라미터

push_agent / pushAgentpush_skill / pushSkill 모두 다음 파라미터를 수락합니다:

Parameter Type Description
identifier string The repo's identifier.
files dict[str, Entry | None] Map of file path to Entry. Pass None / null to delete a path in this commit.
parent_commit / parentCommit string (optional) Parent commit hash prefix for optimistic concurrency. Must be 8–64 characters when provided. If it doesn't match the latest commit, the API returns a 409 conflict.
description string (optional) Repo description. Set on creation or patched on update.
readme string (optional) Repo readme content.
tags string[] (optional) Repo tags.
is_public / isPublic boolean (optional) Whether the repo is publicly discoverable.

에이전트 풀

에이전트 저장소의 스냅샷을 풀합니다. 기본적으로 최신 커밋이 반환됩니다. 특정 버전을 풀려면 version으로 커밋 해시 또는 태그를 전달하거나(또는 owner/name:version으로 식별자에 포함):

참고: 식별자 형식: identifier 인자는 세 가지 형태를 수락합니다:

  • name: 현재 워크스페이스 소유자에 대해 해석.
  • owner/name: 완전 자격.
  • owner/name:version: 특정 커밋 해시 또는 태그에 고정.

선택적 version 인자는 식별자에 포함된 버전을 재정의합니다. 둘 다 제공되지 않으면 최신 커밋이 반환됩니다.

from langsmith import Client

client = Client()

agent = client.pull_agent("email-assistant")
print(agent.commit_hash)
print(list(agent.files))

# Pull a specific commit.
pinned = client.pull_agent("email-assistant", version="7ca95573")

# Pull a tagged commit (for example, the production tag).
prod = client.pull_agent("email-assistant:production")
import { Client } from "langsmith";

const client = new Client();

const agent = await client.pullAgent("email-assistant");
console.log(agent.commit_hash);
console.log(Object.keys(agent.files));

// Pull a specific commit.
const pinned = await client.pullAgent("email-assistant", {
  version: "7ca95573",
});

// Pull a tagged commit.
const prod = await client.pullAgent("email-assistant:production");

스킬 풀

스킬 저장소의 스냅샷을 풀합니다. pull_agent와 동일하게 동작하지만 SkillContext를 반환합니다:

from langsmith import Client

client = Client()

skill = client.pull_skill("deep-research")
print(skill.files["SKILL.md"].content)
import { Client } from "langsmith";

const client = new Client();

const skill = await client.pullSkill("deep-research");
const skillFile = skill.files["SKILL.md"];
if (skillFile.type === "file") {
  console.log(skillFile.content);
}

풀 파라미터

pull_agent / pullAgentpull_skill / pullSkill 모두 다음 파라미터를 수락합니다:

Parameter Type Description
identifier string The repo's identifier. May include an inline version: owner/name:version.
version string (optional) Commit hash or tag to pull. Overrides any version embedded in the identifier.

pull_agentAgentContext를, pull_skillSkillContext를 반환합니다.

저장소 존재 확인

푸시하거나 풀기 전에 워크스페이스에 에이전트 또는 스킬 저장소가 존재하는지 확인하려면 이 메서드들을 사용하세요:

from langsmith import Client

client = Client()

if client.agent_exists("email-assistant"):
    print("agent already exists")

if not client.skill_exists("deep-research"):
    print("skill not found")
import { Client } from "langsmith";

const client = new Client();

if (await client.agentExists("email-assistant")) {
  console.log("agent already exists");
}

if (!(await client.skillExists("deep-research"))) {
  console.log("skill not found");
}

에이전트와 스킬 나열

두 유형의 저장소를 가시성, 보관 상태, 검색 쿼리의 선택적 필터로 나열합니다:

from langsmith import Client

client = Client()

# Python returns a paginated response.
result = client.list_agents(limit=20, query="email")
for repo in result.repos:
    print(repo.repo_handle)

skills = client.list_skills(is_public=True)
import { Client } from "langsmith";

const client = new Client();

// TypeScript yields one repo at a time, auto-paginating.
for await (const repo of client.listAgents({ query: "email" })) {
  console.log(repo.repo_handle);
}

for await (const skill of client.listSkills({ isPublic: true })) {
  console.log(skill.repo_handle);
}
Parameter Type Description
limit int (Python only) Maximum number of repos to return per page. Defaults to 100.
offset int (Python only) Number of repos to skip. Defaults to 0.
is_public / isPublic boolean (optional) Filter to only public (or only private) repos.
is_archived / isArchived boolean (optional) Filter by archived state. Defaults to False.
query string (optional) Search query across repo handle, owner handle, description, and tags.

참고: Python의 list_agents / list_skills는 명시적 limitoffset이 있는 페이지네이션 응답 객체를 반환합니다. TypeScript의 listAgents / listSkills는 소비할 때 페이지네이션을 자동으로 처리하는 AsyncIterableIterator를 반환합니다.

에이전트 또는 스킬 삭제

경고: 이 작업은 영구적이며 되돌릴 수 없습니다. 저장소를 삭제하면 소유한 자식 파일 저장소도 제거됩니다.

워크스페이스에서 에이전트 또는 스킬 저장소를 삭제합니다:

from langsmith import Client

client = Client()

client.delete_agent("email-assistant")
client.delete_skill("deep-research")
import { Client } from "langsmith";

const client = new Client();

await client.deleteAgent("email-assistant");
await client.deleteSkill("deep-research");

더 알아보기