๋ฐฐ๊ฒฝ

๋๊ณ ๊ฐ ์ฑ๋ด ๊ฐ๋ฐ ๋น์ hallucination ์ ๊ดํ ๊ธฐ์ค์ด ์๊ฒฉํด ๋ชจ๋ฅด๋ ๋ต๋ณ์ ๋ชจ๋ฅธ๋ค๊ณ ๋ต๋ณํ๊ณ ์๋ด์ ์ฐ๊ฒฐ๋ก ๋๋ฆฌ๋ ๋ก์ง์ผ๋ก ์ค๊ณ๋์ด ์์์ต๋๋ค.
๋๋ฌธ์ ๊ณ ๊ฐ์ด chain ๊ตฌ์กฐ์์ ์กฐ๊ธ๋ง ์์์ ์ด๊ธ๋๋ ํ๋์ ํ๋ฉด ๋ต๋ณ์ ํํผ(๋ชจ๋ฅด๊ฒ ๋ค ๋ต๋ณ ํ ์๋ด์ ์ฐ๊ฒฐ) ํด ์๋ด ๋ง์กฑ๋๊ฐ ๋จ์ด์ง๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋๋ฐ์, ๊ทธ๋์ ์ง๋ฌธ์ ์ ์ฐํ๊ฒ ๋์ํ๊ธฐ ์ํด ์ฒด์ธ๊ตฌ์กฐ์์ ReAct agent ๋ก ๋ง์ด๊ทธ๋ ์ด์ ํ๊ธฐ๋ก ํ์ต๋๋ค.
์ฒด์ธ์ ๋๋ฌํ ๋์๋ ์ ํด์ง DTO ๋ฅผ ์ง์ผ์ผ ํ๋๋ฐ ์ฒด์ธ์ด ์๋ Tool ๊น์ง ๋๋ฌํ ๋์๋ ์ด๋ฏธ LLM ์ ์ํด DTO ๊ฐ ๋ญ๊ฐ์ ธ Tool ์ ์ธ์๋ฅผ ์ ๋ฌํ์ง ๋ชปํ๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค. ์ด๋ ํ๋กฌํํธ๋ก๋ง ์ถ๋ ฅ์ ์ ์ดํ์๋๋ฐ, ๋ต๋ณ์ ์ํ๋ ๊ฒ ์ฒ๋ผ ๋ณด์์ง๋ง Langsmith ๋ก agent tool calling์ ์ถ์ ํ ๊ฒฐ๊ณผ ๋ด๋ถ์ ์ผ๋ก๋ ์ผ๋ถ ๋ฐ์ดํฐ๋ค์ ๋๋ฝ๋๊ณ calling ์ ๋ฐ๋ณต ํ๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค. ์๋ง ๊ฐ๋ ฅํ ํ๋กฌํํธ๋ฅผ ์ฐ๋ฉด ์ข ๋์์ก๊ฒ ์ง๋ง ๊ฒฐ๊ณผ์ ์ผ๋ก ์ด ๋ฌธ์ ๋ ์๋ต์๊ฐ ์ง์ฐ๊ณผ, ํ ํฐ ๋น์ฉ ์ฆ๊ฐ๋ก ์ด์ด์ก์ต๋๋ค. ํ์ง๋ง ๊ณ ๊ฐ๋ฐ์๊ณผ ์ค์ ๋น์ง๋์ค ๋ฌธ์ ํด๊ฒฐ์๋ ๋ฌธ์ ๊ฐ ์์๊ธฐ ๋๋ฌธ์ ์ฐ์ ์์์ ๋ฐ๋ ค ๊ธฐ์ ๋ถ์ฑ๋ก ๋จ๊ฒ๋์์ต๋๋ค.
์ง๊ธ ํ์ฌ์ ์ค๊ฒ ๋๋ฉด์ structured output ์ ๊ดํ ๊ฐ๋ ์ ์ ํ๊ฒ ๋๊ณ ์ ๋ขฐ๊ฐ๋ฅํ์ง, ์ค์ ๋๊ณ ๊ฐ ์ ๋ฌด์์ ์ฌ์ฉํ ๋งํผ ์ ๋ขฐ๋ ์๋์ง ํ์ธํด๋ณด๋ ค๊ณ ํฉ๋๋ค.
Structured Output ์ ์๋์๋ฆฌ
๋จผ์ structured output ์ LLM ์ output ์ Json ์ด๋ Pydantic ํน์ dataclass ๊ฐ์ ํํ๋ก ๋ฐ์ ์ ์๋ ๊ธฐ๋ฅ์ ๋๋ค. ๋ํ ์๋ฌ์ฒ๋ฆฌ๊ฐ ๊ฐ๋ฅํ๋ฐ, ๋ชจ๋ธ์ด ๋ฒ์๋ฅผ ์ด๊ธ๋๊ฒ ์๋ตํ๊ฑฐ๋ ์๋ฃํ์ ํ๋ฆฌ๊ฒ ๋งค์นญํ๋ค๋ฉด validation error ๋ฅผ ๋ง๋ค ์ ์์ด ์๋ฌ๋ฉ์์ง ์ ๋๊ฐ ๊ฐ๋ฅํฉ๋๋ค.
์ด๊ฒ์ ์ ํ์ฉํ๋ฉด ํน์ ๊ฒฝ์ฐ์๋ง (format ์ด ๋ง์ง ์๋ ๊ฒฝ์ฐ, ํ๋์ ๊ฐ์ด ์๋ชป ๋ค์ด๊ฐ๋ ๊ฒฝ์ฐ) Error๋ฅผ ๋ฐ์์ํฌ ์ ์์ต๋๋ค. ์ผ๋ฐ์ ์ผ๋ก๋ ์ฌ์๋๋ฅผ ํ๊ฒ๋๊ณ ์ฌ์๋ ํ๋ ๊ฒฝ์ฐ ๋๋ถ๋ถ ์ ๋งค์นญ์ด ๋ฉ๋๋ค. ๊ฐ์ฅ ์น๋ช ์ ์ธ ๊ฒ์ structure ์ ๋ง๊ฒ ๋ฐ์ดํฐ๋ฅผ ๋ฃ๊ธฐ๋ ํ์ง๋ง, ๊ทธ ๊ฐ์ด ์ค์ ๋ก ๋ง๋์ง๋ ๋ณด์ฅํ์ง ์๋ ๋ค๋ ๊ฒ์ ๊ณ ๋ คํด์ผํฉ๋๋ค.
์๋ ์์
- ๋ชจ๋ธ๊ณผ ์คํค๋ง๋ฅผ ์ ๋ ฅ๋ฐ๋๋ค.
- langchain ๋ด๋ถ์์ ์ ๋ต์ ์ ํํจ
- toolcalling strategy : ๋ชจ๋ธ์ด structured output ์ง์ํ์ง ์๋ ๊ฒฝ์ฐ
- langchain ์ด ๋๊ตฌํธ์ถ JSON ํํ๋ก ๋ฐํํ๊ณ langchain ์์ ํ์ฑํด์ ์คํค๋ง์ ๋ง๋ ๊ฐ์ฒด๋ก ๋ณํํ๋๋ฐ ๋๊ตฌ ํธ์ถ ์์ฒด๊ฐ ํ ํฐ์ ๋ ์ฐ๊ธฐ๋๋ฌธ์ ๋น์ฉ์ฆ๊ฐ/์๋ต์๊ฐ ์ฆ๊ฐ๊ฐ ๋ฐ์ํฉ๋๋ค https://platform.openai.com/docs/guides/structured-outputs
- provider strategy : ๋ชจ๋ธ์ด structured output ์ง์ํ๋ ๊ฒฝ์ฐ
- langchain or agent ์๋ต ์์ฑ
- ๊ฒฐ๊ณผ๋ฌผ ์ ํจ์ฑ ๊ฒ์ฆ : ์คํค๋ง์ ๋ง๊ฒ ํ์ฑ์ด ๋์๋์ง Pydantic ์ด๋ json ๊ธฐ๋ฐ ํ์ ์ฌ
- ํ์ฑ ์ฑ๊ณตํ๋ฉด structured_response ์ ๋ฃ์ด์ ์ต์ข ๊ฒฐ๊ณผ ๋ฐํ
์คํค๋ง์ ๋ ฅ / ์ ๋ต์ ํ
์คํค๋ง๋ฅผ ์ ๋ ฅ๋ฐ๋ ๋ถ๋ถ๋ถํฐ ์ดํด๋ณด๊ฒ ์ต๋๋ค. ์๋์ ์์ ๊ฐ ์์ต๋๋ค.
Pydantic ์คํค๋ง๋ก ์์๋ฅผ ์์ฑํ๋๋ฐ with_structured_output ๋ฉ์๋์ ์ธ์๋ก Pydantic ์ด ์คํค๋ง๋ก ๋์ด๊ฐ๊ฒ ๋ฉ๋๋ค.
class ReviewSummary(BaseModel):
title: str = Field(..., description="๋ฆฌ๋ทฐ ์ ๋ชฉ")
sentiment: str = Field(..., description="๊ธ์ /๋ถ์ /์ค๋ฆฝ ์ค ํ๋")
score: float = Field(..., description="0~1 ์ฌ์ด์ ๊ฐ์ ์ ์")
from langchain_openai import ChatOpenAI
# OpenAI API ๋๋ vLLM OpenAI ์๋ฒ URL๋ก ์๋ ์ฐ๊ฒฐ๋จ
model = ChatOpenAI(
model="gpt-4o-mini", # ์๋ฌด ๋ชจ๋ธ ๊ฐ๋ฅ
temperature=0
)
structured_model = model.with_structured_output(ReviewSummary)
result = structured_model.invoke(user_input)
print(result)
print(type(result))
------------
title='์ํ ๋ฆฌ๋ทฐ ์์ฝ'
sentiment='๋ถ์ '
score=0.15
<class '__main__.ReviewSummary'>
------------
structured output ์ง์ํ๋ ์ผ๋ถ ๋ชจ๋ธ๋ค์ ์๋์ฒ๋ผ ๋ฒค๋์ฌ๊ฐ ์ง์ํ๋ ์คํค๋ง์ ๋ง๊ฒ ๋ณํํ๋ ๋๊ตฌ๋ง์ bind ํ ์ฑ๋ก ๋๋๊ฒ ๋ฉ๋๋ค.
class ChatAnthropic(BaseChatModel):
#----------์ค๋ต----------
def with_structured_output():
#----------์ค๋ต----------
if method == "function_calling":
formatted_tool = **convert_to_anthropic_tool(schema)**
tool_name = formatted_tool["name"]
if self.thinking is not None and self.thinking.get("type") == "enabled":
llm = self._get_llm_for_structured_output_when_thinking_is_enabled(
schema,
formatted_tool,
)
else:
llm = self.bind_tools(
[schema],
tool_choice=tool_name,
ls_structured_output_format={
"kwargs": {"method": "function_calling"},
"schema": formatted_tool,
},
)
@dataclass(init=False)
class ProviderStrategy(Generic[SchemaT]):
"""Use the model provider's native structured output method."""
schema: type[SchemaT]
"""Schema for native mode."""
schema_spec: _SchemaSpec[SchemaT]
"""Schema spec for native mode."""
def __init__(
self,
schema: type[SchemaT],
) -> None:
"""Initialize ProviderStrategy with schema."""
self.schema = schema
self.schema_spec = _SchemaSpec(schema)
๊ทธ๋ฆฌ๊ณ Provider ์ ์๋ ๋ชจ๋ธ์ ToolStrategy ๋ฅผ ์ฌ์ฉํ๊ฒ ๋๋๋ฐ vllm ๊ฐ์ ๋ก์ปฌ ์๋น ํ๋ ์์ํฌ์์ ์๋์ํค๋ ๋ชจ๋ธ๋ค์ด ๋์ฒด๋ก ๊ทธ๋ฌํฉ๋๋ค.
class ChatOllama(BaseChatModel):
#---์ค๋ต----
def with_structurd_output():
#---์ค๋ต----
if is_pydantic_schema:
schema = cast("TypeBaseModel", schema)
if issubclass(schema, BaseModelV1):
response_format = schema.schema()
else:
response_format = schema.model_json_schema()
llm = self.bind(
format=response_format,
ls_structured_output_format={
"kwargs": {"method": method},
"schema": schema,
},
)
@dataclass(init=False)
class ToolStrategy(Generic[SchemaT]):
"""Use a tool calling strategy for model responses."""
schema: type[SchemaT]
"""Schema for the tool calls."""
schema_specs: list[_SchemaSpec[SchemaT]]
"""Schema specs for the tool calls."""
tool_message_content: str | None
"""The content of the tool message to be returned when the model calls
an artificial structured output tool."""
handle_errors: (
bool | str | type[Exception] | tuple[type[Exception], ...] | Callable[[Exception], str]
)
ToolStrategy ๋ bind ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ ๋ฌ๋๋ธ ๊ฐ์ฒด์ ์ ๊ทผํ๊ณ ๊ทธ ์ง์ ์ ํด์ฝ๋ง์ ํ๊ฒ ๋ฉ๋๋ค.
์ฌ๋์ด ๊ฐ์ ํ์ฌ ๋ฒค๋์ฌ์ ํด์ ํธ์ถํ ์ ์์ง๋ง ์ ๋ต์ ํ์ ๊ฒฐ์ ์ ์ผ๋ก ํฐ ์ฐจ์ด๋ ๊ฒฐ๊ตญ with_structured_output ํจ์๋ฅผ ํธ์ถํ ๋ ๊ธฐ๋ณธ์ผ๋ก ์ ํ๋๋ method ๊ฐ ๋ค๋ฅด๋ค๋ ๊ฒ์ ๋๋ค.
๋ชจ๋ธ์ด structured output ์ง์ํ์ง ์๋ ๊ฒฝ์ฐ
def with_structured_output(
self,
schema: dict | type,
*,
method: Literal["function_calling", "json_mode", "json_schema"] = "json_schema",
include_raw: bool = False,
**kwargs: Any,
) -> Runnable[LanguageModelInput, dict | BaseModel]:
r"""Model wrapper that returns outputs formatted to match the
structured output ์ง์ํ๋ ๊ฒฝ์ฐ
def with_structured_output(
self,
schema: dict | type,
*,
include_raw: bool = False,
method: Literal["function_calling", "json_schema"] = "function_calling",
**kwargs: Any,
) -> Runnable[LanguageModelInput, dict | BaseModel]:
"""Model wrapper that returns outputs formatted to match the given schema.
structured output ์ ์ง์ํ๋ ๊ฒฝ์ฐ์๋ method ๊ฐ function_calling ์ผ๋ก api ์ ๊ณต ๋ฒค๋์ฌ์ function calling ํํ๋ก ์ฒ๋ฆฌํ๊ณ
if method == "function_calling":
formatted_tool = convert_to_anthropic_tool(schema)
tool_name = formatted_tool["name"]
if self.thinking is not None and self.thinking.get("type") == "enabled":
llm = self._get_llm_for_structured_output_when_thinking_is_enabled(
schema,
formatted_tool,
)
else:
llm = self.bind_tools(
[schema],
tool_choice=tool_name,
ls_structured_output_format={
"kwargs": {"method": "function_calling"},
"schema": formatted_tool,
},
)
bind_tools ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๊ณ ์์ต๋๋ค.
๋ฐ๋์ ๊ฒฝ์ฐ์๋ json_schema ๊ฐ ๊ธฐ๋ณธ ์ ํ๋์ด bind ๋ฉ์๋๋ฅผ ์ฌ์ฉํด์ tool calling ํํ๊ฐ ์๋๋ผ runnable sequence ์ ์๋ก์ด ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด ํธ์ถ ์ต์ ์ ์ฌ์ ์๋ ๊ฒ์ ๋๋ค.
elif method == "json_schema":
if schema is None:
msg = (
"schema must be specified when method is not 'json_mode'. "
"Received None."
)
raise ValueError(msg)
if is_pydantic_schema:
schema = cast("TypeBaseModel", schema)
if issubclass(schema, BaseModelV1):
response_format = schema.schema()
else:
response_format = schema.model_json_schema()
llm = self.bind(
format=response_format,
ls_structured_output_format={
"kwargs": {"method": method},
"schema": schema,
},
)
output_parser = PydanticOutputParser(pydantic_object=schema) # type: ignore[arg-type]
##bind example
"""
Example:
```python
from langchain_ollama import ChatOllama
from langchain_core.output_parsers import StrOutputParser
model = ChatOllama(model="llama3.1")
# Without bind
chain = model | StrOutputParser()
chain.invoke("Repeat quoted words exactly: 'One two three four five.'")
# Output is 'One two three four five.'
# With bind
chain = model.bind(stop=["three"]) | StrOutputParser()
chain.invoke("Repeat quoted words exactly: 'One two three four five.'")
# Output is 'One two'
"""
์์ฒด์ ์ผ๋ก response_format ์ ์ธํ ํ๊ณ ์๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค. ์ด๋ ๊ฒ ์คํค๋ง๋ฅผ ์ ๋ ฅ๋ฐ๊ณ ์ ๋ต์ ์ ํํ๋ ๋ก์ง์ ๊ฑฐ์น๊ฒ ๋ฉ๋๋ค.
์ด์ ์ ๋ต๋ณ๋ก ์ด๋ป๊ฒ structured output ์ ๋ง๋ค์ด ๋ด๋์ง ์ดํด๋ณด๊ฒ ์ต๋๋ค.
์ ๋ต๋ณ ์๋ต์์ฑ ๊ณผ์
- ToolcallingStrategy
langchain ์ schema_spec ์ ์ด์ฉํด์ fake tool schema ๋ฅผ ์์ฑํ๊ณ ์ด fake tool ์ด๋ฆ์ด structured output ๊ฐ์ ํํ๋ก ๋ชจ๋ธ์๊ฒ ์ ๋ฌ๋ฉ๋๋ค. ๊ทธ๋ผ ๋ชจ๋ธ์ ์๋์ ๊ฐ์ ํํ๋ก ์๋ตํฉ๋๋ค.์ด์ json ์ ํ์ฑํด์ pydantic ์ด๋ dataclass ๊ฒ์ฆ์ ํ๊ณ ์คํจํ๋ฉด Validation Error ์ ๋ฑ์ด๋ด๊ณ ๋ค์ ๋ชจ๋ธ์๊ฒ ์์ฒญ์ ํ๊ฒ ๋ฉ๋๋ค.class ToolStrategy(Generic[SchemaT]): schema: type[SchemaT] schema_specs: list[_SchemaSpec[SchemaT]] tool_message_content: str | None handle_errors: bool | ...
์ด error ์ดํ ๋ค์ ๋ชจ๋ธ์๊ฒ ์์ฒญํ๋ ๊ณผ์ ์์ ๋ง์ฝ ๋ชจ๋ ์ปจํ ์คํธ๋ฅผ ํฌํจํ ์ฒด์ธ์ด๋ ๋ ธ๋๋ผ๋ฉด ์ ๋ง ๋ง์ ํ ํฐ์ด ๋ญ๋น๋๊ณ , ์๋ต์๊ฐ์ด ์ง์ฐ๋๊ฒ ๋ฉ๋๋ค.๋ชจ๋ธ์ด native ํ๊ฒ structured output ์ ์ง์ํ์ง ์๋ ๊ฒฝ์ฐ Toolcalling strategy ๋ฅผ ์ ํํ๊ฒ ๋ฉ๋๋ค.{ "tool": "structured_output", "arguments": { "title": "some text", "score": 0.82 } } โ - ProviderStrategy
langchain ์ ์คํค๋ง๋ง ๊ทธ๋๋ก ๋ชจ๋ธ์๊ฒ ์ ๋ฌํ๊ณ ์๋ต๋ฐ์์ ํ์ฑ๋ง ์ํํฉ๋๋ค. openAI ์ anthropic gemini ์ ์๋ต์ ์์ ์ ์ผ๋ก ๋ค์ ๋ชจ๋ธ์๊ฒ ์์ฒญํ๋ ๊ฒฝ์ฐ๊ฐ ์ ์ต๋๋ค. ๋ชจ๋ธ์ด ์์ฒด์ ์ผ๋ก structured output ์ ์ง์ํ๋ ๊ฒฝ์ฐ์ ๋๋ค. ์ด๋ langchain ์ ๊ฐ ๋ฒค๋์ฌ์ ๋ง๋ ํํ๋ก ๋ณํ/ํ์ฑ์ ์ํํฉ๋๋ค.@dataclass(init=False) class ProviderStrategy(Generic[SchemaT]): """Use the model provider's native structured output method.""" schema: type[SchemaT] """Schema for native mode.""" schema_spec: _SchemaSpec[SchemaT] """Schema spec for native mode."""
Structured Output ํ ์คํธ
openai ์ structured otutput์ ์๋์ ์ฅ์ ์ ๊ฐ๊ณ ์๋๋ฐ, ํนํ ์ธ๋ฒ์งธ ๋ถ๋ถ์ด ์ธ์์ ์ด์์ต๋๋ค. ์ด์ ์ฑ๋ด ๊ฐ๋ฐ๋น์ ๋ ๊ฑฐ์๋ ์ด ๊ธฐ๋ฅ์ ๋ชฐ๋๋๊ฒ์ธ์ง ํ๋กฌํํธ๋ก ์ถ๋ ฅ์ ๊ฐ์ ํ๊ณ ์์๋๋ฐ, structured output ์ ์ฌ์ฉํ๋ฉดformat ์ ์งํค๊ธฐ ์ํด์ ๊ฐ๋ ฅํ ํ๋กฌํํธ๋ฅผ ํ์ง ์์๋ ๋๊ธฐ ๋๋ฌธ์ ๋๋ค.

structured output ์ด ์ธ์ ์ง์๋๋๋ก ํฌํจ๋์๋์ง ํ์ธํด๋ณด๋ Toolcalling strategy ๋ 2023๋ ์คํ๋ฐ์ฏค ๊ทธ๋ฆฌ๊ณ ProviderStrategy๋ 2024๋ 8์ 6์ผ gpt-4o ๋ชจ๋ธ์ ์์์ผ๋ก openai ๊ฐ ๊ฐ์ฅ๋จผ์ ์ง์ํ์ต๋๋ค. ๊ทธ ๋ค์ anthropic ๊ณผ gemini ๊ฐ ์ฐจ๋ก๋ก ์ง์ํ๊ธฐ ์์ํ์ต๋๋ค.
langchain ์คํ ์ด๋ธ๋ฒ์ ์ด 2024๋ 1์์ ๋ฐฐํฌ๋๊ณ , ๊ทธ๋๋ถํฐ ์ฑ๋ด ๋ ๊ฑฐ์๊ฐ ๊ฐ๋ฐ๋๊ธฐ ์์ํ์ผ๋ ์ต์ด ์์คํ ๊ฐ๋ฐ ์ดํ ์ ๊ธฐ์ ์ถ์ ์ 1๋ 6๊ฐ์ ๊ฐ๊น์ด ํ์ง ์์๋ค๋ ๊ฒ์ ์ ์ ์์์ต๋๋ค.
๊ทธ๋ผ ์ค์ ๋ก ํ๋กฌํํธ๋ก ์ถ๋ ฅ์ ๊ฐ์ ํ๋ ๊ฒ๊ณผ structured output ์ผ๋ก output ํํ๋ฅผ ํ์ฑํ๋ ๊ฒ์ด ์ผ๋ง๋ ๋ค๋ฅธ์ง ํ์ธํด๋ณด๊ฒ ์ต๋๋ค.
ํ๋กฌํํธ ์์ง๋์ด๋ง์ผ๋ก output format ๊ฐ์ ํ ์คํธ

Structured Output Pydantic ํ๋ผ๋ฏธํฐ ์ ๋ฌ ํ ์คํธ
structured output ์ ๊ณต์๋ฌธ์์์๋ “structured output ์ ์ค์ํ ์ ์๋ค” , “์ต๋ํ ์คํค๋ง์ ๋ํ ์ ๋ณด๋ฅผ ์ ์์ฑํด๋ผ” ๋ผ๊ณ ๋งํ๊ณ ์์ต๋๋ค. ๊ทธ๋์ ๋ฐ๋ผ์ LLM ์ด ๋ถ๋ฅํ๊ฑฐ๋, ์ด๋ค ํฌ๋งท์ ์ ๋ ฅ์ ๊ฐ์ ํด์ผํ๋ค๋ฉด Pydantic ์ฌ์ฉํ๊ธฐ๋ฅผ ๊ถ์ฅํฉ๋๋ค.

๊ฐ๋จํ ํ๋กฌํํธ์ ๊ฒฝ์ฐ ๋๋ค ์ ๋ฑ์ด๋ด๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค.
๊ทธ๋ผ ์ค๋ฌด์์ ๋ฐ์ํ๋ ์๋๋ฆฌ์ค๋ฅผ ์๊ฐํด๋ณด๊ณ ํ ์คํธ ํด๋ณด๊ฒ ์ต๋๋ค. LLM ์ด ์ญ์ทจํ๊ฒ ๋ ๋ฐ์ดํฐ๋ ์๊ฐ๋ณด๋ค ๋ณต์กํ ์ ์์ต๋๋ค. ํนํ ์ฌ๋ฌ๊ฐ DTO ๊ฐ ์์ฌ์๋ ๊ฒฝ์ฐ DTO ๊ฐ ๊ธฐํ๊ธ์์ ์ผ๋ก ์ปค์ง๊ฒ ๋๋๋ฐ์ 3๊ฐ์ DTO๋ฅผ ์์๋ก ํ์ฌ json ํ์ ์ด ์๋ ์์ฐ์ด๋ก ๋ฐ์ดํฐ๋ฅผ ์ฃผ์์ ๋ ์ ํ์ฑํ๋์ง ํ์ธํด๋ณด๊ฒ ์ต๋๋ค.
class Gender(str, Enum):
male = "male"
female = "female"
other = "other"
class Address(BaseModel):
street: str = Field(description="Street name and number")
city: str = Field(description="City name")
state: str = Field(description="State/Province")
postal_code: str = Field(description="Postal/ZIP code")
country: str = Field(description="Country name")
class UserProfile(BaseModel):
name: str = Field(description="The user's full name")
age: int = Field(description="The user's age")
gender: Gender = Field(description="The user's gender")
email: str = Field(description="The user's email address")
phone_number: str = Field(description="The user's primary phone number")
addresses: List[Address] = Field(description="List of user's addresses")
date_of_birth: date = Field(description="The user's birth date")
interests: List[str] = Field(default_factory=list, description="List of user's interests")
is_active: bool = Field(default=True, description="Whether the user is active")
bio: Optional[str] = Field(default=None, description="Short biography of the user")
friends_ids: Optional[List[int]] = Field(default_factory=list, description="List of friend's user IDs")
account_created: date = Field(description="Date when the user account was created")
Input์ ์๋์ ๊ฐ์ด ํ๋ค.
๋ฐ์คํธ๋ผ๋ ์ฌ์ฉ์์ ์ ๋ณด๋ฅผ JSON์ผ๋ก ๋ง๋ค์ด์ฃผ์ธ์.
๋์ด๋ 24์ธ, ๋จ์ฑ์ด๋ฉฐ, ์ด๋ฉ์ผ์ park.junho@example.com,
์ ํ๋ฒํธ๋ 010-1111-2222์
๋๋ค.
์ฃผ์๋ ๋ถ์ฐ ํด์ด๋๊ตฌ ๋ง๋ฆฐ์ํฐ 5๋ฒ์ง์ ๋๊ตฌ ์์ฑ๊ตฌ ๋ฒ์ด๋ก 88๋ฒ์ง์
๋๋ค.
์์ผ์ 2000๋
12์ 1์ผ, ๊ด์ฌ์ฌ๋ ๊ฒ์, ์ฝ๋ฉ, ์ถ๊ตฌ์
๋๋ค.
์ฌ์ฉ์๋ ๋นํ์ฑ ์ํ(False)์ด๋ฉฐ, ์๊ธฐ์๊ฐ๋ ๊ฒ์ ๊ฐ๋ฐ์๋ฅผ ๊ฟ๊พธ๊ณ ์๋ ๋ํ์์
๋๋ค.
์น๊ตฌ ID๋ 301, 302, ๊ณ์ ์์ฑ์ผ์ 2021๋
6์ 20์ผ์
๋๋ค.
๋ณต์กํ ๊ตฌ์กฐ์ ๋ฐ์ดํฐ๋ฅผ ํ๋กฌํํธ๋ก ํํ๋ฅผ ๊ฐ์ ํ ๊ฒ๋ ๋์ฒด๋ก ์ ํ์ฑํ๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค. ํ์ง๋ง ๊ฒฐ๊ณผ๋ฌผ์ ๋ณด๋ฉด postal code์ ํฌํจ๋์ด ์์ง ์์ ๋ฐ์ดํฐ๊ฐ ๋ค์ด์์ต๋๋ค.

๊ทธ๋ ๋ค๋ฉด structured output ์ ์ฌ์ฉํ ์ฟผ๋ฆฌ๋ ์ด๋จ๊น์?

์ฐฌ๊ฐ์ง๋ก ์ ํ์ฑํฉ๋๋ค. DTO๊ฐ ๋ณต์กํด์ง๋๋ผ๋ ์ข์ ๋ชจ๋ธ์ธ ๊ฒฝ์ฐ์๋ ๊ฑฐ์ ๋ค ํ์ฑ์ ํด๋ด๋ ๊ฒ์ ๋ณผ ์ ์์์ต๋๋ค. ํ์ง๋ง ํ๊ฐ์ง ์ฐจ์ด์ ์ด ๋ฐ์ํ๋๋ฐ์ with structured output ๋ฉ์๋๋ postal_code ๊ฐ ๋น์นธ์ธ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค. ํ์ง๋ง prompt ๋ก ๊ฐ์ ํ ๊ฒฝ์ฐ์๋ ์ค์ ๋ฐ์ดํฐ์ postal code ๊ฐ ์์์๋ ๋ถ๊ตฌํ๊ณ dummy ๋ฐ์ดํฐ๊ฐ ๋ค์ด๊ฐ์๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค.
Structured Outpu๋ ์ ๋ขฐํ ์ ์์๊น
์ง๊ธ๊น์ง ๋ด์ฉ์ผ๋ก structured output ์ ์ฌ์ฉํ ๋ ์กฐ๊ธ ๋ ์ ํ์ฑ์ด ๋๋ ๊ฒ์ ๋ณผ ์ ์์๋๋ฐ์, ํจ์ ๊ฐ๊ฒฐํ๊ณ ์ฑ๋ฅ์ด ์ข์ผ๋ ๋ฐ๋ผ์ ํ๋กฌํํธ๋ก ๊ฐ์ ํ๋ ๊ฒ๋ณด๋ค structured output ๊ธฐ๋ฅ์ ์ฌ์ฉํ๋๊ฒ์ด ํจ์ฌ ๋ ์ ๋ฆฌํ ๊ฒ ๊ฐ์ต๋๋ค.
2025๋ 12์ 2์ผ ๊ธฐ์ค์ผ๋ก
AI Leaderboards 2025 - Compare All AI Models
Comprehensive AI leaderboards comparing LLM, TTS, STT, video, image, and embedding models. Compare performance, pricing, and capabilities across all AI modalities.
llm-stats.com
์คํ์ ์ฌ์ฉํ gpt-4o ๋ชจ๋ธ๋ณด๋ค ๊ด์ฐฎ์ ๋ก์ปฌ ๋ชจ๋ธ๋ค์ด ๋ง์๋ฐ์ 30B ์ ๋ ๋๋ ๋ชจ๋ธ๋ค์ ์ฌ์ฉํ๋ค๋ฉด ๋ก์ปฌ์์ ๋๋ฆฌ๋ ๋ชจ๋ธ๋ค๋ ์ ์๋ํ ๊ฒ์ด๋ผ ์์ํฉ๋๋ค. ๊ทธ๋์ ์ฑ๋ฅ์ธก๋ฉด์์ ์ด๋ค ์ ๋ต์ด ๋ ์ฐ์ํ๋ค๋ ๊ฒ์ ํฐ ์๋ฏธ๊ฐ ์์ด๋ณด์ ๋๋ค.
ํ์ง๋ง ๊ทธ๋ผ์๋ ๋ถ๊ตฌํ๊ณ Toolcalling Strategy ์ ๊ฒฝ์ฐ๋ retry ๊ฐ ์์ฃผ ๋ฐ์ํ ์ ์๊ธฐ ๋๋ฌธ์ structured output ์ง์๋๋ api ๋ฅผ ์ฌ์ฉํ ์ ์๋ ํ๊ฒฝ์ด๋ผ๋ฉด ProviderStrategy ๋ฅผ ์ฌ์ฉํ ์ ์๋ ๋ฐฉ๋ฒ์ผ๋ก ์๋ํด์ผ ํ๋ค๊ณ ์๊ฐํฉ๋๋ค.
์ด์ ์ถ๋ ฅ ๊ตฌ์กฐ๋ฅผ ํ๋กฌํํธ๋ก ๊ฐ์ ํ๋ ๊ฒ๋ณด๋ค structured output ์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข๋ค๋ ๊ฒ์ ์๊ฒ ๋์์ต๋๋ค. ๊ทธ๋ผ ๊ฒฐ์ ์ ์ผ๋ก structured output ์ ์ ๋ขฐํ ์ ์์๊น? ์ ๋ํ ๋ต์ ๊ตฌํด์ผํ๋๋ฐ, ์ต๊ทผ ์๋์ ๊ธ์ ์ฝ๊ฒ ๋์์ต๋๋ค.
https://www.philschmid.de/why-engineers-struggle-building-agents
Why (Senior) Engineers Struggle to Build AI Agents
Traditional software engineering is deterministic, while AI agents operate probabilistically. This fundamental difference creates challenges for engineers accustomed to strict interfaces and predictable outcomes.
www.philschmid.de
์๋์ด ๊ฐ๋ฐ์๋ค์ด ์ฃผ๋์ด ๊ฐ๋ฐ์๋ค๋ณด๋ค AI Agent ๋ฅผ ๊ฐ๋ฐํ๋๊ฒ ๋๋ฆฌ๋ค๋ ์ฃผ์ ๋ก ์์ํ ๊ธ์ธ๋ฐ ๊ทธ ์ด์ ๋ฅผ ์๊ฐํ๋ฉด ์ฌ๋ญ ์ฒ ํ์ ์ผ๋ก ๋ฐ์๋ค์ฌ์ผ ํ ๋ถ๋ถ์ด ์์ต๋๋ค.
์ด์ ๋ ์ ํต์ ์ธ ์ํํธ์จ์ด ์์ง๋์ด๋ง(์๊ฒฉํ ์ ์ด, ๊ฒฐ์ ๋ก ์ ) ๊ทธ๋ฌ๋๊น ๋ง์ผ๋ฉด ๋ง๋๊ฑฐ๊ณ ํ๋ฆฌ๋ฉด ํ๋ฆฐ๊ฑฐ์ง, ํ๋ฆฌ๋ฉด ๊ณ ์ณ์ผ์ง ๋ผ๋ ์ ํต์ ์ธ ์์ง๋์ด๋ง์ ์ฒ ํ๊ณผ ์ต๊ด์ด AI ์์ด์ ํธ ๊ฐ๋ฐ์ ๋ฐฉํด๊ฐ ๋๊ณ ์๋ค๋ ๊ฒ๋๋ค. ๊ธ์ ์ ์์ธ Phillipp Schmid ๋ ์๋์ด์ผ์๋ก LLM ์ ๋ถํ์ค์ฑ์ ์ฝ๋๋ก ์ ๊ฑฐํ๋ ค๊ณ ํ๋ ๊ฒฝํฅ์ด ์์ด ์ฃผ๋์ด๋ณด๋ค ๋๋ ค์ง๋ค๋ ๊ฒ์ ๋๋ค.
ํ ์คํธ ๋ฐ์ดํฐ์ ๋งฅ๋ฝ์ ๊ตฌ์กฐํ ๋ ๊ฒ์ผ๋ก ๊ฐ์ ํ๋ฉด LLM์ด ์ํ๋๊ฒ์ ์คํ๋ ค ๋ ๋ชปํ๊ฒ ํ๋ฉด์ ์ฑ๋ฅ์ด ๋จ์ด์ง๊ณ ์ฑ๋ฅ์ด ๋จ์ด์ง๋ ์ด์ ๋ฅผ ์ฝ๋๋ก ์ ๊ฑฐํ๋ ค ํ๋ ์๋ ์ ๋น ์ง๊ฒ ๋๋ค์ ์๋ฏธ์ธ ๊ฒ ๊ฐ์ต๋๋ค.
๊ทธ๋์ ์ ์๋ agent๋ฅผ ๊ฐ๋ฐํ ๋ ์๋์ ์ ์ ์ ๊ฐ์ถ์ด์ผ ํ๋ค๊ณ ์ ์ํฉ๋๋ค.
- ํ
์คํธ๊ฐ ์๋ก์ด ์ํ(State)
- ํจ์ : ์์ฐ์ด ์ ๋ ฅ์ ๊ตฌ์กฐํ๋ ๋ฐ์ดํฐ(์: true/false)๋ก ๊ฐ์ ํ๋ฉด ๋งฅ๋ฝ ์์ค.
- ํด๊ฒฐ: ํผ๋๋ฐฑ(์: “์น์ธ, ๋ฏธ๊ตญ ์์ฅ ์ง์ค”)์ ํ ์คํธ๋ก ๋ณด์กดํด ๋์ ์กฐ์ ๊ฐ๋ฅ.
- ์ ์ด๊ถ์ ๋๊ฒจ๋ผ
- ํจ์ : ํ๋ฆ์ ํ๋์ฝ๋ฉ(์: ๊ตฌ๋ ์ทจ์ ๋ฃจํธ)ํ๋ฉด ๋น์ง์ ์ ์ํธ์์ฉ ๋์ ์คํจ.
- ํด๊ฒฐ: ์์ด์ ํธ(LLM)๊ฐ ๋งฅ๋ฝ ๊ธฐ๋ฐ์ผ๋ก ์๋ ํ๋จํ๋๋ก ์ ๋ขฐ.
- ์๋ฌ๋ ๊ทธ๋ฅ ์
๋ ฅ์ด๋ค
- ํจ์ : ์๋ฌ ๋ฐ์ ์ ํ๋ก๊ทธ๋จ ์ค๋จ(์ ํต ๋ฐฉ์)์ผ๋ก ๊ณ ๋น์ฉ ์คํ ๋ญ๋น.
- ํด๊ฒฐ: ์๋ฌ๋ฅผ ํผ๋๋ฐฑ์ผ๋ก ์ ๊ณตํด ์์ด์ ํธ๊ฐ ์๊ฐ ๋ณต๊ตฌ ์๋.
- ์ ๋ ํ
์คํธ์์ Eval๋ก
- ํจ์ : ์ด์ง ํ ์คํธ(TDD) ์ ์ฉ ์ ํ๋ฅ ์ ์์คํ ์์ ๋ฌด์๋ฏธ(๋ฌดํ ์ ํจ ๋ต๋ณ).
- ํด๊ฒฐ: ์ ๋ขฐ์ฑ(Pass@k), ํ์ง(LLM Judge), ์ถ์ (Eval)๋ก ๋ณ๋์ฑ ๊ด๋ฆฌ.
- ์์ด์ ํธ๋ ์งํํ๊ณ , API๋ ๊ทธ๋ ์ง ์๋ค
- ํจ์ : ์ธ๊ฐ ์ค์ฌ API(์๋ฌต์ ๋งฅ๋ฝ) ์ฌ์ฉ ์ ์์ด์ ํธ ํ๊ฐ ๋ฐ์.
- ํด๊ฒฐ: ์์ธ ์๋งจํฑ ํ์ดํ(์: “user_email_address”)๊ณผ ๋ ์คํธ๋ง์ผ๋ก ๋ช ํํ. ์์ด์ ํธ๋ ๋๊ตฌ ๋ณํ์ ์ ์ ๊ฐ๋ฅ.
๊ฒฐ๋ก ์ ์์ง๋์ด๋ง ์ฐ๋ฌผ์ ํ๋ฅ ์ฑ์ ๋ฐ์๋ค์ด๊ณ edge case ๋ค์ ๊ฐ์ ํ๋ ๊ฒ์ด ์๋ ๊ทธ ๋ง์ ๋ LLM ์ด ์๊ธฐํผ๋๋ฐฑ์ ํ ์ ์๋ ํ๋ ฅ์ ์์คํ ๊ตฌ์ถ์ผ๋ก ๋ง๋ค๊ณ ๊ทธ ๊ณผ์ ์ ๊ด๋ฆฌํ๋ผ๋ ๋ง ์ ๋๋ค.
๊ทธ๋์ ๋ค์ ์์ ์ผ๋ก ๋์์ structured output ์ ์ ๋ขฐํ ์ ์๋๊ฐ? ์ ๋ํ ๋ต์ ์ ๋ขฐํ ์ ์๋ค์ ๊ฐ๊น๋ค. ์ธ ๊ฒ ๊ฐ์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ ๋ขฐํ ์ ์๋ค ์๋ค ๋ก ํ๋จํ๋๊ฒ์ด ์๋๋ผ ์ผ๋ง๋ ์ ๋ขฐํ ์ ์๋๊ฐ? ์ ์ง์คํด์ผ ํ๊ฒ ์ต๋๋ค.
๊ธฐ๋ฅ์ ๋์ฒด๋ก ์ ์๋ํ๋(gpt-4o ์ด์์ ๋ชจ๋ธ), ๊ฐ์์ ํ๋ก๋์ ํ๊ฒฝ์์ ํ ์คํธํด๋ณด๊ณ ๊ด๋ฆฌ ๊ฐ๋ฅํ edge case ์ธ์ง ํ์ ํ๊ณ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ ๊ฒ ๊ฐ์ต๋๋ค.
์ด ๋ถ๋ถ์ ๋ํ ์๊ฐ์ ์ฌ๋๋ง๋ค ๋ง์ด ๋ค๋ฅผ ๊ฒ ๊ฐ์ต๋๋ค. ๋ค๋ฅธ ์๊ฒฌ๋ค์ ๋๊ธ๋ก ๋จ๊ฒจ์ฃผ์ธ์!
'Dev,AI > Langchain' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| LangChain ์์ํ๊ธฐ: ๊ธฐ๋ณธ LLM ์ฒด์ธ (Prompt + LLM) ์ดํดํ๊ธฐ (3) | 2025.08.12 |
|---|
