Spaces:
Paused
Paused
github-actions commited on
Commit ยท
3e685d7
1
Parent(s): c5ccac1
sync: c44e5ea
Browse files
src/inference/agent_manager.py
CHANGED
|
@@ -47,8 +47,8 @@ class AgentManager:
|
|
| 47 |
|
| 48 |
Usage:
|
| 49 |
manager = AgentManager("agents/")
|
| 50 |
-
persona = manager.get_agent("
|
| 51 |
-
prompt = manager.build_prompt("
|
| 52 |
"""
|
| 53 |
|
| 54 |
_FRONTMATTER_RE = re.compile(r"^---\s*\n(.*?)\n---\s*\n(.*)$", re.DOTALL)
|
|
|
|
| 47 |
|
| 48 |
Usage:
|
| 49 |
manager = AgentManager("agents/")
|
| 50 |
+
persona = manager.get_agent("domain_adapter")
|
| 51 |
+
prompt = manager.build_prompt("domain_adapter", "๊ฑด์ถ ํ๊ฐ ์ ์ฐจ์ ๋ํด ์๋ดํด์ฃผ์ธ์.")
|
| 52 |
"""
|
| 53 |
|
| 54 |
_FRONTMATTER_RE = re.compile(r"^---\s*\n(.*?)\n---\s*\n(.*)$", re.DOTALL)
|
src/inference/api_server.py
CHANGED
|
@@ -152,7 +152,7 @@ class vLLMEngineManager:
|
|
| 152 |
self.session_store = SessionStore()
|
| 153 |
self.agent_manager = AgentManager(AGENTS_DIR)
|
| 154 |
self._api_lookup_action = None # MinwonAnalysisAction (์ง์ฐ ์ด๊ธฐํ)
|
| 155 |
-
self.
|
| 156 |
self.graph = None # LangGraph CompiledGraph (v2 ์๋ํฌ์ธํธ์ฉ)
|
| 157 |
self.graph_v3 = None # v3 ReAct graph (v3 ์๋ํฌ์ธํธ์ฉ)
|
| 158 |
self._checkpointer_ctx = None # AsyncSqliteSaver ์ปจํ
์คํธ ๋งค๋์ (lifespan์์ ๊ด๋ฆฌ)
|
|
@@ -402,8 +402,8 @@ class vLLMEngineManager:
|
|
| 402 |
gen_defaults = runtime_config.generation
|
| 403 |
|
| 404 |
safe_message = self._escape_special_tokens(self._extract_query(request.prompt))
|
| 405 |
-
user_content = f"๋ค์
|
| 406 |
-
prompt = self._build_persona_prompt("
|
| 407 |
|
| 408 |
sampling_params = SamplingParams(
|
| 409 |
temperature=request.temperature,
|
|
@@ -431,8 +431,8 @@ class vLLMEngineManager:
|
|
| 431 |
|
| 432 |
safe_message = self._escape_special_tokens(self._extract_query(request.prompt))
|
| 433 |
# ํ์ต ๋ฐ์ดํฐ ํ์: user = instruction + "\n\n" + input
|
| 434 |
-
user_content = f"๋ค์
|
| 435 |
-
prompt = self._build_persona_prompt("
|
| 436 |
|
| 437 |
sampling_params = SamplingParams(
|
| 438 |
temperature=(
|
|
@@ -534,7 +534,7 @@ class vLLMEngineManager:
|
|
| 534 |
|
| 535 |
engine_ref = self
|
| 536 |
|
| 537 |
-
async def
|
| 538 |
query: str,
|
| 539 |
context: dict,
|
| 540 |
session: SessionContext,
|
|
@@ -564,7 +564,7 @@ class vLLMEngineManager:
|
|
| 564 |
"text": "",
|
| 565 |
"draft_text": "",
|
| 566 |
"success": False,
|
| 567 |
-
"error": "
|
| 568 |
"results": [],
|
| 569 |
"context_text": "",
|
| 570 |
}
|
|
@@ -581,7 +581,7 @@ class vLLMEngineManager:
|
|
| 581 |
"completion_tokens": len(final_output.outputs[0].token_ids),
|
| 582 |
}
|
| 583 |
|
| 584 |
-
self.
|
| 585 |
|
| 586 |
def _build_langgraph_tools(self) -> list:
|
| 587 |
"""LangGraph ToolNode์ฉ ๋๊ตฌ ๋ชฉ๋ก์ ์์ฑํ๋ค.
|
|
@@ -592,7 +592,7 @@ class vLLMEngineManager:
|
|
| 592 |
|
| 593 |
return build_all_tools(
|
| 594 |
api_lookup_action=self._api_lookup_action,
|
| 595 |
-
|
| 596 |
)
|
| 597 |
|
| 598 |
def _init_graph_with_async_checkpointer(self, checkpointer: object) -> None:
|
|
|
|
| 152 |
self.session_store = SessionStore()
|
| 153 |
self.agent_manager = AgentManager(AGENTS_DIR)
|
| 154 |
self._api_lookup_action = None # MinwonAnalysisAction (์ง์ฐ ์ด๊ธฐํ)
|
| 155 |
+
self._domain_adapter_fn = None # Domain adapter generation closure (lazy init)
|
| 156 |
self.graph = None # LangGraph CompiledGraph (v2 ์๋ํฌ์ธํธ์ฉ)
|
| 157 |
self.graph_v3 = None # v3 ReAct graph (v3 ์๋ํฌ์ธํธ์ฉ)
|
| 158 |
self._checkpointer_ctx = None # AsyncSqliteSaver ์ปจํ
์คํธ ๋งค๋์ (lifespan์์ ๊ด๋ฆฌ)
|
|
|
|
| 402 |
gen_defaults = runtime_config.generation
|
| 403 |
|
| 404 |
safe_message = self._escape_special_tokens(self._extract_query(request.prompt))
|
| 405 |
+
user_content = f"๋ค์ ์์ฒญ์ ๋ํด ํด๋น ๋๋ฉ์ธ์ ์ ๋ฌธ ์ง์์ ๋ฐํ์ผ๋ก ๋ต๋ณ์ ์์ฑํด ์ฃผ์ธ์.\n\n{safe_message}"
|
| 406 |
+
prompt = self._build_persona_prompt("domain_adapter", user_content)
|
| 407 |
|
| 408 |
sampling_params = SamplingParams(
|
| 409 |
temperature=request.temperature,
|
|
|
|
| 431 |
|
| 432 |
safe_message = self._escape_special_tokens(self._extract_query(request.prompt))
|
| 433 |
# ํ์ต ๋ฐ์ดํฐ ํ์: user = instruction + "\n\n" + input
|
| 434 |
+
user_content = f"๋ค์ ์์ฒญ์ ๋ํด ํด๋น ๋๋ฉ์ธ์ ์ ๋ฌธ ์ง์์ ๋ฐํ์ผ๋ก ๋ต๋ณ์ ์์ฑํด ์ฃผ์ธ์.\n\n{safe_message}"
|
| 435 |
+
prompt = self._build_persona_prompt("domain_adapter", user_content)
|
| 436 |
|
| 437 |
sampling_params = SamplingParams(
|
| 438 |
temperature=(
|
|
|
|
| 534 |
|
| 535 |
engine_ref = self
|
| 536 |
|
| 537 |
+
async def _domain_adapter_tool(
|
| 538 |
query: str,
|
| 539 |
context: dict,
|
| 540 |
session: SessionContext,
|
|
|
|
| 564 |
"text": "",
|
| 565 |
"draft_text": "",
|
| 566 |
"success": False,
|
| 567 |
+
"error": "Domain adapter response generation failed",
|
| 568 |
"results": [],
|
| 569 |
"context_text": "",
|
| 570 |
}
|
|
|
|
| 581 |
"completion_tokens": len(final_output.outputs[0].token_ids),
|
| 582 |
}
|
| 583 |
|
| 584 |
+
self._domain_adapter_fn = _domain_adapter_tool
|
| 585 |
|
| 586 |
def _build_langgraph_tools(self) -> list:
|
| 587 |
"""LangGraph ToolNode์ฉ ๋๊ตฌ ๋ชฉ๋ก์ ์์ฑํ๋ค.
|
|
|
|
| 592 |
|
| 593 |
return build_all_tools(
|
| 594 |
api_lookup_action=self._api_lookup_action,
|
| 595 |
+
domain_adapter_fn=self._domain_adapter_fn,
|
| 596 |
)
|
| 597 |
|
| 598 |
def _init_graph_with_async_checkpointer(self, checkpointer: object) -> None:
|
src/inference/graph/nodes.py
CHANGED
|
@@ -158,10 +158,16 @@ def _extractive_summarize(older_messages: list) -> str:
|
|
| 158 |
|
| 159 |
|
| 160 |
_BASE_SYSTEM_PROMPT = (
|
| 161 |
-
"You are GovOn,
|
| 162 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 163 |
"Decision rules:\n"
|
| 164 |
-
"1. For
|
| 165 |
"(public_admin_adapter for administrative matters, legal_adapter for legal questions).\n"
|
| 166 |
"2. For data or statistics: Use api_lookup, stats_lookup, issue_detector, "
|
| 167 |
"keyword_analyzer, or demographics_lookup as needed.\n"
|
|
|
|
| 158 |
|
| 159 |
|
| 160 |
_BASE_SYSTEM_PROMPT = (
|
| 161 |
+
"You are GovOn, an agentic AI platform that transforms Korea's fragmented "
|
| 162 |
+
"government DX infrastructure into a unified AX (Agentic Transformation) system.\n"
|
| 163 |
+
"You orchestrate distributed government APIs โ scattered across ministries, departments, "
|
| 164 |
+
"and agencies โ as callable tools, enabling seamless cross-agency data access and "
|
| 165 |
+
"domain-specific response generation through a single intelligent interface.\n\n"
|
| 166 |
+
"Currently active domain adapters (MVP):\n"
|
| 167 |
+
"- public_admin_adapter: Public administration (civil complaints, permits, administrative procedures)\n"
|
| 168 |
+
"- legal_adapter: Legal domain (statutes, precedents, legal interpretation)\n\n"
|
| 169 |
"Decision rules:\n"
|
| 170 |
+
"1. For domain-specific response drafts: ALWAYS call the appropriate adapter tool "
|
| 171 |
"(public_admin_adapter for administrative matters, legal_adapter for legal questions).\n"
|
| 172 |
"2. For data or statistics: Use api_lookup, stats_lookup, issue_detector, "
|
| 173 |
"keyword_analyzer, or demographics_lookup as needed.\n"
|
src/inference/graph/tools/__init__.py
CHANGED
|
@@ -15,7 +15,7 @@ from .search_tools import build_search_tools
|
|
| 15 |
def build_all_tools(
|
| 16 |
*,
|
| 17 |
api_lookup_action: Optional[Any] = None,
|
| 18 |
-
|
| 19 |
) -> list:
|
| 20 |
"""์ ์ฒด ๋๊ตฌ ๋ชฉ๋ก์ ๋์ ์ผ๋ก ์์ฑํ๋ค.
|
| 21 |
|
|
@@ -23,7 +23,7 @@ def build_all_tools(
|
|
| 23 |
----------
|
| 24 |
api_lookup_action : Optional[MinwonAnalysisAction]
|
| 25 |
๊ณต๊ณต๋ฐ์ดํฐํฌํธ API Action ์ธ์คํด์ค.
|
| 26 |
-
|
| 27 |
๋ต๋ณ ์ด์ ์์ฑ ํด๋ก์ . ์์ผ๋ฉด adapter_tools๋ฅผ ์ถ๊ฐ.
|
| 28 |
|
| 29 |
Returns
|
|
@@ -34,11 +34,11 @@ def build_all_tools(
|
|
| 34 |
tools: list = []
|
| 35 |
tools.extend(build_search_tools(api_lookup_action))
|
| 36 |
tools.extend(build_analysis_tools(api_lookup_action))
|
| 37 |
-
if
|
| 38 |
try:
|
| 39 |
from .adapter_tools import build_adapter_tools
|
| 40 |
|
| 41 |
-
tools.extend(build_adapter_tools(
|
| 42 |
except ImportError:
|
| 43 |
import logging
|
| 44 |
|
|
|
|
| 15 |
def build_all_tools(
|
| 16 |
*,
|
| 17 |
api_lookup_action: Optional[Any] = None,
|
| 18 |
+
domain_adapter_fn: Optional[Callable[..., Any]] = None,
|
| 19 |
) -> list:
|
| 20 |
"""์ ์ฒด ๋๊ตฌ ๋ชฉ๋ก์ ๋์ ์ผ๋ก ์์ฑํ๋ค.
|
| 21 |
|
|
|
|
| 23 |
----------
|
| 24 |
api_lookup_action : Optional[MinwonAnalysisAction]
|
| 25 |
๊ณต๊ณต๋ฐ์ดํฐํฌํธ API Action ์ธ์คํด์ค.
|
| 26 |
+
domain_adapter_fn : Optional[Callable]
|
| 27 |
๋ต๋ณ ์ด์ ์์ฑ ํด๋ก์ . ์์ผ๋ฉด adapter_tools๋ฅผ ์ถ๊ฐ.
|
| 28 |
|
| 29 |
Returns
|
|
|
|
| 34 |
tools: list = []
|
| 35 |
tools.extend(build_search_tools(api_lookup_action))
|
| 36 |
tools.extend(build_analysis_tools(api_lookup_action))
|
| 37 |
+
if domain_adapter_fn:
|
| 38 |
try:
|
| 39 |
from .adapter_tools import build_adapter_tools
|
| 40 |
|
| 41 |
+
tools.extend(build_adapter_tools(domain_adapter_fn))
|
| 42 |
except ImportError:
|
| 43 |
import logging
|
| 44 |
|
src/inference/graph/tools/adapter_tools.py
CHANGED
|
@@ -22,12 +22,12 @@ class AdapterToolInput(BaseModel):
|
|
| 22 |
query: str = Field(description="Civil complaint or legal query text")
|
| 23 |
|
| 24 |
|
| 25 |
-
def build_adapter_tools(
|
| 26 |
"""AdapterRegistry์ ๋ชจ๋ ์ด๋ํฐ์ ๋ํด StructuredTool์ ๋์ ์์ฑํ๋ค.
|
| 27 |
|
| 28 |
Parameters
|
| 29 |
----------
|
| 30 |
-
|
| 31 |
``async (query, context, session) -> dict`` ์๊ทธ๋์ฒ์ ๋ต๋ณ ์์ฑ ํจ์.
|
| 32 |
|
| 33 |
Returns
|
|
@@ -49,7 +49,7 @@ def build_adapter_tools(draft_response_fn: Callable) -> List[StructuredTool]:
|
|
| 49 |
try:
|
| 50 |
# session=None: ToolNode์์๋ ์ธ์
์ปจํ
์คํธ๊ฐ ๋ถํ์.
|
| 51 |
# persist_node๊ฐ ๋ณ๋๋ก ์ธ์
์ ์ฅ์ ์ฒ๋ฆฌํ๋ค.
|
| 52 |
-
result = await
|
| 53 |
query=query,
|
| 54 |
context={"adapter": name},
|
| 55 |
session=None,
|
|
|
|
| 22 |
query: str = Field(description="Civil complaint or legal query text")
|
| 23 |
|
| 24 |
|
| 25 |
+
def build_adapter_tools(domain_adapter_fn: Callable) -> List[StructuredTool]:
|
| 26 |
"""AdapterRegistry์ ๋ชจ๋ ์ด๋ํฐ์ ๋ํด StructuredTool์ ๋์ ์์ฑํ๋ค.
|
| 27 |
|
| 28 |
Parameters
|
| 29 |
----------
|
| 30 |
+
domain_adapter_fn : Callable
|
| 31 |
``async (query, context, session) -> dict`` ์๊ทธ๋์ฒ์ ๋ต๋ณ ์์ฑ ํจ์.
|
| 32 |
|
| 33 |
Returns
|
|
|
|
| 49 |
try:
|
| 50 |
# session=None: ToolNode์์๋ ์ธ์
์ปจํ
์คํธ๊ฐ ๋ถํ์.
|
| 51 |
# persist_node๊ฐ ๋ณ๋๋ก ์ธ์
์ ์ฅ์ ์ฒ๋ฆฌํ๋ค.
|
| 52 |
+
result = await domain_adapter_fn(
|
| 53 |
query=query,
|
| 54 |
context={"adapter": name},
|
| 55 |
session=None,
|
src/inference/runtime_config.py
CHANGED
|
@@ -149,10 +149,10 @@ class ModelConfig:
|
|
| 149 |
- vLLM ์๋น ์ต์
: --enable-auto-tool-choice --tool-call-parser hermes
|
| 150 |
|
| 151 |
Multi-LoRA ์ด๋ํฐ:
|
| 152 |
-
- public_admin-adapter (LoRA #1):
|
| 153 |
ํ์ต ๋ฐ์ดํฐ: umyunsang/govon-civil-response-data (74K๊ฑด), QLoRA on AWQ base
|
| 154 |
HF Hub: umyunsang/GovOn-EXAONE-LoRA-v2
|
| 155 |
-
- legal-adapter (LoRA #2):
|
| 156 |
ํ์ต ๋ฐ์ดํฐ: umyunsang/govon-legal-response-data (243K๊ฑด), QLoRA on AWQ base
|
| 157 |
HuggingFace: siwo/govon-legal-adapter
|
| 158 |
- ๋๋จธ์ง capability (api_lookup, synthesis ๋ฑ)๋ LoRA ์์ด base model ์ฌ์ฉ
|
|
|
|
| 149 |
- vLLM ์๋น ์ต์
: --enable-auto-tool-choice --tool-call-parser hermes
|
| 150 |
|
| 151 |
Multi-LoRA ์ด๋ํฐ:
|
| 152 |
+
- public_admin-adapter (LoRA #1): domain_adapter ์ฉ๋
|
| 153 |
ํ์ต ๋ฐ์ดํฐ: umyunsang/govon-civil-response-data (74K๊ฑด), QLoRA on AWQ base
|
| 154 |
HF Hub: umyunsang/GovOn-EXAONE-LoRA-v2
|
| 155 |
+
- legal-adapter (LoRA #2): domain_adapter ์ฉ๋
|
| 156 |
ํ์ต ๋ฐ์ดํฐ: umyunsang/govon-legal-response-data (243K๊ฑด), QLoRA on AWQ base
|
| 157 |
HuggingFace: siwo/govon-legal-adapter
|
| 158 |
- ๋๋จธ์ง capability (api_lookup, synthesis ๋ฑ)๋ LoRA ์์ด base model ์ฌ์ฉ
|