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("draft_response")
51
- prompt = manager.build_prompt("draft_response", "๋ฏผ์› ๋‹ต๋ณ€ ์ดˆ์•ˆ์„ ์ž‘์„ฑํ•ด์ฃผ์„ธ์š”.")
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._draft_response_fn = None # ๋‹ต๋ณ€ ์ดˆ์•ˆ ์ƒ์„ฑ ํด๋กœ์ € (์ง€์—ฐ ์ดˆ๊ธฐํ™”)
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"๋‹ค์Œ ๋ฏผ์›์— ๋Œ€ํ•œ ๋‹ต๋ณ€์„ ์ž‘์„ฑํ•ด ์ฃผ์„ธ์š”.\n\n{safe_message}"
406
- prompt = self._build_persona_prompt("draft_response", user_content)
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"๋‹ค์Œ ๋ฏผ์›์— ๋Œ€ํ•œ ๋‹ต๋ณ€์„ ์ž‘์„ฑํ•ด ์ฃผ์„ธ์š”.\n\n{safe_message}"
435
- prompt = self._build_persona_prompt("draft_response", user_content)
436
 
437
  sampling_params = SamplingParams(
438
  temperature=(
@@ -534,7 +534,7 @@ class vLLMEngineManager:
534
 
535
  engine_ref = self
536
 
537
- async def _draft_response_tool(
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._draft_response_fn = _draft_response_tool
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
- draft_response_fn=self._draft_response_fn,
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, a Korean civil complaint response assistant.\n"
162
- "Analyze the user's request and actively use the available tools to provide accurate, data-backed answers.\n\n"
 
 
 
 
 
 
163
  "Decision rules:\n"
164
- "1. For complaint response drafts: ALWAYS call the appropriate adapter tool "
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
- draft_response_fn: Optional[Callable[..., Any]] = None,
19
  ) -> list:
20
  """์ „์ฒด ๋„๊ตฌ ๋ชฉ๋ก์„ ๋™์ ์œผ๋กœ ์ƒ์„ฑํ•œ๋‹ค.
21
 
@@ -23,7 +23,7 @@ def build_all_tools(
23
  ----------
24
  api_lookup_action : Optional[MinwonAnalysisAction]
25
  ๊ณต๊ณต๋ฐ์ดํ„ฐํฌํ„ธ API Action ์ธ์Šคํ„ด์Šค.
26
- draft_response_fn : Optional[Callable]
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 draft_response_fn:
38
  try:
39
  from .adapter_tools import build_adapter_tools
40
 
41
- tools.extend(build_adapter_tools(draft_response_fn))
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(draft_response_fn: Callable) -> List[StructuredTool]:
26
  """AdapterRegistry์˜ ๋ชจ๋“  ์–ด๋Œ‘ํ„ฐ์— ๋Œ€ํ•ด StructuredTool์„ ๋™์  ์ƒ์„ฑํ•œ๋‹ค.
27
 
28
  Parameters
29
  ----------
30
- draft_response_fn : Callable
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 draft_response_fn(
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): draft_response ์šฉ๋„
153
  ํ•™์Šต ๋ฐ์ดํ„ฐ: umyunsang/govon-civil-response-data (74K๊ฑด), QLoRA on AWQ base
154
  HF Hub: umyunsang/GovOn-EXAONE-LoRA-v2
155
- - legal-adapter (LoRA #2): draft_response ์šฉ๋„
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 ์‚ฌ์šฉ