Spaces:
Sleeping
Sleeping
| """LangGraph State β λ©ν°ν΄ 보ν μ±λ΄ μν μ€ν€λ§. | |
| νμ νλ: | |
| messages β Human/AI/Tool λ©μμ§ λμ (add_messages reducer) | |
| trace β λ Έλλ³ μ€ν λ‘κ·Έ (append reducer) | |
| """ | |
| from __future__ import annotations | |
| from typing import Annotated, Literal | |
| from langchain_core.messages import HumanMessage | |
| from langgraph.graph import MessagesState | |
| from pydantic import Field | |
| # ββ Trace Reset Sentinel βββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # ainvoke μμ μ μ΄μ ν΄ traceλ₯Ό μ΄κΈ°ννλ λ§μ»€ κ°μ²΄. | |
| # dict νμ μ΄μ§λ§ κ°μ²΄ λμΌμ±(is)μΌλ‘ λΉκ΅νλ―λ‘ μ¬μ©μ λ°μ΄ν°μ μΆ©λ μμ. | |
| _TRACE_RESET: dict = {"__reset__": True} | |
| def _append_trace(current: list[dict], update: list[dict]) -> list[dict]: | |
| """Trace reducer β μ ainvoke μμ μ μ΄κΈ°ν, ν΄ λ΄μμλ λμ . | |
| update[0] is _TRACE_RESET μ΄λ©΄ μ΄λ² ν΄λ§ μ μ§ (체ν¬ν¬μΈνΈ trace νκΈ°). | |
| """ | |
| if update and update[0] is _TRACE_RESET: | |
| return list(update[1:]) | |
| return current + update | |
| class AgentState(MessagesState): | |
| """κ·Έλν μ 체 μν. λͺ¨λ λ Έλκ° μ΄ νμ μ λΆλΆμ§ν©μ μ μΆλ ₯.""" | |
| trace: Annotated[list[dict], _append_trace] | |
| guardrail_action: Literal["pass", "block", "retry"] = Field(default="pass") | |
| rewritten_query: str = Field(default="") | |
| """query_rewriterκ° λ¨λ¬Έ/νμ μ§λ¬Έμ μ¬μμ±ν κ²°κ³Ό. λΉμ΄μμΌλ©΄ μλ³Έ μ¬μ©.""" | |
| guardrail_retry_count: int = Field(default=0) | |
| """output_guardrail μ°¨λ¨ ν μ¬μλ νμ. 무ν 루ν λ°©μ§μ©.""" | |
| conversation_started: bool = Field(default=False) | |
| """output_guardrailλ₯Ό ν΅κ³Όν μ€μ AI μλ΅μ΄ μ΅μ 1ν μ΄μ μ μ‘λ μ μλμ§ μ¬λΆ. | |
| guardrailμμ κ±°μ λ μλ΅λ§ μμ λ Falseλ₯Ό μ μ§ν¨μΌλ‘μ¨ | |
| λλ©μΈ μ²΄ν¬ μ°ν(1ν΄ μ°¨λ¨ β 2ν΄ followup νμ ) μ·¨μ½μ μ λ°©μ§νλ€. | |
| build_graph_input()μμ 리μ νμ§ μμΌλ―λ‘ checkpointerλ₯Ό ν΅ν΄ λν μ λ°μ κ±Έμ³ μ μ§λλ€. | |
| """ | |
| def build_graph_input(query: str) -> dict: | |
| """κ·Έλν νΈμΆμ© μ λ ₯ dictλ₯Ό ꡬμ±νλ€. | |
| λͺ¨λ μ§μ μ (FastAPI, MCP)μ΄ μ΄ ν¨μλ₯Ό μ¬μ©νμ¬ | |
| AgentState μ€ν€λ§μ λ§λ μ λ ₯μ μμ±νλ€. | |
| traceμ _TRACE_RESETμ μ£Όμ νμ¬ μ΄μ ν΄ traceκ° λμ λμ§ μλλ‘ νλ€. | |
| conversation_startedλ μλμ μΌλ‘ 리μ νμ§ μλλ€ (λν μ λ° μ μ§). | |
| """ | |
| return { | |
| "messages": [HumanMessage(content=query)], | |
| "trace": [_TRACE_RESET], | |
| "guardrail_action": "pass", | |
| "rewritten_query": "", | |
| "guardrail_retry_count": 0, | |
| } | |
| def extract_last_human_query(messages: list) -> str: | |
| """λ©μμ§ νμ€ν 리μμ κ°μ₯ μ΅κ·Ό HumanMessageμ contentλ₯Ό λ°ν.""" | |
| for msg in reversed(messages): | |
| if isinstance(msg, HumanMessage) and msg.content: | |
| return msg.content | |
| return "" | |
| def extract_tools_used(messages: list) -> list[str]: | |
| """λ©μμ§ λ¦¬μ€νΈμμ μ¬μ©λ λꡬ μ΄λ¦μ μ€λ³΅ μμ΄ μμ 보쑴νμ¬ λ°ν.""" | |
| return list(dict.fromkeys( | |
| msg.name for msg in messages | |
| if hasattr(msg, "name") and msg.name and getattr(msg, "type", "") == "tool" | |
| )) | |