Vertex AI Agent Builder provides a powerful framework for developing and deploying intelligent agents in Google Cloud. This integration is particularly valuable since any agent running on Vertex AI Agent Engine or the open-source ADK runtime can be seamlessly surfaced through Agentspace, making it easily accessible to your organization.
TL;DR
Build the agent with ADK → deploy to Agent Engine → "Add to Agentspace"—the SurrealDB retrieval tool keeps working unchanged, giving your Gemini-based agent sub-second RAG over your own vector index, all inside Google Cloud.
Below is a concise walkthrough that shows:
creating a SurrealDB-powered retrieval tool
wiring it into an ADK agent
deploying that agent to Agent Engine
registering it in Agentspace so employees can chat with it from the Agentspace UI.
Prerequisites
pip install google-adk google-genai surrealdb # ADK + Gemini SDK + SurrealDB docker run -p 8000:8000 surrealdb/surrealdb:latest \ start --user root --pass secret file:/data/db # optional local DB export GOOGLE_API_KEY=<your-Gemini-key>
classSurrealRetriever: """SurrealDB-powered retrieval tool for Google Agent.""" def__init__( self, config: Optional[SurrealConfig]=None, api_key: Optional[str]=None ): """Initialize the retriever. Args: config: Optional SurrealDB configuration api_key: Optional Google API key """ self.config=configorSurrealConfig() self.api_key=api_keyoros.environ.get("GOOGLE_API_KEY") ifnotself.api_key: raiseValueError("Google API key is required") genai.configure(api_key=self.api_key) self.embedder=genai.Client().models.get_embedding_model("models/embedding-001") @asynccontextmanager asyncdef_get_connection(self) -> AsyncSurreal: """Get a database connection with proper authentication. Yields: Connected AsyncSurreal instance Raises: SurrealException: If connection fails """ db=AsyncSurreal(self.config.url) try: awaitdb.signin({ "username": self.config.username, "password": self.config.password }) awaitdb.use(self.config.namespace,self.config.database) yielddb exceptSurrealExceptionase: logger.error(f"Failed to connect to SurrealDB: {str(e)}") raiseSurrealException(f"Connection failed: {str(e)}") finally: awaitdb.close()
asyncdef_embed(self,text: str) -> List[float]: """Generate embeddings for text. Args: text: Text to embed Returns: List of embedding values Raises: Exception: If embedding generation fails """ try: returnself.embedder.embed(content=text).embedding exceptExceptionase: logger.error(f"Failed to generate embeddings: {str(e)}") raiseException(f"Embedding generation failed: {str(e)}")
asyncdefretrieve(self,question: str,k: int=4) -> str: """Retrieve top-k passages related to question from SurrealDB. Args: question: Search query k: Number of results to return Returns: Formatted string of matching passages Raises: SurrealException: If database operations fail """ try: qv=awaitself._embed(question) asyncwithself._get_connection()asdb: result=awaitdb.query(""" SELECT text, source, vector::distance::cosine(embedding, $vec) AS score FROM kb_docs WHERE embedding <|$k|> $vec ORDER BY score ASC """,{ "vec": qv, "k": k }) rows=result[0]["result"] return"\n".join( f"- {r['text']} (src: {r['source']})" forrinrows ) exceptSurrealExceptionase: logger.error(f"Retrieval failed: {str(e)}") raiseSurrealException(f"Retrieval failed: {str(e)}")
asyncdefingest(self,docs: List[Dict[str,str]]) -> None: """Ingest documents into SurrealDB. Args: docs: List of documents with text and source Raises: SurrealException: If database operations fail """ try: asyncwithself._get_connection()asdb: fordocindocs: rec={ "id": hashlib.sha1(doc["text"].encode()).hexdigest(), "text": doc["text"], "source": doc["source"], "embedding": awaitself._embed(doc["text"]), } awaitdb.create("kb_docs",rec) logger.info(f"Ingested {len(docs)} documents") exceptSurrealExceptionase: logger.error(f"Ingestion failed: {str(e)}") raiseSurrealException(f"Ingestion failed: {str(e)}")
asyncdefensure_schema(self) -> None: """Ensure the required table and index exist. Raises: SurrealException: If schema operations fail """ try: asyncwithself._get_connection()asdb: awaitdb.query(""" DEFINE TABLE IF NOT EXISTS kb_docs SCHEMALESS; DEFINE FIELD id ON kb_docs TYPE string; DEFINE FIELD text ON kb_docs TYPE string; DEFINE FIELD source ON kb_docs TYPE string; DEFINE FIELD embedding ON kb_docs TYPE array; DEFINE INDEX IF NOT EXISTS kb_vec ON kb_docs FIELDS embedding HNSW DIMENSION 1536 DIST COSINE; """) logger.info("Schema ensured successfully") exceptSurrealExceptionase: logger.error(f"Schema setup failed: {str(e)}") raiseSurrealException(f"Schema setup failed: {str(e)}")
# Example usage asyncdefmain(): retriever=SurrealRetriever() try: # Ensure schema exists awaitretriever.ensure_schema() # Ingest sample documents awaitretriever.ingest([ { "text": "Nikola Tesla patented the first practical AC induction motor in 1888.", "source": "wiki/Tesla" }, { "text": "The Wright brothers achieved powered flight on 17 Dec 1903.", "source": "wiki/Wright" }, ]) # Test retrieval result=awaitretriever.retrieve( "Who invented the AC motor and when?", k=2 ) print(result) exceptExceptionase: logger.error(f"Error: {str(e)}") raise
@Tool asyncdefknowledge_search(query: str) -> str: """Search SurrealDB for passages relevant to the query. Args: query: Search query Returns: Formatted string of matching passages """ try: returnawaitretriever.retrieve(query,k=4) exceptExceptionase: logger.error(f"Knowledge search failed: {str(e)}") returnf"Error searching knowledge base: {str(e)}"
@asynccontextmanager asyncdefget_agent(): """Get an agent instance with proper setup and teardown. Yields: Configured Agent instance """ try: agent=Agent( name="Surreal-Facts-Bot", llm="gemini-pro", instructions=""" You are a helpful assistant that must cite retrieved passages verbatim. When knowledge is required, call knowledge_search(). """, tools=[knowledge_search], ) logger.info("Agent created successfully") yieldagent exceptExceptionase: logger.error(f"Failed to create agent: {str(e)}") raise
asyncdefmain(): """Run the agent.""" try: asyncwithget_agent()asagent: response=awaitagent.chat("Who invented the AC motor and when?") print(response) logger.info("Agent execution completed successfully") exceptExceptionase: logger.error(f"Agent execution failed: {str(e)}") raise
if__name__=="__main__": asyncio.run(main())
Run locally (python agent.py) to verify the agent calls your SurrealDB tool.
gcloud ai agentspace agent-galleries add-agent \ --agent-engine=projects/$PROJECT/locations/us-central1/agentEngines/surreal-facts
Once added, employees will see "Surreal Facts Bot" in the gallery and can chat with it from the Agentspace UI; every time it needs knowledge it silently calls your SurrealDB index.
Operational notes
Topic
Guidance
Networking
Run SurrealDB on Cloud Run, GKE, or a VM inside the same VPC; use Private Service Connect so the Agent Engine can reach it.
Security
Protect the DB with DEFINE ACCESS tokens or basic auth; Agentspace inherits IAM & VPC-SC you already set in Agent Builder (Google Cloud).
Hybrid search
Mix Boolean filters with the <|K|> operator (WHERE source ~ 'wiki' AND embedding <|3|>).
Updates
New docs can be inserted at any time; SurrealDB's HNSW index updates incrementally, or run REBUILD INDEX during low-traffic windows (SurrealDB).