이 사례 연구에서는 AgentChat을 ProjectDesk라는 멀티테넌트 프로젝트 SaaS에 통합합니다. 모든 고객은 동일한 프로젝트 API와 작업 API를 사용하지만, 사용자 Alice는 workspace_a에서만 작업할 수 있고 사용자 Bob은 workspace_b에서만 작업할 수 있습니다. 하나의 API 문서를 재사용하면서 쓰기 전용 요청 헤더가 서로 다른 두 개의 세션을 생성합니다.
보안 경계는 모델에게 워크스페이스 내부에 머물라고 요청하는 프롬프트가 아닙니다. ProjectDesk는 모든 HTTP 도구 요청을 인증하고 권한을 부여합니다. AgentChat은 작업을 선택하고 올바른 세션 자격 증명을 주입하며, 각 작업의 허용 여부는 ProjectDesk가 결정합니다.
1단계: 비즈니스 API를 테넌트 인식형으로 만들기
GET /v1/projects?status=active
→ { "items": [{ "project_id": "proj_12", "name": "Website launch", "role": "editor" }] }
POST /v1/projects/proj_12/tasks
{ "title": "Review launch checklist", "due_at": "2026-08-28" }
→ { "task_id": "task_91", "project_id": "proj_12", "status": "open" } ProjectDesk는 전달자 토큰을 검증하고, 여기서 사용자 ID를 도출하며, X-Workspace-ID 워크스페이스의 구성원인지 확인한 후 해당 워크스페이스를 모든 데이터베이스 쿼리에 추가합니다. 프로젝트 ID만으로는 테넌트 필터를 우회할 수 없습니다. 읽기 스코프와 쓰기 스코프는 별도로 확인됩니다.
2단계: 재사용 가능한 ProjectDesk 문서 하나 등록
POST $AGENTCHAT_SITE_URL/api/api-documents
Authorization: Bearer ac_live_AGENTCHAT_KEY
Content-Type: application/json
{
"title": "ProjectDesk Projects and Tasks",
"description": "List authorized projects and create tasks inside them.",
"content": "# ProjectDesk API\nBase URL: https://projects.example.com/v1\n\nGET /projects?status=active returns only projects visible to the authenticated workspace member. Response items contain project_id, name, and role.\n\nPOST /projects/{project_id}/tasks body: title required, due_at optional ISO date. Create only after resolving a project through GET /projects. Response contains task_id, project_id, and status.\n\n401 means the session credential is missing or expired. 403 means the current member lacks permission. On either response, do not retry and tell the user that the chat credential or role must be updated."
} 이 문서는 ID가 아니라 기능을 설명합니다. ProjectDesk는 반환된 문서 UUID를 한 번만 저장하고, 이를 모든 테넌트의 채팅에 연결합니다. 문서에는 테넌트 ID, 사용자 토큰 또는 시크릿이 포함되지 않습니다.
3단계: Alice의 AgentChat 세션 생성
POST $AGENTCHAT_SITE_URL/api/agent/sessions
Authorization: Bearer ac_live_AGENTCHAT_KEY
Content-Type: application/json
{
"title": "ProjectDesk assistant — Alice",
"llm_config_id": "llm_config_uuid",
"api_document_ids": ["projectdesk_document_uuid"],
"system_prompt": "Help the current member manage projects. Never infer access from names; rely on API results.",
"max_turns": 10,
"host_headers": [
{ "host": "projects.example.com", "header_key": "Authorization", "header_value": "Bearer alice_short_lived_token" },
{ "host": "projects.example.com", "header_key": "X-Workspace-ID", "header_value": "workspace_a" }
]
} 세션 응답에는 일반적인 구성 정보가 포함되지만 header_value는 반환되지 않습니다. AgentChat은 일치하는 HTTP 요청에 Alice의 토큰을 주입할 수 있지만, 모델은 토큰이나 저장된 인증 헤더를 어느 것도 볼 수 없습니다.
4단계: 동일한 문서에서 Bob의 세션 생성
POST $AGENTCHAT_SITE_URL/api/agent/sessions
Authorization: Bearer ac_live_AGENTCHAT_KEY
Content-Type: application/json
{
"title": "ProjectDesk assistant — Bob",
"llm_config_id": "llm_config_uuid",
"api_document_ids": ["projectdesk_document_uuid"],
"system_prompt": "Help the current member manage projects. Never infer access from names; rely on API results.",
"max_turns": 10,
"host_headers": [
{ "host": "projects.example.com", "header_key": "Authorization", "header_value": "Bearer bob_short_lived_token" },
{ "host": "projects.example.com", "header_key": "X-Workspace-ID", "header_value": "workspace_b" }
]
} API 계약과 모델 구성은 공유할 수 있지만, 세션 헤더가 각 대화의 호출자를 지정합니다. 이를 통해 고객마다 중복 문서를 생성할 필요가 없으며, 자격 증명 교체를 기능 문서와 독립적으로 수행할 수 있습니다.
5단계: 두 세션에서 동일한 지침 실행
POST /api/agent/sessions/alice_session_uuid/chat
{ "message": "Create a task called Review launch checklist in the Website launch project, due August 28." }
POST /api/agent/sessions/bob_session_uuid/chat
{ "message": "Create a task called Review launch checklist in the Website launch project, due August 28." } Alice의 경우 http_request는 Alice의 토큰과 workspace_a를 projects.example.com에만 전송합니다. ProjectDesk는 Alice에게 표시되는 프로젝트를 반환하고, 에이전트는 해당 결과에서 요청된 프로젝트를 확인한 후 작업을 게시합니다. Bob의 실행도 동일한 계획을 따르지만, ProjectDesk는 workspace_b를 기준으로 필터링합니다. Bob이 해당 프로젝트를 볼 수 없다면 에이전트는 일치하는 프로젝트를 받지 못하므로 Alice의 프로젝트 ID를 임의로 만들어 내거나 재사용해서는 안 됩니다.
호스트 매칭으로 자격 증명 유출을 방지하는 방법
AgentChat은 HTTP 대상이 구성된 호스트 이름 및 선택적 포트와 일치할 때만 세션 헤더를 삽입합니다. 리디렉션은 각 홉마다 다시 일치 여부를 확인합니다. 따라서 projects.example.com에 대한 자격 증명이 files.example.net, 이미지 호스트 또는 예상하지 못한 리디렉션 대상으로 전달되지 않습니다.
권한 오류는 어떻게 표시되는가
HTTP/1.1 403 Forbidden
Content-Type: application/json
{ "error": "insufficient_scope", "required_scope": "tasks:write" } AgentChat의 지침은 401 및 403을 자격 증명 구성 문제로 처리합니다. 에이전트는 차단된 작업을 중지하고 어떤 권한을 확인해야 하는지 사용자에게 알려야 합니다. 채팅에서 비밀 정보를 요청하거나, 저장된 헤더 값을 공개하거나, 거부된 요청을 반복해서 재시도해서는 안 됩니다.
ProjectDesk는 거부 응답을 유용하면서도 민감한 정보를 포함하지 않도록 해야 합니다. 교차 테넌트 레코드가 존재하는지 여부를 확인하지 않고도 필요한 스코프를 명시할 수 있습니다. 감사 로그에는 검증된 행위자와 시도된 리소스를 기록하되, 전달자 토큰 및 기타 헤더 값은 마스킹해야 합니다.
6단계: AgentChat 상태와 ProjectDesk 상태를 별도로 사용하기
GET /api/agent/sessions/alice_session_uuid/messages?after_id=&after_revision=0
GET /api/agent/sessions/alice_session_uuid/state
GET https://projects.example.com/v1/projects/proj_12/tasks ProjectDesk의 채팅 UI는 AgentChat 메시지를 폴링하고 처리 중에 어시스턴트의 수정 내용을 병합합니다. 실행이 완료되면 프로젝트 보드는 ProjectDesk API 또는 데이터베이스에서 작업을 다시 로드합니다. 어시스턴트의 응답은 작업을 설명하지만, 권위 있는 제품 상태는 문구가 아니라 저장된 작업 레코드입니다.
서로 다른 권한 수준에는 별도의 세션을 사용하기
읽기 전용 어시스턴트는 읽기 스코프로 제한된 토큰을 사용해 검색 및 보고서 작성 문서를 연결할 수 있습니다. 프로젝트 편집자는 쓰기 스코프 토큰을 사용해 작업 작성 문서를 연결할 수 있습니다. 결제 정보 변경, 계정 삭제 또는 공개 게시와 같은 고위험 작업에는 더 제한적인 세션이나 제품 측의 승인 대기 엔드포인트를 사용해야 합니다.
승인 흐름에서 에이전트는 보류 중인 작업을 생성하고 해당 ID를 반환합니다. ProjectDesk는 사용자에게 정확한 변경 내용을 표시하고 명시적인 승인을 기록한 다음, 되돌릴 수 없는 작업을 자체 백엔드에서 수행합니다. 최종 권한 부여 결정은 모델이 확인 문구를 해석하는 데 절대 의존하지 않습니다.
프로덕션 격리 테스트
- Alice의 세션을 사용해 알려진 workspace_b 프로젝트 ID를 요청하고, ProjectDesk가 테넌트 간 데이터를 반환하지 않는지 확인합니다.
- Alice와 Bob에게 동일한 프롬프트를 실행하고, 각자의 HTTP 호출이 서로 다른 권한 부여 결과를 받는지 확인합니다.
- 각 세션 토큰을 만료시키거나 폐기하거나 누락시키거나 손상시킨 뒤, 올바른 401 동작이 나타나는지 확인합니다.
- 멤버에게 읽기 전용 스코프를 부여하고 데이터베이스를 변경하지 않은 상태에서 모든 작업 쓰기 요청이 403을 반환하는지 확인합니다.
- 요청을 다른 호스트 이름으로 리디렉션하고 AgentChat이 구성된 자격 증명을 전달하지 않는지 확인합니다.
- 세션 API 응답, 도구 결과, 애플리케이션 로그 및 오류 메시지를 검사하여 비밀 정보가 유출되지 않는지 확인합니다.
- 실행을 중지했다가 계속한 다음, 재개된 작업에서도 해당 세션의 헤더와 문서 바인딩만 사용되는지 확인합니다.
재사용 가능한 멀티테넌트 패턴
비즈니스 기능을 한 번만 등록합니다. 사용자 대화마다 AgentChat 세션을 하나씩 생성합니다. 관련 문서 UUID를 연결하고, 정확한 API 호스트를 위한 단기 유효 자격 증명을 주입하며, SaaS 엔드포인트 내부에서 ID와 정책을 적용합니다. 그런 다음 추론과 영구적인 대화 상태 관리는 AgentChat에 맡기고, 자체 데이터베이스는 신뢰할 수 있는 단일 정보 소스로 유지합니다.