This tutorial builds an agent with function calling where the tool exposed to the model never executes arbitrary SQL. It combines two mechanisms already verified in the Aurabase code: the NL2SQL validator and a read-only Postgres transaction, two bricks of thenative AI integrated into thebackend. Prerequisites: an Aurabase project, its service_rolekey, and an account with one of the three native LLM providers (OpenAI, Anthropic, Gemini).
필수사항
- 실제 위험은 자체를 호출하는 함수가 아니라 모델에 노출된 도구입니다. 원시
execute_sql(query)는 전체 SQL 액세스를 제공합니다. - 안전한 아키텍처는 직접 실행이 아닌 구문 트리 유효성 검사기(SELECT만, 제한된 LIMIT, 격리된 스키마)에 위임하는
query_database(question)도구를 노출합니다. - Aurabase는 이 유효성 검사기를 기본적으로 노출합니다(
/nl2sql). 이를 도구 구현으로 재사용하면 SQL 유효성 검사를 직접 다시 코딩할 필요가 없습니다. - 그런 다음 커밋된 SQL은 단순한 텍스트 필터가 아닌 실제 읽기 전용 Postgres 트랜잭션인
readOnly: true모드에서aura.db.sql()을 통해 실행됩니다. - Aurabase의 기본
/chat엔드포인트는 아직tool역할이나tools매개변수(코드에서 확인됨)를 허용하지 않습니다. 에이전트 루프는 현재 Aurabase 프록시가 아닌 LLM 공급자의 SDK를 통해 실행됩니다. service_role키는 설계상 RLS를 우회합니다. 즉, 백엔드를 벗어나면 안 되며 에이전트는 일반적인 인증된 사용자보다 더 광범위한 액세스 권한을 상속받습니다.
무엇을 구축할 것인가
모델이 있는 그대로 실행되는 SQL을 작성하지 않고도 Postgres 프로젝트의 데이터에 대한 자연어 질문에 대답하는 에이전트를 구축하게 됩니다. 모델은 query_database라는 도구를 호출합니다. 이 도구는 질문을 NL2SQL을 통해 검증된 SQL로 변환한 다음 이 읽기 전용 SQL을 실행하고 해당 행을 모델에 반환하여 답을 공식화합니다.
이 튜토리얼에서는 서버 측의 @aurabase/aurabase-js JavaScript SDK(브라우저 측에서는 절대 사용하지 않으며 service_role 키가 클라이언트에 노출되어서는 안 됨)와 에이전트 루프용 API를 호출하는 OpenAI 함수를 사용합니다. Anthropic 또는 Gemini SDK에도 동일한 원칙이 적용됩니다.
"이 SQL 실행" 도구가 위험한 이유
일부 공식 가이드를 포함한 대부분의 Postgres 에이전트 튜토리얼은 단일 도구, 즉 SQL 문자열을 인수로 사용하여 있는 그대로 실행하는 execute_sql 함수를 정의합니다. 모델은 사용자의 질문과 컨텍스트에 제공된 스키마를 기반으로 이 문자열 자체를 작성합니다.
이 선택은 안정적으로 수행할 수 없는 책임을 모델에 이전합니다. 질문에 신속한 삽입을 하면 도구가 "적법한" 쿼리가 어떻게 생겼는지에 대한 개념이 없기 때문에 무분별하게 실행되는 파괴적인 SQL이 생성될 수 있습니다. 당사의 전용 기사에서는 이 공격 벡터에 대해 자세히 설명합니다: SQL 주입으로부터 NL2SQL 보호.
이 튜토리얼에서 구축된 대안은 더 좁은 도구인 query_database(question)를 노출합니다. 모델은 더 이상 SQL을 직접 작성할 수 없으며 자체 도구 호출에서만 질문할 수 있습니다. Aurabase NL2SQL 엔진은 이 질문을 구문 트리 유효성 검사기(SELECT 단독, 하위 쿼리 없음, 10개 함수 승인, 제한된 LIMIT)를 통해 전달하기 전에 SQL로 변환합니다.
execute_sql(query: string) 도구는 시스템 프롬프트가 얼마나 좋은지에 관계없이 모델에 전체 SQL 액세스를 제공합니다. 명령("SELECT만 실행")은 모델이 사용자의 질문에 삽입하여 따르거나 잘못 해석하거나 회피할 수 있는 명령으로 남아 있습니다.
모델에 노출된 도구의 스키마 정의
Aurabase의 세 가지 기본 LLM 제공업체(OpenAI, Anthropic, Gemini)는 JSON 스키마 형식의 도구 정의 테이블을 허용합니다. 이 에이전트에는 단일 도구로 충분합니다: query_database. 이 도구는 자연어로 질문을 받고 다른 것은 필요하지 않습니다. 모델은 SQL 스키마나 자체적으로 채울 수 있는 query 필드를 볼 수 없습니다.
도구 구현: NL2SQL 이후 읽기 전용
도구 핸들러는 백엔드에서 실행되며 브라우저에서는 실행되지 않습니다. 이는 설계상 RLS를 우회하므로 클라이언트에 절대 노출되어서는 안 되는 프로젝트 키 service_role를 전달합니다. Aurabase SDK를 두 번 호출합니다.
첫 번째 호출은 질문을 aura.ai.nl2sql()를 통해 검증된 SQL로 변환합니다. SELECT만 가능, LIMIT 제한됨, 시스템 카탈로그에 대한 액세스 불가. 두 번째는 readOnly: true 옵션을 사용하여 aura.db.sql()를 통해 이미 검증된 이 SQL을 실행합니다. 그런 다음 Postgres 자체는 NL2SQL 업스트림에서 이미 적용된 텍스트 검증과 관계없이 이 트랜잭션의 쓰기를 거부합니다.
readOnly: true는 실제 읽기 전용 Postgres 트랜잭션을 트리거합니다. 엔진은 쓰기를 거부하며 요청 텍스트에 적용되는 필터가 아닙니다. NL2SQL의 SELECT 전용 유효성 검사와 결합된 에이전트에는 두 개의 독립적인 계층이 있습니다. 하나에 결함이 있으면 다른 하나는 여전히 유지됩니다.
에이전트 루프: 공급자의 SDK 측에서 호출하는 함수
Aurabase는 세 가지 기본 LLM 공급자를 노출하지만 해당 /chat 엔드포인트는 아직 tools 매개변수 또는 tool역할을 전달하지 않습니다. ChatOptions는 temperature, max_tokens 및 model만 전달하며 허용되는 역할은 system, user 및 assistant(llm/mod.rs 및 handlers/chat.rs에서 확인됨)로 제한됩니다. 따라서 함수 호출 루프는 현재 Aurabase 프록시가 아닌 공급자의 SDK를 통해 직접 실행됩니다.
Aurabase가 도구 호출을 기본적으로 조정하지 않는 한, 백엔드는 OpenAI, Anthropic 또는 Gemini SDK를 사용하여 루프 자체를 관리해야 합니다. NL2SQL 및 SQL 실행은 이 루프 내에서 클래식 Aurabase 호출로 유지됩니다.
LangChain 또는 Azure AI 에이전트와 같은 서비스를 사용하여 에이전트를 오케스트레이션하는 경우 원칙은 동일하게 유지됩니다. 프레임워크에 선언된 도구는 원시 SQL 실행자가 아닌 동일한 query_database로 유지되어야 합니다. LangChain과 LlamaIndex가 Postgres에 실제 가치를 제공하는 부분과 특히 복잡성을 추가하는 부분에 대한 비교 세부 정보: LangChain 또는 LlamaIndex를 사용하는 Postgres 에이전트.
실제 질문으로 테스트하기
상담원에게 보낸 질문: "이번 달에 주문한 프리미엄 고객 수는 몇 명입니까?" ". 템플릿은 SQL을 보거나 작성하지 않고 있는 그대로 이 질문으로 query_database을 호출합니다. 다음은 도구에 의해 트리거된 두 내부 호출의 결과입니다.
모델의 최종 답은 추측이 아닌 실제 선을 기반으로 합니다. 도구가 0개의 행을 반환하는 경우 확인된 데이터 없이 응답하는 모델을 사용할 때보다 숫자 환각이 발생할 가능성이 훨씬 줄어듭니다.
프로덕션에 들어가기 전에 에이전트를 확보하세요
service_role키는 백엔드를 떠나지 않습니다. 모델로 전송된 프롬프트나 로그, 클라이언트 측 환경 변수에서도 마찬가지입니다.- 프로젝트가 애플리케이션의 다른 곳에 작성해야 하는 경우에도
readOnly: true은 이 특정 도구에 대해aura.db.sql()에서 활성 상태로 유지됩니다. service_role는 설계상 RLS를 우회합니다. 에이전트가 질문하는 사용자에 따라 다르게 응답해야 하는 경우 SQL에서 명시적으로 필터링하거나 RLS를 존중하는 클래식 PostgREST 엔드포인트로 대체하세요. 다중 테넌트 RLS 격리를 참조하세요.- 각 도구 호출(질문, 검증된 SQL, 줄 수)을 기록합니다. 이는 질문이 예상치 못한 결과를 생성하는 경우 사용할 수 있는 유일한 추적입니다.
- Aurabase의 속도 제한 및 월별 할당량은 이미
/nl2sql의 프로젝트별로 적용됩니다. 수다스러운 에이전트는 조용히 AI 예산을 초과할 수 없습니다.
알아야 할 현재 제한 사항
query_database 도구는 NL2SQL 유효성 검사기의 모든 제한 사항(하위 쿼리 없음, CTE/WITH 없음, UNION 없음, 10개 SQL 함수의 폐쇄 목록)을 상속합니다. 자연스럽게 하위 쿼리를 요구하는 질문("주문한 적이 없는 고객")은 NL2SQL에 강제로 적용하기보다는 다시 공식화하거나 두 번째 전용 도구로 처리해야 합니다.
현재 Aurabase /chat 프록시 내부에는 도구 호출 오케스트레이션이 존재하지 않습니다. 여기에 설명된 에이전트 루프는 관리형 서비스가 아닌 애플리케이션 코드에 있습니다. 에이전트가 여러 도구(예: 데이터베이스 및 다큐멘터리 RAG)를 연결해야 하는 경우 두 통화를 조정하는 것은 백엔드입니다.
RAG와 함수 호출 결합
이 튜토리얼에서는 관계형 데이터에 대한 구조화된 질문을 다룹니다. 구조화되지 않은 콘텐츠(문서, 티켓, 메모)에 대한 질문의 경우 동일한 에이전트가 Aurabase의 기본 RAG(pgVector, HNSW 검색)에 연결된 두 번째 도구를 노출할 수 있습니다. 두 가지 기능과 해당 표현은 Postgres의 네이티브 AI페이지에 자세히 설명되어 있습니다.