G-gen ã®äœã
æšã§ããåœèšäºã§ã¯ãæ³ä»€ API ã䜿çšããŠæ¥æ¬ã®æ³ä»€ãæ€çŽ¢ã§ãã AI ãšãŒãžã§ã³ããæ§ç¯ããGoogle Cloud äžã§åäœãããã£ããããããšããŠå©çšã§ããããã«ããŸãã æ§æ æ³ä»€ API ãšãŒãžã§ã³ã Google Cloud äžã®æ§æ åœèšäºã§äœ¿çšãããã® æ³ä»€ API Agent Development KitïŒADKïŒ Vertex AI Agent Engine Cloud Run ããã¯ãšã³ãã®æ§ç¯ ããã¯ãšã³ãã®æŠèŠ æ³ä»€ API ãšãŒãžã§ã³ãã®éçº ãã£ã¬ã¯ããªæ§æ ãããžã§ã¯ãã®æºå agent.py init.py requirements.txt .env ããŒã«ã«ã§ã®åäœç¢ºèªïŒADK Web UIïŒ ãšãŒãžã§ã³ãã®ããã〠Google Cloud ã®èªèšŒãšèšå® Agent Engine ãžã®ããã〠ããã³ããšã³ãã®æ§ç¯ ããã³ããšã³ãã®æŠèŠ ãã£ãããããã®éçº ãã£ã¬ã¯ããªæ§æ ãããžã§ã¯ãã®æºå app.py Dockerfile OAuth åæç»é¢ã®æ§æ Cloud Run ãžã®ããã〠ãµãŒãã¹ã¢ã«ãŠã³ãã®äœæ ããã〠åäœç¢ºèª æ©èœã®æ¡åŒµã«ã€ã㊠å€äŸæ€çŽ¢ãšãŒãžã§ã³ãã®è¿œå Memory Bank ã«ããé·æèšæ¶ã®å®è£
æ§æ æ³ä»€ API ãšãŒãžã§ã³ã åœèšäºã§ã¯ã Agent Development Kit ïŒADKïŒ ã§å®çŸ©ããã AI ãšãŒãžã§ã³ãã Gemini ã¢ãã«ã LLM ãšããŠäœ¿çšãããŠãŒã¶ãŒã®è³ªåã«å¿ã㊠æ³ä»€ API ãåŒã³åºãããã«æ§æããŠãããŸãã å
·äœçã«ã¯ããŠãŒã¶ãŒããã£ããã§è³ªåãéããš Gemini ããã®æå³ãè§£éãããšãŒãžã§ã³ãã«å®çŸ©ãããããŒã«é¢æ°ïŒæ³ä»€ API ãåŒã³åºã颿°ïŒãéžæã»å®è¡ããŸããæ³ä»€ API ããè¿ãããæ€çŽ¢çµæãæ¡æããŒã¿ã¯ Gemini ã«ãã£ãŠèŠçŽã»æŽåœ¢ãããèªç¶èšèªã«ããåçããŠãŒã¶ãŒã«è¿ããŸãã æ³ä»€ API ãšãŒãžã§ã³ãã®æ§æ Google Cloud äžã®æ§æ åœèšäºã§ã¯ãADK ã§å®çŸ©ãã AI ãšãŒãžã§ã³ãã Vertex AI Agent Engine ã«ããšãŒãžã§ã³ããå©çšãããã£ãããããã Cloud Run ã«ãããã€ããŸãã ãã®2ã€ã®ãµãŒãã¹ã¯ããããã ãŠãŒã¶ãŒã«ããã€ã³ãã©ç®¡çãäžèŠ ãªãã«ãããŒãžããªå®è¡åºç€ãæäŸãããŸã ãªã¯ãšã¹ããåŠçããŠãããšãã ãæéãçºçãã ãšããç¹åŸŽããããŸãã ãŸããCloud Run ã§ Identity-Aware ProxyïŒIAPïŒ ãæå¹åããããšã§ãGoogle ã¢ã«ãŠã³ãã§èªèšŒãããŠãŒã¶ãŒã®ã¿ããã£ããããããå©çšã§ããããã«ããŸãã æ³ä»€æ€çŽ¢ãã£ãããããã®æ§æ åè : Identity-Aware Proxy ã®æŠèŠ åœèšäºã§äœ¿çšãããã® æ³ä»€ API æ³ä»€ API ã¯ããžã¿ã«åºãæäŸããŠãããe-Gov æ³ä»€æ€çŽ¢ãã«æ ŒçŽãããŠããæ³ä»€ïŒæ³åŸã»æ¿ä»€ã»ç什ãªã©ïŒã®ããŒã¿ãååŸã§ãã API ã§ãããHTTP ãªã¯ãšã¹ãã§æ³ä»€äžèŠ§ãæ³ä»€ã®æ¬æãååŸããããããŒã¯ãŒãæ€çŽ¢ãè¡ã£ããã§ããŸãã API 仿§æžã¯ OpenAPI SpecificationïŒOASïŒã«åºã¥ããŠäœæãããŠãããSwagger UI äžã§åãšã³ããã€ã³ãã®ä»æ§ç¢ºèªããªã¯ãšã¹ãã®è©Šè¡ãå¯èœã§ãããŸããYAML 圢åŒã®ä»æ§ãã¡ã€ã«ãå
¬éãããŠããŸãã API ã®å©çšã«ããã£ãŠã¯èªèšŒã API ããŒã®ååŸã¯äžèŠã§ããã誰ã§ãç¡æã§å©çšã§ããŸãã åè : e-Gov æ³ä»€æ€çŽ¢ åè : æ³ä»€API Version 2 åè : ããžã¿ã«åºã«ãããæ³ä»€APIãæ³ä»€Ãããžã¿ã«ã®åãçµã¿ã«ã€ã㊠Agent Development KitïŒADKïŒ Agent Development Kit ïŒä»¥äžã ADK ïŒã¯ãGoogle Cloud ãæäŸãã AI ãšãŒãžã§ã³ãæ§ç¯ã®ããã®ãªãŒãã³ãœãŒã¹ ãã¬ãŒã ã¯ãŒã¯ã§ãããåçŽãªã¿ã¹ã¯ãããªããšãŒãžã§ã³ãããè€æ°ã®ãšãŒãžã§ã³ããååããè€éãªã¯ãŒã¯ãããŒãŸã§å®¹æã«å®è£
ã§ããŸãã åè : Agent Development Kit åè : Agent Development Kit ã®æŠèŠ Vertex AI Agent Engine Vertex AI Agent Engine ïŒä»¥äžã Agent Engine ïŒã¯ AI ãšãŒãžã§ã³ãã®å®è¡åºç€ãæäŸãããã«ãããŒãžããµãŒãã¹ã§ãã Agent Engine ã§ã¯ãšãŒãžã§ã³ããšã®ãã«ãã¿ãŒã³äŒè©±ãå®çŸãã ã»ãã·ã§ã³æ©èœ ãçµã¿èŸŒã¿ã§æäŸãããŠããããã®ä»ããšãŒãžã§ã³ãã®æ©èœæ¡åŒµã«å¿
èŠãªæ§ã
ãªæ©èœãå©çšã§ããŸãã Agent Engine ã®è©³çްã«ã€ããŠã¯ã以äžã®èšäºããäžèªãã ããã blog.g-gen.co.jp Cloud Run Cloud Run 㯠Google Cloud ã®ãããŒãžããªã³ã³ããå®è¡ç°å¢ã§ã¢ããªã±ãŒã·ã§ã³ãå®è¡ã§ããããµãŒããŒã¬ã¹ ã³ã³ããã³ã³ãã¥ãŒãã£ã³ã° ãµãŒãã¹ã§ãã Cloud Run ã¯ãšãŒãžã§ã³ãã®å®è¡åºç€ãšããŠãæçšãªãµãŒãã¹ã§ããAgent Engine ãšæ¯èŒãããšãã€ã³ãã©ç°å¢ã®ã«ã¹ã¿ãã€ãºæ§ã«åªããåé¢ãã»ãã·ã§ã³ãªã©ãšãŒãžã§ã³ãç¹æã®æ©èœã¯ç¬èªã«å®è£
ããŠããå¿
èŠããããŸãã åœèšäºã§ã¯ããšãŒãžã§ã³ãèªäœã®å®è¡åºç€ãšããŠã¯ Agent Engine ãå©çšããããã³ããšã³ããšããŠãšãŒãžã§ã³ããšããåããè¡ããã£ãããããã Cloud Run ã«æ§ç¯ããŠãããŸãã Cloud Run ã®è©³çްã«ã€ããŠã¯ã以äžã®èšäºããäžèªãã ããã blog.g-gen.co.jp ããã¯ãšã³ãã®æ§ç¯ ããã¯ãšã³ãã®æŠèŠ ããã¯ãšã³ããšããŠãæ³ä»€ API ãåŒã³åºã AI ãšãŒãžã§ã³ãã ADK ã§éçºããAgent Engine ã«ãããã€ããŸãã ããã¯ãšã³ããšããŠæ§ç¯ããç¯å² æ³ä»€ API ãšãŒãžã§ã³ãã®éçº ãã£ã¬ã¯ããªæ§æ æçµçãªãã£ã¬ã¯ããªæ§æã¯ä»¥äžã®éãã«ãªããŸãã lawapi_agent ãã£ã¬ã¯ããªã§ AI ãšãŒãžã§ã³ããå®è£
ããŠãããŸãã . âââ lawapi_agent â âââ agent.py â âââ .env â âââ __init__.py â âââ requirements.txt âââ pyproject.toml # èªåã§äœæ âââ uv.lock # èªåã§äœæ ADK ã§ã¯ãšãŒãžã§ã³ãã®ããã±ãŒãžïŒããã§ã¯ lawapi_agent ãã£ã¬ã¯ããªïŒå
ã« agent.py ãé
眮ããããã«ããŒã«é¢æ°ãšãšãŒãžã§ã³ãå®çŸ©ãå®è£
ããŸãã ãããžã§ã¯ãã®æºå ãšãŒãžã§ã³ãéçºçšã®ãã£ã¬ã¯ããªã§ãããžã§ã¯ããåæåããŸãã # uv ãããžã§ã¯ãåæå $ uv init --no-readme # ããã±ãŒãžã®è¿œå $ uv add " google-adk>=1.27.3 " " google-cloud-aiplatform[agent-engines]>=1.142.0 " " httpx>=0.28 " " python-dotenv>=1.1 " agent.py ãšãŒãžã§ã³ããæ³ä»€æ€çŽ¢ãå®è¡ããããã®ããŒã«ãšããŠã以äžã®ããŒã«é¢æ°ãå®è£
ãããããã䜿çšãããšãŒãžã§ã³ãã ADK ã§å®çŸ©ããŸãã ããŒã«é¢æ°å åŠçå
容 search_laws_by_keyword ããŒã¯ãŒãã«ããæ³ä»€ã®å
šææ€çŽ¢ãè¡ããŸãã該åœããæ³ä»€ã®æ¡æããã¹ããäžéšååŸããŸãã list_laws æ³ä»€åïŒéšåäžèŽïŒãæ³ä»€çš®å¥ãªã©ã®æ¡ä»¶ãæå®ããŠãæ³ä»€ã®äžèŠ§ãæ³ä»€ ID ãååŸããŸãã get_law_detail æ³ä»€ ID ãæ³ä»€çªå·ãæå®ããŠãå¯Ÿè±¡ã®æ³ä»€ããŒã¿ïŒå
šæãŸãã¯ç¹å®ã®èŠçŽ ïŒãååŸããŸãã ããŒã«é¢æ°ã® docstring 㯠ADK ãéã㊠Gemini ã«æž¡ããããããåŒæ°ã®èª¬æãæ£ç¢ºã«èšè¿°ããããšãéèŠã§ãã ã³ãŒãæ«å°Ÿã® root_agent ã§ãšãŒãžã§ã³ããå®çŸ©ããŠããŸãã䜿çšããã¢ãã«ãæ¯ãèããæç€ºããããã³ããïŒ instruction ïŒãšãäžèš3ã€ã®ããŒã«é¢æ°ãæå®ããŠããŸãã import httpx from google.adk.agents import Agent BASE_URL = "https://laws.e-gov.go.jp/api/2" def search_laws_by_keyword (keyword: str , limit: int = 10 ) -> dict : """æ³ä»€ã®æ¬æãããŒã¯ãŒãã§å
šææ€çŽ¢ããŸãã Args: keyword: æ€çŽ¢ããŒã¯ãŒããAND/OR/NOTæ€çŽ¢ãã¯ã€ã«ãã«ãŒã(*,?)ã䜿ããŸãã limit: ååŸä»¶æ°ã®äžéïŒããã©ã«ã10ãæå€§1000ïŒã Returns: dict: æ€çŽ¢çµæããããããæ³ä»€ãšè©²åœç®æã®ããã¹ããå«ã¿ãŸãã """ try : resp = httpx.get( f "{BASE_URL}/keyword" , params={ "keyword" : keyword, "limit" : limit}, timeout= 30 , ) resp.raise_for_status() data = resp.json() total = data.get( "total_count" , 0 ) items = [] for item in data.get( "items" , []): law_info = item.get( "law_info" , {}) sentences = item.get( "sentences" , []) items.append({ "law_title" : law_info.get( "law_title" ), "law_num" : law_info.get( "law_num" ), "law_id" : law_info.get( "law_id" ), "matched_sentences" : [ { "position" : s.get( "position" ), "text" : s.get( "text" )} for s in sentences[: 5 ] ], }) return { "status" : "success" , "total_count" : total, "items" : items} except httpx.HTTPStatusError as e: return { "status" : "error" , "error_message" : f "APIãšã©ãŒ: {e.response.status_code}" } except Exception as e: return { "status" : "error" , "error_message" : str (e)} def list_laws (law_title: str = "" , law_type: str = "" , category_cd: str = "" , limit: int = 10 ) -> dict : """æ¡ä»¶ãæå®ããŠæ³ä»€ã®äžèЧãååŸããŸãã Args: law_title: æ³ä»€åïŒéšåäžèŽïŒãäŸ: "å人æ
å ±", "åŽååºæº" law_type: æ³ä»€çš®å¥ãConstitution,Act,CabinetOrder,ImperialOrder,MinisterialOrdinance,Rule,Misc ããæå®ã category_cd: äºé
å¥åé¡ã³ãŒãïŒ001ã050ïŒãäŸ: "046"ïŒæ°äºïŒ, "002"ïŒåäºïŒ limit: ååŸä»¶æ°ã®äžéïŒããã©ã«ã10ïŒã Returns: dict: æ³ä»€äžèŠ§ãæ³ä»€åãæ³ä»€çªå·ãæ³ä»€IDãªã©ãå«ã¿ãŸãã """ try : params = { "limit" : limit} if law_title: params[ "law_title" ] = law_title if law_type: params[ "law_type" ] = law_type if category_cd: params[ "category_cd" ] = category_cd resp = httpx.get(f "{BASE_URL}/laws" , params=params, timeout= 30 ) resp.raise_for_status() data = resp.json() total = data.get( "total_count" , 0 ) laws = [] for law in data.get( "laws" , []): info = law.get( "law_info" , {}) laws.append({ "law_title" : info.get( "law_title" ), "law_num" : info.get( "law_num" ), "law_id" : info.get( "law_id" ), "law_type" : info.get( "law_type" ), }) return { "status" : "success" , "total_count" : total, "laws" : laws} except httpx.HTTPStatusError as e: return { "status" : "error" , "error_message" : f "APIãšã©ãŒ: {e.response.status_code}" } except Exception as e: return { "status" : "error" , "error_message" : str (e)} def get_law_detail (law_id: str , elm: str = "" ) -> dict : """æ³ä»€IDãæå®ããŠæ³ä»€ã®æ¬æãååŸããŸãã Args: law_id: æ³ä»€IDïŒäŸ: "322CO0000000016"ïŒãŸãã¯æ³ä»€çªå·ïŒäŸ: "æåäºåäºå¹Žæ¿ä»€ç¬¬åå
å·"ïŒã elm: ååŸããèŠçŽ ã®ãã¹ãçç¥ãããšå
šæãååŸããŸãã äŸ: "MainProvision-Article_1" ã§ç¬¬1æ¡ãååŸã Returns: dict: æ³ä»€ã®æ¬æããŒã¿ïŒJSON light圢åŒïŒã """ try : params = { "response_format" : "json" , "json_format" : "light" } if elm: params[ "elm" ] = elm resp = httpx.get(f "{BASE_URL}/law_data/{law_id}" , params=params, timeout= 30 ) resp.raise_for_status() data = resp.json() law_info = data.get( "law_info" , {}) revision_info = data.get( "revision_info" , {}) law_full_text = data.get( "law_full_text" , {}) return { "status" : "success" , "law_title" : law_info.get( "law_title" ), "law_num" : law_info.get( "law_num" ), "amendment_date" : revision_info.get( "amendment_date" ), "law_full_text" : law_full_text, } except httpx.HTTPStatusError as e: return { "status" : "error" , "error_message" : f "APIãšã©ãŒ: {e.response.status_code}" } except Exception as e: return { "status" : "error" , "error_message" : str (e)} root_agent = Agent( name= "law_search_agent" , model= "gemini-2.5-flash" , description= "æ¥æ¬ã®æ³ä»€ãæ€çŽ¢ã»é²èЧã§ããAIãšãŒãžã§ã³ã" , instruction=( "ããªãã¯æ¥æ¬ã®æ³ä»€ãæ€çŽ¢ã»èª¿æ»ããå°éã¢ã·ã¹ã¿ã³ãã§ãã \n " "e-Govæ³ä»€APIã䜿ã£ãŠããŠãŒã¶ãŒã®è³ªåã«åçããŠãã ããã \n\n " "## äœ¿ãæ¹ã®ã¬ã€ãã©ã€ã³ \n " "- ãŠãŒã¶ãŒãæ³åŸã®å
容ã«ã€ããŠè³ªåããå ŽåããŸã search_laws_by_keyword ã list_laws ã§è©²åœããæ³ä»€ãç¹å®ããŠãã ããã \n " "- ç¹å®ã®æ³ä»€ã®æ¡æã確èªãããå Žå㯠get_law_detail ã䜿ã£ãŠãã ããã \n " "- æ¡æãåŒçšããéã¯ãæ³ä»€åãšæ¡çªå·ãæèšããŠãã ããã \n " "- æ³ä»€ã®è§£éã«ã€ããŠã¯ãæ¡æã®å
å®¹ãæ£ç¢ºã«äŒããäžã§ãäžè¬çãªè§£éã説æããŠãã ããã \n " "- å°éçãªæ³ç倿ãå¿
èŠãªå Žåã¯ãåŒè·å£«çã®å°éå®¶ãžã®çžè«ãæšå¥šããŠãã ããã \n " ), tools=[search_laws_by_keyword, list_laws, get_law_detail], ) init .py ADK ããšãŒãžã§ã³ãããã±ãŒãžãèªèããããã«å¿
èŠãªãã¡ã€ã«ã§ãã以äžã®1è¡ã ãèšè¿°ããŠãããŸãã from . import agent requirements.txt Agent Engine ãžã®ãããã€æã«äœ¿çšãããäŸåé¢ä¿ã®å®çŸ©ã§ããããŒã«ã«éçºã§ã¯ã«ãŒãã® pyproject.toml ã䜿çšãããããããã®ãã¡ã€ã«ã¯ãããã€å°çšã§ãã google-adk httpx google-cloud-aiplatform[adk,agent_engines] .env Gemini ã¢ãã«ã䜿çšããããã® Vertex AI ã®æ¥ç¶èšå®ãèšè¿°ããŸãã adk web ã³ãã³ãã«ãããšãŒãžã§ã³ãã®ããŒã«ã«å®è¡æã«èªåã§èªã¿èŸŒãŸããŸããAgent Engine äžã§ã¯ Vertex AI ã®èšå®ãèªåã§é©çšãããããããã®ãã¡ã€ã«ã¯ããŒã«ã«å®è¡å°çšã®ãã®ã§ãã GOOGLE_GENAI_USE_VERTEXAI = 1 GOOGLE_CLOUD_PROJECT = < ãããžã§ã¯ãID > GOOGLE_CLOUD_LOCATION =asia-northeast1 ããŒã«ã«ã§ã®åäœç¢ºèªïŒADK Web UIïŒ ä»¥äžã®ã³ãã³ããå®è¡ãããš ADK ã® Web UI ãããŒã«ã«ã§èµ·åããŸãããã©ãŠã¶ã§ http://localhost:8000 ãéãããã£ããã§ãšãŒãžã§ã³ããæ£ããåäœããããšã確èªããŸãã # ADK Web UI ã®èµ·å $ uv run adk web . # ----- åºåã®æç² ----- INFO: Started server process [ 49931 ] INFO: Waiting for application startup. +--------------------------------------------------------------------------- -- + | ADK Web Server started | | | | For local testing, access at http:// 127 . 0 . 0 .1:8000. | +--------------------------------------------------------------------------- -- + INFO: Application startup complete . INFO: Uvicorn running on http:// 127 . 0 . 0 .1:8000 ( Press CTRL+C to quit ) ãã£ãã UI ããæ³ä»€ã«é¢ãã質åãéä¿¡ããŠã¿ãŸãã ADK Web UI ã䜿çšããããŒã«ã«ã§ã®ãšãŒãžã§ã³ãã®åäœç¢ºèª ãšãŒãžã§ã³ãã質åå
容ããé©åãªããŒã«é¢æ°ã倿ã»å®è¡ããããšã§ãæ³ä»€ API ããããŒã¿ãååŸããŠåçãè¡ã£ãŠããŸãã ãšãŒãžã§ã³ãã®ããã〠Google Cloud ã®èªèšŒãšèšå® ãããã€ã®åã«ãGoogle Cloud CLI ã§ã®èªèšŒãè¡ã£ãŠãããŸãã # ãããžã§ã¯ã ID ãã·ã§ã«å€æ°ã«ã»ãã $ PROJECT_ID = < ãããžã§ã¯ãID > # èªèšŒ $ gcloud auth login $ gcloud auth application-default login # ãããžã§ã¯ãã®èšå® $ gcloud config set project $PROJECT_ID Agent Engine ãžã®ããã〠adk deploy ã³ãã³ãã䜿çšããŠã Agent Engine ã«ãšãŒãžã§ã³ãããããã€ããŸãã # Agent Engine ã«ãšãŒãžã§ã³ããããã〠$ uv run adk deploy agent_engine \ --project = $PROJECT_ID \ --region = asia-northeast1 \ --display_name =" Law Search Agent " \ lawapi_agent ãããã€ãæåãããšã以äžã®ããã« Agent Engine ã®ãªãœãŒã¹åãåºåãããŸãã â
Created agent engine: projects/ < ãããžã§ã¯ãçªå· > /locations/asia-northeast1/reasoningEngines/ < ãšãŒãžã§ã³ãåºæã®æ°å > ãã®ãªãœãŒã¹åã¯ãã£ãããããã®ãããã€æã«äœ¿çšãããããã·ã§ã«å€æ°ã«ã»ããããŠãããŸãã # ã·ã§ã«å€æ°ã«ãªãœãŒã¹åãã»ãã ENGINE_ID =projects/ < ãããžã§ã¯ãçªå· > /locations/asia-northeast1/reasoningEngines/ < ãšãŒãžã§ã³ãåºæã®æ°å > ããã³ããšã³ãã®æ§ç¯ ããã³ããšã³ãã®æŠèŠ æ©æ¢°åŠç¿ã¢ãã«ã®ãã¢çš Web UI ã容æã«äœæã§ãã Gradio ãšãã Python ã©ã€ãã©ãªã䜿çšããŠãã£ããããããå®è£
ããŸãã ãã£ãããããã¯ãã³ã³ããã€ã¡ãŒãžåã㊠Cloud Run ã«ãããã€ããWeb ãµãŒãã¹ãšããŠå
¬éã§ããããã«ããŸãã ããã³ããšã³ããšããŠæ§ç¯ããç¯å² åè : Gradio ãã£ãããããã®éçº ãã£ã¬ã¯ããªæ§æ ããã³ããšã³ãã¯ãšãŒãžã§ã³ããšã¯å¥ã®ãã£ã¬ã¯ããªã§æ§ç¯ããŸãã æçµçãªãã£ã¬ã¯ããªæ§æã¯ä»¥äžã®éãã«ãªããŸãã app.py ã«ãã£ããããããå®è£
ããŠãããŸãã . âââ app.py âââ Dockerfile âââ pyproject.toml # èªåã§äœæ âââ uv.lock # èªåã§äœæ ãããžã§ã¯ãã®æºå ãšãŒãžã§ã³ããšã¯å¥ã®ãã£ã¬ã¯ããªã§ uv ãããžã§ã¯ããåæåããŸãã # uv ãããžã§ã¯ãåæå $ uv init --no-readme # ããã±ãŒãžã®è¿œå $ uv add " google-cloud-aiplatform[agent-engines]>=1.142.0 " " gradio>=5.29 " app.py app.py ã§ã¯ä»¥äžã®åŠçãå®è£
ããŠããŸãã vertexai.init() ã§ Vertex AI ã«æ¥ç¶ãã agent_engines.get() ã§ Agent Engine ã«ãããã€ãããšãŒãžã§ã³ããååŸ Agent Engine ã®ã»ãã·ã§ã³æ©èœïŒ create_session ïŒã䜿ãããŠãŒã¶ãŒããšã«ãã«ãã¿ãŒã³ã®äŒè©±ã管ç agent.stream_query() ã§ãšãŒãžã§ã³ãã«ã¡ãã»ãŒãžãéä¿¡ããã¹ããªãŒãã³ã°ã§å¿çãåä¿¡ gr.Blocks ã§ Gradio ã®ãã£ãã UI ãæ§ç¯ import os import uuid import gradio as gr import vertexai from vertexai import agent_engines AGENT_ENGINE_ID = os.environ[ "AGENT_ENGINE_ID" ] def get_agent (): vertexai.init( project=os.environ.get( "GOOGLE_CLOUD_PROJECT" ), location=os.environ.get( "GOOGLE_CLOUD_LOCATION" ), ) return agent_engines.get(AGENT_ENGINE_ID) agent = get_agent() def chat (message: str , history: list , session_state: dict ) -> tuple [ str , dict ]: user_id = session_state.get( "user_id" ) if not user_id: user_id = str (uuid.uuid4()) session_state[ "user_id" ] = user_id session_id = session_state.get( "session_id" ) if not session_id: session = agent.create_session(user_id=user_id) session_id = session[ "id" ] session_state[ "session_id" ] = session_id response_text = "" for event in agent.stream_query( message=message, user_id=user_id, session_id=session_id, ): if event.get( "content" ) and event[ "content" ].get( "parts" ): for part in event[ "content" ][ "parts" ]: if part.get( "text" ): response_text += part[ "text" ] yield response_text, session_state with gr.Blocks( title= "æ³ä»€æ€çŽ¢ãšãŒãžã§ã³ã" , fill_height= True , css= """ .title-row { text-align: center; margin-bottom: 0; } .caption-row { text-align: center; margin-top: 0; color: #666; font-size: 0.9em; } .input-row { position: sticky; bottom: 0; background: var(--background-fill-primary); padding: 10px 0; } """ , ) as demo: gr.Markdown( "<h1 class='title-row'>âïž æ³ä»€æ€çŽ¢ãšãŒãžã§ã³ã</h1>" "<p class='caption-row'>e-Govæ³ä»€APIã䜿ã£ãŠæ¥æ¬ã®æ³ä»€ãæ€çŽ¢ããŸã</p>" ) session_state = gr.State(value={}) chatbot = gr.Chatbot( show_label= False , scale= 1 , avatar_images=( None , "https://em-content.zobj.net/source/google/412/balance-scale_2696-fe0f.png" ), placeholder= "質åãå
¥åãããšãããã«äŒè©±ã衚瀺ãããŸã" , ) with gr.Row(elem_classes= "input-row" ): textbox = gr.Textbox( placeholder= "æ³ä»€ã«ã€ããŠè³ªåããŠãã ããïŒäŸ: å人æ
å ±ä¿è·æ³ã®ç®çã¯ïŒïŒ" , show_label= False , container= False , scale= 7 , ) def respond (message, history, session_state): history = history + [ { "role" : "user" , "content" : message}, ] yield history, session_state, gr.update(value= "" , interactive= False ) assistant_text = "" for text, updated_state in chat(message, history, session_state): assistant_text = text session_state = updated_state yield ( history + [{ "role" : "assistant" , "content" : assistant_text}], session_state, gr.update(interactive= False ), ) yield ( history + [{ "role" : "assistant" , "content" : assistant_text}], session_state, gr.update(interactive= True ), ) textbox.submit( respond, inputs=[textbox, chatbot, session_state], outputs=[chatbot, session_state, textbox], ) if __name__ == "__main__" : port = int (os.environ.get( "PORT" , 8080 )) demo.launch(server_name= "0.0.0.0" , server_port=port) Dockerfile Cloud Run ã«ãããã€ããããã®ã³ã³ããã€ã¡ãŒãžãå®çŸ©ããŸããuv ã®å
¬åŒã€ã¡ãŒãžãããã€ããªãã³ããŒããäŸåããã±ãŒãžã®ã€ã³ã¹ããŒã«ãšã¢ããªã±ãŒã·ã§ã³ã®èµ·åãè¡ããŸãã FROM python:3.14-slim COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ WORKDIR /app COPY pyproject.toml uv.lock ./ RUN uv sync --frozen --no-dev COPY app.py . EXPOSE 8080 CMD [ " uv ", " run ", " python ", " app.py " ] OAuth åæç»é¢ã®æ§æ Cloud Run ã§ IAP ãæå¹åãããšãCloud Run äžã®ãµãŒãã¹ãžã®ã¢ã¯ã»ã¹æã« Google ã¢ã«ãŠã³ãã§ã®ãã°ã€ã³ãæ±ããããããã«ãªããèš±å¯ããããŠãŒã¶ãŒã®ã¿ããã£ããããããå©çšã§ããŸãã ãããžã§ã¯ãã§ OAuth åæç»é¢ã®æ§æããŸã è¡ã£ãŠããªãå Žåã以äžã®ããã¥ã¡ã³ããåç
§ããŠå®æœããŠãã ããã åè : OAuth åæç»é¢ãèšå®ããã¹ã³ãŒããéžæãã Cloud Run ãžã®ããã〠ãµãŒãã¹ã¢ã«ãŠã³ãã®äœæ Cloud Run çšã®ã«ã¹ã¿ã ãµãŒãã¹ã¢ã«ãŠã³ããäœæããAgent Engine ãžã®ã¢ã¯ã»ã¹ã«å¿
èŠãª Vertex AI ãŠãŒã¶ãŒ ïŒ roles/aiplatform.user ïŒããŒã«ãä»äžããŸãã # ãµãŒãã¹ã¢ã«ãŠã³ãã®äœæ $ gcloud iam service-accounts create lawapi-frontend \ --display-name =" Law API Frontend " # Vertex AI User ããŒã«ã®ä»äž $ gcloud projects add-iam-policy-binding $PROJECT_ID \ --member =" serviceAccount:lawapi-frontend@ ${PROJECT_ID} .iam.gserviceaccount.com " \ --role =" roles/aiplatform.user " ããã〠gcloud run deploy ã³ãã³ãã§ Cloud Run ã«ãããã€ããŸãã --source ãªãã·ã§ã³ãæå®ãããšãCloud Build ã«ããã³ã³ããã€ã¡ãŒãžã®ãã«ããšãããã€ãèªåã§è¡ãããŸãã --no-allow-unauthenticated ãš --iap ãæå®ããããšã§ãIAP ã§èªèšŒããããŠãŒã¶ãŒã®ã¿ãã¢ã¯ã»ã¹ã§ããããã«ããŠããŸãã --service-account ã§å
ã»ã©äœæããã«ã¹ã¿ã ãµãŒãã¹ã¢ã«ãŠã³ããæå®ããŸãã $ gcloud run deploy lawapi-frontend \ --source . \ --region asia-northeast1 \ --set-env-vars " GOOGLE_CLOUD_PROJECT= $PROJECT_ID ,GOOGLE_CLOUD_LOCATION=asia-northeast1,AGENT_ENGINE_ID= $ENGINE_ID " \ --service-account lawapi-frontend@ ${PROJECT_ID} .iam.gserviceaccount.com \ --cpu 1 \ --memory 1Gi \ --no-allow-unauthenticated \ --iap Cloud Run ã®åçš®èšå®é
ç®ã®è©³çްã«ã€ããŠã¯ã以äžã®èšäºããäžèªãã ããã blog.g-gen.co.jp åäœç¢ºèª ãããã€ãå®äºããããCloud Run ãµãŒãã¹ã® URL ã«ãã©ãŠã¶ã§ã¢ã¯ã»ã¹ããŸãã # ãããã€åŸã«åºåããããµãŒãã¹ URL Service URL: https://lawapi-frontend- < ãããžã§ã¯ãçªå· > .asia-northeast1.run.app IAP ãæå¹åãããŠãããããGoogle ã¢ã«ãŠã³ãã§ã®ãã°ã€ã³ãæ±ããããŸãã IAP ã§ä¿è·ããããŠã§ãã¢ã㪠ãŠãŒã¶ãŒ ïŒ roles/iap.httpsResourceAccessor ïŒããŒã«ãä»äžããããŠãŒã¶ãŒã§ãã°ã€ã³ããŸãã Google ã¢ã«ãŠã³ãã§ãã°ã€ã³ãã ãã°ã€ã³åŸããã£ããç»é¢ã衚瀺ãããã®ã§ãæ³ä»€ã«é¢ãã質åãå
¥åããŠãšãŒãžã§ã³ãã®åäœã確èªããŸãã äŸãã°ãå人æ
å ±ä¿è·æ³ã®ç®çã¯ïŒããšè³ªåãããšããšãŒãžã§ã³ããæ³ä»€ API ãéããŠå人æ
å ±ä¿è·æ³ã®æ¡æãæ€çŽ¢ãã第1æ¡ã®ç®çèŠå®ãåŒçšããªããåçãè¿ããŸãã ãã£ãããããã®åäœç¢ºèª ãšãŒãžã§ã³ãã¯äŒè©±ã®ã³ã³ããã¹ãïŒæèïŒãä¿æããŠãããããç¶ããŠã眰åã¯ããïŒãã®ããã«è¿œå ã®è³ªåããããšãåãæ³ä»€ã®é¢é£ããæ¡æãæ€çŽ¢ããŠåçããŸãã ã»ãã·ã§ã³ã«ãã£ãŠã³ã³ããã¹ããä¿æãããŠããããç¢ºèª æ©èœã®æ¡åŒµã«ã€ã㊠å€äŸæ€çŽ¢ãšãŒãžã§ã³ãã®è¿œå åœèšäºã§æ§ç¯ãããšãŒãžã§ã³ãã¯æ³ä»€ API ã«ããæ³ä»€ã®æ€çŽ¢ã«ç¹åããŠããŸãããADK ã Agent Engine ã®æ©èœã掻çšããããšã§ãããã«é«åºŠãªãŠãŒã¹ã±ãŒã¹ã«å¯Ÿå¿ãããããšãã§ããŸãã ããšãã°ãæ³ä»€ã®æ¡æã ãã§ãªããå®éã®å€äŸãè£å€äŸãåç
§ãããã±ãŒã¹ãå€ããããŸããADK ã§ã¯ google_search ããŒã«ãçµã¿èŸŒã¿ã§æäŸãããŠããã以äžã®ããã«å€äŸã Web æ€çŽ¢ãããšãŒãžã§ã³ããæ§ç¯ã§ããŸãïŒ agent.py ã®è¿œå å®è£
äŸïŒã from google.adk.tools import google_search case_search_agent = Agent( name= "case_search_agent" , model= "gemini-2.5-flash" , description= "æ¥æ¬ã®å€äŸã»è£å€äŸãWebæ€çŽ¢ãããµããšãŒãžã§ã³ããå€äŸã®æ€çŽ¢ãèŠæšã®ç¢ºèªãå€äŸã®è§£èª¬ãã§ããŸãã" , instruction=( "ããªãã¯æ¥æ¬ã®å€äŸã»è£å€äŸãæ€çŽ¢ã»èª¿æ»ããå°éã¢ã·ã¹ã¿ã³ãã§ãã \n " "Googleæ€çŽ¢ã䜿ã£ãŠããŠãŒã¶ãŒã®è³ªåã«é¢é£ããå€äŸãæ€çŽ¢ããŠãã ããã \n\n " "## äœ¿ãæ¹ã®ã¬ã€ãã©ã€ã³ \n " "- å€äŸãæ€çŽ¢ããéã¯ãå€äŸããè£å€äŸããæé«è£ãã倿±ºããªã©ã®ããŒã¯ãŒããçµã¿åãããŠãã ããã \n " "- è£å€æã®ãŠã§ããµã€ãïŒcourts.go.jpïŒã®æ
å ±ãåªå
ããŠãã ããã \n " "- å€äŸãåŒçšããéã¯ãè£å€æåã倿±ºæ¥ãäºä»¶çªå·ãæèšããŠãã ããã \n " "- å€äŸã®èŠæšã倿šãæ£ç¢ºã«äŒããŠãã ããã \n " "- å€äŸã®è§£éã«ã€ããŠã¯ãäžè¬çãªåŠèª¬ã»é説ãèžãŸããŠèª¬æããŠãã ããã \n " "- å°éçãªæ³ç倿ãå¿
èŠãªå Žåã¯ãåŒè·å£«çã®å°éå®¶ãžã®çžè«ãæšå¥šããŠãã ããã \n " ), tools=[google_search], ) ãã®ãããªå€äŸæ€çŽ¢ãšãŒãžã§ã³ããæ³ä»€æ€çŽ¢ãšãŒãžã§ã³ãã®ããŒã«ã®äžã€ãšããŠçµã¿èŸŒãããšã§ããšãŒãžã§ã³ãã¯ãŠãŒã¶ãŒã®è³ªåå
容ã«å¿ããŠé©åãªããŒã«ã䜿ãåããŸããæ³ä»€ãšå€äŸã®äž¡æ¹ã«é¢ãã質åã§ã¯ãäž¡æ¹ã®ããŒã«ãåäžã¿ãŒã³ã§åŒã³åºãããšãå¯èœã§ãã from google.adk.tools.agent_tool import AgentTool root_agent = Agent( name= "legal_research_agent" , model= "gemini-2.5-flash" , description= "æ¥æ¬ã®æ³ä»€æ€çŽ¢ãšå€äŸæ€çŽ¢ãçµ±åãããªãŒã¬ã«ãªãµãŒãAIãšãŒãžã§ã³ã" , instruction=( "ããªãã¯æ¥æ¬ã®æ³åŸã«é¢ãããªãŒã¬ã«ãªãµãŒããæ¯æŽããçµ±åã¢ã·ã¹ã¿ã³ãã§ãã \n " "æ³ä»€æ€çŽ¢ããŒã«ãšå€äŸæ€çŽ¢ããŒã«ã䜿ãåããŠãã ããã \n\n " "## ããŒã«ã®äœ¿ãåã \n " "- **search_laws_by_keyword / list_laws / get_law_detail**: æ³åŸã»æ¿ä»€ã»ç什ãªã©ã®æ³ä»€ã®æ¡æãæ€çŽ¢ã»é²èЧãããå Žåã«äœ¿ã£ãŠãã ããã \n " "- **case_search_agent**: å€äŸã»è£å€äŸãæ€çŽ¢ãããå Žåã«äœ¿ã£ãŠãã ããã \n\n " "## ã¬ã€ãã©ã€ã³ \n " "- ãŠãŒã¶ãŒã®è³ªåã«å¿ããŠãé©åãªããŒã«ãéžæããŠãã ããã \n " "- æ³ä»€ãšå€äŸã®äž¡æ¹ãé¢é£ãã質åã®å Žåã¯ãäž¡æ¹ã®ããŒã«ã掻çšããŠãã ããã \n " "- æçµçãªåçã¯ãæ³ä»€ã®æ¡æãšå€äŸãç·åããŠåããããããŸãšããŠãã ããã \n " "- å°éçãªæ³ç倿ãå¿
èŠãªå Žåã¯ãåŒè·å£«çã®å°éå®¶ãžã®çžè«ãæšå¥šããŠãã ããã \n " ), tools=[ search_laws_by_keyword, list_laws, get_law_detail, AgentTool(agent=case_search_agent), ], ) 以äžã®ã¹ã¯ãªãŒã³ã·ã§ããã¯ãæ³ä»€ãšé¢é£ããå€äŸãåæã«è³ªåããéã®ãšãŒãžã§ã³ãã®åäœäŸã§ãããŸãæ³ä»€ API ã«ããæ¡ææ€çŽ¢ã宿œããããã®åŸãããŒã«ãšããŠçµã¿èŸŒãã§ãããå€äŸæ€çŽ¢ãšãŒãžã§ã³ãã«ãã Web æ€çŽ¢ãè¡ãããŠããŸããæçµçã«ã¯ããããã®æ€çŽ¢çµæãæŽçãããã®ãåçãããŠããŸãã ãŸãæ³ä»€ API ã䜿çšããŠæ¡æãæ€çŽ¢ããããŒã«ãå®è¡ãã ãã®åŸãå€äŸæ€çŽ¢ãšãŒãžã§ã³ããé¢é£ããå€äŸã Web æ€çŽ¢ã»èŠçŽãã åè : Google Search Grounding for agents Memory Bank ã«ããé·æèšæ¶ã®å®è£
åœèšäºã®ãã£ãããããã§ã¯ Agent Engine ã®ã»ãã·ã§ã³æ©èœã䜿ã£ãŠäŒè©±ã®ã³ã³ããã¹ããä¿æããŠããŸãããã»ãã·ã§ã³ã¯ãããŸã§äžé£ã®äŒè©±ã®äžã§ã®çæçãªèšæ¶ã§ãã Agent Engine ã§ã¯ Memory Bank ãšããé·æèšæ¶ã®æ©èœãæäŸãããŠãããéå»ã®ã»ãã·ã§ã³ã®å
容ããŠãŒã¶ãŒããšã«èšæ¶ãšããŠèç©ããæ°ããã»ãã·ã§ã³ã§ãåç
§ã§ããŸãã äŸãã°ããããŠãŒã¶ãŒã以åã®äŒè©±ã§ããæ³ä»€ã«ã€ããŠèª¿ã¹ãŠããå Žåãå¥ã®æ¥ã«æ°ããã»ãã·ã§ã³ã§ãåå調ã¹ãŠããæ³åŸã®ææ°ã®æ¹æ£å
容ãæããŠããšè³ªåãããšãMemory Bank ã«ä¿åãããéå»ã®ã³ã³ããã¹ããããšã«é©åãªåçãè¿ãããšãæåŸ
ã§ããŸãã ãã®ããã«ãMemory Bank ãæŽ»çšããããšã§ããŠãŒã¶ãŒããšã«ããŒãœãã©ã€ãºãããæ³ä»€èª¿æ»ã¢ã·ã¹ã¿ã³ããæ§ç¯ããããšãå¯èœã«ãªããŸãã åè : Vertex AI Agent Engine Memory Bank ã®æŠèŠ äœã
æš é§¿å€ª (èšäºäžèЧ) G-gen æå端ãåæµ·éåšäœã®ã¯ã©ãŠããœãªã¥ãŒã·ã§ã³éšãšã³ãžã㢠2022幎6æã« G-gen ã«ãžã§ã€ã³ãGoogle Cloud Partner Top Engineer ã«éžåºïŒ2024 / 2025 Fellow / 2026ïŒã奜ã㪠Google Cloud ãããã¯ã㯠Cloud Runã è¶£å³ã¯ã³ãŒããŒãå°èª¬ïŒSFããã¹ããªïŒãã«ã©ãªã±ãªã©ã Follow @sasashun0805