Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions app/agents/report_generation/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ class ReportGenerationSettings(BaseSettings):
enable_bedrock_guardrails: bool = False
bedrock_guardrail_id: str = ""

# 비어있으면(기본값) Evidence Research Agent는 in-process 검색 함수를 그대로 쓴다
# (app.agents.report_generation.evidence_research.tools). 채워지면 대신 이
# AgentCore Gateway(MCP, AWS_IAM 인증)를 통해 kure_retriever Lambda의 7개
# tool을 원격 호출한다 - 둘은 같은 파이프라인을 공유하므로(Lambda가 같은
# @tool 함수를 재사용) 동작은 동일하고 실행 위치만 달라진다.
evidence_research_gateway_url: str = ""
evidence_research_gateway_region: str = "ap-northeast-2"

model_config = {"env_file": ".env", "extra": "ignore"}


Expand Down
56 changes: 46 additions & 10 deletions app/agents/report_generation/evidence_research/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
search_korean_evidence,
)

# evidence_research_gateway_url이 비어있을 때(기본값) 쓰는 in-process tool.
# Gateway 모드에서는 이 대신 kure_retriever Lambda가 노출하는 동일 이름의
# MCP tool을 원격 호출한다(_mcp_gateway_client) - 둘 다 결국 같은 @tool
# 함수(같은 파이프라인)를 실행하므로 검색 결과는 동일해야 한다.
_AGENT_TOOLS = [
search_korean_evidence,
search_international_evidence,
Expand All @@ -32,38 +36,70 @@
]


def build_evidence_research_agent() -> Agent:
model = BedrockModel(
def _build_model() -> BedrockModel:
return BedrockModel(
model_id=cfg.research_agent_model_id,
region_name="ap-northeast-2",
temperature=cfg.research_agent_temperature,
max_tokens=4096,
)


def build_evidence_research_agent() -> Agent:
"""in-process tool로 동작하는 Agent (Gateway 미설정 시 기본 경로)."""
return Agent(
model=model,
model=_build_model(),
tools=_AGENT_TOOLS,
system_prompt=EVIDENCE_RESEARCH_SYSTEM_PROMPT,
)


def _mcp_gateway_client():
"""kure_retriever Lambda를 노출하는 AgentCore Gateway(MCP, AWS_IAM 인증)에 연결한다.

참고: https://github.com/aws/mcp-proxy-for-aws - aws_iam_streamablehttp_client가
호출자의 AWS 자격증명으로 각 요청에 SigV4 서명을 자동으로 붙여준다.
"""
from mcp_proxy_for_aws.client import aws_iam_streamablehttp_client
from strands.tools.mcp import MCPClient

return MCPClient(
lambda: aws_iam_streamablehttp_client(
endpoint=cfg.evidence_research_gateway_url,
aws_region=cfg.evidence_research_gateway_region,
aws_service="bedrock-agentcore",
)
)


def research_evidence(
clinical_context: ClinicalContextOutput,
search_feedback: dict | None = None,
) -> EvidenceResearchOutput:
agent = build_evidence_research_agent()

message = (
f"[Clinical Context]\n{clinical_context.model_dump_json(indent=2)}\n\n"
)
if search_feedback:
message += f"[이전 Critic 피드백 - 반드시 반영]\n{json.dumps(search_feedback, ensure_ascii=False, indent=2)}\n\n"
message += "위 clinical_priorities/evidence_needs를 지원할 문헌 근거를 검색하라."

result = agent(
message,
structured_output_model=EvidenceResearchOutput,
limits={"turns": cfg.research_agent_max_turns},
)
call_kwargs = {
"structured_output_model": EvidenceResearchOutput,
"limits": {"turns": cfg.research_agent_max_turns},
}

if cfg.evidence_research_gateway_url:
with _mcp_gateway_client() as mcp_client:
agent = Agent(
model=_build_model(),
tools=mcp_client.list_tools_sync(),
system_prompt=EVIDENCE_RESEARCH_SYSTEM_PROMPT,
)
result = agent(message, **call_kwargs)
else:
agent = build_evidence_research_agent()
result = agent(message, **call_kwargs)

output = result.structured_output
if output is None:
logger.warning("[evidence_research_agent] structured_output이 비어 있음")
Expand Down
7 changes: 7 additions & 0 deletions lambda/kure_retriever/handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,13 @@ def lambda_handler(event: dict, context) -> dict:
event: 호출된 tool의 입력 파라미터 (예: {"query_ko": "...", "top_k": 5}).
"""
if event.get("query") == "ping" or event.get("query_ko") == "ping":
# KURE-v1 임베딩 모델을 실제로 로드해 이 실행 환경(warm container)에
# 캐싱해둔다. AgentCore Gateway의 tool 호출은 ~30초에서 끊기는데, 모델
# 로드(수십 초)를 여기서 미리 안 해두면 실제 검색 요청이 매번 그 안에서
# 콜드 로드까지 겹쳐 타임아웃난다 (실제 호출로 확인함) - DB는 안 거친다.
from app.rag.retriever import _get_embedding_model

_get_embedding_model().predict(["ping"])
return {"statusCode": 200, "body": json.dumps([])}

full_tool_name = _resolve_tool_name(context) or ""
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ dependencies = [
# AWS
"boto3>=1.34.0",
"strands-agents>=1.0.0",
"mcp-proxy-for-aws>=1.6.0",
# DB
"sqlalchemy[asyncio]>=2.0.30",
"psycopg[binary]>=3.1.19",
Expand Down
Loading
Loading