μλ¦¬μ¦ 3νΈ. 1νΈ νλ€μ€ μμ§λμ΄λ§ μ λ¬Έ · 2νΈ νκ° νλ€μ€ κ΅¬μΆ κ°μ΄λμ μ΄μ΄, μ΄λ² κΈμ νλ€μ€μ κ°μ₯ μ€μ©μ μΈ κ΅¬μ± μμ — λꡬ(Tools) λ₯Ό λ€λ£Ήλλ€.
λ€μ΄κ°λ©°: κ°μ λͺ¨λΈ, λ€λ₯Έ κ²°κ³Ό
κ°μ Claude Opus 4.6μ μ°λ λ νμ΄ μμ΅λλ€. Aνμ μμ΄μ νΈλ 볡μ‘ν 리ν©ν°λ§μ μ²μ² ν΄λ΄κ³ , Bνμ μμ΄μ νΈλ νμΌ κ²½λ‘ νλ λͺ» μ°Ύμ ν€λ§΅λλ€. μ°¨μ΄λ λͺ¨λΈμ΄ μλλΌ λꡬμ μμ΅λλ€.
μμ΄μ νΈ κ°λ°μλ€μ΄ κ°μ₯ νν νλ μ°©κ°μ "LLMμ΄ λλνλκΉ λꡬλ λμΆ© λ§λ€μ΄λ μμμ μΈ κ²"μ΄λΌλ μκ°μ λλ€. νμ€μ μ λ°λμ λλ€. μ’μ λꡬλ λͺ¨νΈν μΆλ‘ λ¬Έμ λ₯Ό κ²°μ μ μΈ ν¨μ νΈμΆλ‘ λ°κΏλλ€. λμ λꡬλ μΈμμμ κ°μ₯ λλν λͺ¨λΈμ‘°μ°¨ λ°λ³΄λ‘ λ§λλλ€.
λꡬ μ€κ³μ μμΉ: μμ΄μ νΈμκ² "λ ν μ μλμ§"κ° μλλΌ "μ΄λ»κ² μ±κ³΅νλμ§"λ₯Ό κ°λ₯΄μ³λΌ.
μ’μ λꡬμ 5κ°μ§ μμΉ

1οΈβ£ λͺ νν κ³μ½ (Clear Contract)
λꡬμ μ΄λ¦, μ€λͺ , νλΌλ―Έν° νμ , λ°ν κ°μ΄ κ·Έ μμ²΄λ‘ μ¬μ© μ€λͺ μκ° λμ΄μΌ ν©λλ€. μμ΄μ νΈλ μ¬λμ²λΌ μ§κ΄μΌλ‘ μ±μ λ£μ§ μμ΅λλ€ — λ¬Έμμ μμΌλ©΄ λͺ¨λ¦ λλ€.
# β λμ μ: λͺ¨νΈν μ΄λ¦, νμ
μμ, 무μμ΄ λμμ€λμ§ λΆλͺ
def run(cmd):
"""Run a command."""
return os.system(cmd)
# β
μ’μ μ: μλκ° λλ¬λλ μ΄λ¦, λͺ
μμ νμ
, ꡬ쑰νλ λ°ν
def search_files(
pattern: str,
directory: str = "/workspace",
max_results: int = 50
) -> SearchResult:
"""νμΌ λ΄μ©μμ μ κ·μ ν¨ν΄μ κ²μν©λλ€.
Args:
pattern: Python re λͺ¨λ λ¬Έλ²μ μ κ·μ
directory: κ²μ μμ λλ ν°λ¦¬ (κΈ°λ³Έ: /workspace)
max_results: λ°νν μ΅λ λ§€μΉ μ
Returns:
SearchResult(matches: list[Match], truncated: bool)
"""
2οΈβ£ μΉμ ν μλ¬ λ©μμ§ (Informative Errors)
μλ¬λ λλ²κΉ μ μμμ μ΄ μλλΌ μμ κ°μ΄λμ¬μΌ ν©λλ€. μμ΄μ νΈλ μλ¬ λ©μμ§λ₯Ό μ½κ³ λ€μ νλμ κ²°μ ν©λλ€.
| μν© | β λμ μλ¬ | β μ’μ μλ¬ |
| νμΌ μμ | FileNotFoundError | File not found: /x/config.yml. Did you mean /x/config.yaml? (3 similar files in directory) |
| κΆν λΆμ‘± | PermissionError: [Errno 13] | Cannot write to /etc/hosts. This path is outside the sandbox. Allowed paths: /workspace, /tmp |
| μλͺ»λ μΈμ | TypeError: expected int | Parameter 'timeout' must be int (seconds), got str "30s". Try: timeout=30 |
ν΅μ¬: μλ¬ λ©μμ§μλ νμ "κ·Έλμ λ νλ©΄ λλμ§"κ° λ€μ΄ μμ΄μΌ ν©λλ€.
3οΈβ£ μ μ ν μΆμν μμ€ (Right Granularity)
λꡬλ λ무 μ μμ€μ΄λ©΄ μμ΄μ νΈκ° λ§€λ² λ³΅μ‘ν μνμ€λ₯Ό 쑰립ν΄μΌ νκ³ , λ무 κ³ μμ€μ΄λ©΄ μ μ°μ±μ΄ μ¬λΌμ§λλ€.
β λ무 μ μμ€: open_file, read_bytes(1024), decode_utf8, close_file
β
μ μ ν μμ€: read_file(path) -> str
β λ무 κ³ μμ€: fix_all_bugs(repo)
β
μ μ ν μμ€: run_tests(), edit_file(), search_code()
κ²½νμΉ: μλ ¨λ μ£Όλμ΄ κ°λ°μκ° ν λ²μ μ§μλ‘ μνν μ μλ λ¨μκ° μ μ ν λꡬ ν¬κΈ°μ λλ€.
4οΈβ£ λ©±λ±μ± (Idempotency)
κ°λ₯ν κ²½μ° κ°μ μ λ ₯ → κ°μ κ²°κ³Όκ° λλλ‘ μ€κ³νμΈμ. μμ΄μ νΈλ μ¬μλκ° μ¦μ΅λλ€.
# β λΉλ©±λ±: λ§€λ² μ νμΌ μμ±
def create_log_file() -> str:
path = f"/logs/{uuid4()}.log"
open(path, 'w').close()
return path
# β
λ©±λ±: κ°μ keyλ‘ νΈμΆνλ©΄ κ°μ κ²°κ³Ό
def get_or_create_log_file(key: str) -> str:
path = f"/logs/{key}.log"
if not os.path.exists(path):
open(path, 'w').close()
return path
5οΈβ£ κ΄μΈ‘ κ°λ₯μ± (Observability)
λꡬ νΈμΆμ νΈλ μ΄μ€μ λ¨λ μ΄λ²€νΈμ λλ€. λλ²κΉ κ°λ₯ν λ‘κ·Έλ₯Ό μμ°μ€λ½κ² λ¨κΈ°λλ‘ μ€κ³νμΈμ.
- νΈμΆ μ νμ μν diffλ₯Ό κΈ°λ‘
- μ€ν¨ μ μ¬ν κ°λ₯ν μ λ ₯ λ€ν
- μ€ν μκ°κ³Ό 리μμ€ μ¬μ©λ
Tool Spec μμ± μ²΄ν¬λ¦¬μ€νΈ
λꡬ νλλ₯Ό λ§λ€ λλ§λ€ λ€μμ μ κ²νμΈμ.
β‘ μ΄λ¦μ΄ λμ¬-λͺ
μ¬ ννμ΄κ³ μλκ° λΆλͺ
νκ°?
β‘ docstringλ§ μ½κ³ νλΌλ―Έν°λ₯Ό μ±μΈ μ μλκ°?
β‘ λͺ¨λ νλΌλ―Έν°μ νμ
ννΈκ° μλκ°?
β‘ μ νμ νλΌλ―Έν°μ ν©λ¦¬μ κΈ°λ³Έκ°μ΄ μλκ°?
β‘ λ°ν νμ
μ΄ κ΅¬μ‘°νλμ΄ μλκ°? (dictκ° μλλΌ TypedDict/dataclass)
β‘ λͺ¨λ μλ¬ κ²½λ‘μ μμ κ°μ΄λκ° λ€μ΄ μλκ°?
β‘ κ°μ μ
λ ₯μΌλ‘ λ λ² νΈμΆν΄λ μμ νκ°?
β‘ νκ΄΄μ μμ
(μμ /μ°κΈ°)μ νμΈ νλκ·Έκ° νμνκ°?
β‘ μ€μ μμ΄μ νΈμκ² "μ΄ λκ΅¬λ‘ Xλ₯Ό ν΄λ΄"λΌκ³ μμΌλ΄€λκ°?
λ§μ§λ§ νλͺ©μ΄ κ°μ₯ μ€μν©λλ€. Tool specμ μ€μ μμ΄μ νΈλ‘ λλΌμ΄λΈ ν μ€νΈνκΈ° μ κΉμ§λ μμ±λ κ² μλλλ€.
μν°ν¨ν΄ κ°€λ¬λ¦¬: νΌν΄μΌ ν λꡬ μ€κ³
π« μν°ν¨ν΄ 1: "λ§λ²μ λꡬ"
def smart_refactor(code: str) -> str:
"""Intelligently refactor code."""
"Intelligent"κ° λ€μ΄κ°λ μκ° μμ¬νμΈμ. λκ΅¬κ° ν΄μΌ ν μΌμ΄ λΆλͺ νν λ μ°λ λ¨μ΄μ λλ€. λμ extract_function, rename_symbol, inline_variableμ²λΌ ꡬ체μ μΈ λ¦¬ν©ν°λ§ μ‘μ μΌλ‘ μͺΌκ°μΈμ.
π« μν°ν¨ν΄ 2: "λ¬Έμμ΄ λΈλ‘ λ°ν"
def get_file_info(path: str) -> str:
return f"File: {path}\nSize: {size}\nModified: {mtime}\n..."
μμ΄μ νΈκ° λ€μ νμ±ν΄μΌ ν©λλ€. ꡬ쑰νλ κ°μ²΄λ₯Ό λ°ννμΈμ.
π« μν°ν¨ν΄ 3: "μ‘°μ©ν μ€ν¨"
def delete_file(path: str) -> bool:
try:
os.remove(path)
return True
except:
return False
μ μ€ν¨νλμ§ λͺ¨λ₯΄λ©΄ μμ ν μ μμ΅λλ€. μμΈλ μΌν€μ§ λ§κ³ ꡬ쑰νν΄μ λλ €μ£ΌμΈμ.
π« μν°ν¨ν΄ 4: "30κ°μ νλΌλ―Έν°"
def run_command(cmd, cwd, env, timeout, shell, stdin, stdout,
stderr, encoding, errors, universal_newlines, ...):
νλΌλ―Έν°κ° 10κ°λ₯Ό λμΌλ©΄ λꡬλ₯Ό μͺΌκ°κ±°λ, μ€μ κ°μ²΄λ‘ κ°μΈμΈμ. μμ΄μ νΈλ 보μ΄λ λͺ¨λ νλΌλ―Έν°λ₯Ό μ±μ°λ €λ κ²½ν₯μ΄ μμ΄ λΆνμν μΈμ§ λΆνκ° μκΉλλ€.
π« μν°ν¨ν΄ 5: "λμ΄ν¬ μ μλ λΆμμ©μ΄ κΈ°λ³Έκ°"
def deploy(service: str, force: bool = True): # ← forceκ° κΈ°λ³Έ True
νκ΄΄μ λμμ λͺ μμ μΌλ‘ μμ²ν λλ§ μΌμ΄λμΌ ν©λλ€. κΈ°λ³Έκ°μ νμ μμ ν μͺ½μΌλ‘.
μ€μ : λμ λꡬ → μ’μ λκ΅¬λ‘ λ¦¬ν©ν°λ§
Before — μ νμ μΈ "λμΆ© λ§λ " λꡬ:
def db_query(q):
"""Run a database query."""
return db.execute(q).fetchall()
λ¬Έμ μ : SQL μΈμ μ μν, μλ¬ μ²λ¦¬ μμ, λ°ν ν¬λ§· λΆλͺ , λμ©λ κ²°κ³Όμ λν λ°©μ΄ μμ.
After — νλ€μ€ κ΄μ μμ λ€μ μ€κ³:
def query_users(
filter_by: Literal["email", "id", "status"],
value: str,
limit: int = 100
) -> QueryResult:
"""users ν
μ΄λΈμ μμ νκ² μ‘°νν©λλ€.
νκ΄΄μ μμ
(INSERT/UPDATE/DELETE)μ λΆκ°λ₯ν©λλ€.
νμν κ²½μ° modify_users λꡬλ₯Ό μ¬μ©νμΈμ.
"""
if limit > 1000:
return QueryResult(
error="limit cannot exceed 1000. Use pagination with cursor parameter.",
suggestion="query_users(filter_by=..., value=..., limit=1000, cursor=...)"
)
try:
rows = db.execute(
"SELECT id, email, status FROM users WHERE {} = %s LIMIT %s".format(filter_by),
(value, limit)
).fetchall()
return QueryResult(rows=rows, count=len(rows), truncated=len(rows) == limit)
except DatabaseError as e:
return QueryResult(
error=f"Query failed: {e}",
suggestion="Check if the users table exists and filter_by column is indexed."
)
λ³νμ λ³Έμ§: μ μ½(SELECTλ§ νμ©, limit μν), λͺ νν κ³μ½(ꡬ쑰νλ λ°ν), μΉμ ν μλ¬(suggestion ν¬ν¨) — 1νΈμ νλ€μ€ μμΉ κ·Έλλ‘μ λλ€.
λ§μΉλ©°: Tool Specμ ν둬ννΈμ μ°μ₯μ΄λ€
λ§μ νμ΄ ν둬ννΈ μμ§λμ΄λ§μ μκ°μ 90%λ₯Ό μ°κ³ , λꡬ μ€κ³μ 10%λ₯Ό μλλ€. μ±μν νμ μ λ°λμ λλ€.
κ·Έ μ΄μ λ κ°λ¨ν©λλ€. ν둬ννΈλ μμ΄μ νΈμκ² "무μμ νλΌ"κ³ λ§νμ§λ§, λꡬλ "μ΄λ»κ² ν μ μλμ§"λ₯Ό μ μν©λλ€. μ’μ λꡬ μμμλ μ§§μ ν둬ννΈλ‘λ μμ΄μ νΈκ° λλ°λ‘ μμ§μ΄κ³ , λμ λꡬ μμμλ μ무리 μ κ΅ν ν둬ννΈλ μ€ν¨λ₯Ό λ§μ μ μμ΅λλ€.
"μμ΄μ νΈκ° λ©μ²ν΄ 보μΈλ€λ©΄, λ¨Όμ μμ¬ν΄μΌ ν 건 λͺ¨λΈμ΄ μλλΌ λΉμ μ΄ λ§λ λꡬλ€."
μ΄λ‘μ¨ νλ€μ€ μμ§λμ΄λ§ 3λΆμμ λ§μΉ©λλ€. 1νΈμμ ν° κ·Έλ¦Όμ κ·Έλ¦¬κ³ , 2νΈμμ μΈ‘μ 체κ³λ₯Ό μΈμ°κ³ , 3νΈμμ κ°μ₯ μ€μ©μ μΈ λ λ²μΈ λꡬ μ€κ³λ₯Ό λ€λ€μ΅λλ€. μΈ νΈ λͺ¨λ ν λ¬Έμ₯μΌλ‘ μμ½νλ©΄ μ΄λ μ΅λλ€.
"μμ΄μ νΈλ₯Ό λ λλνκ² λ§λ€λ € νμ§ λ§κ³ , κ·Έ μ£Όλ³μ λ λ¨λ¨νκ² λ§λ€μ΄λΌ."
λ€μ μ리μ¦μμλ μ€μ μΌμ΄μ€ μ€ν°λ — Claude Code, Devin, Cursorκ° κ°μ μ΄λ€ νλ€μ€ ν¨ν΄μ μ ννλμ§ λΉκ΅ λΆμ — λ‘ μ°Ύμλ΅κ² μ΅λλ€.
#AIμμ΄μ νΈ #ToolDesign #LLMOps #AgentInfrastructure #νλ€μ€μμ§λμ΄λ§