본문으로 바로가기 본문 바로가기
WIKI 기술 지식 베이스

LangChain4j Agent

원문 보기 위키 갱신

LangChain4j Agent 컴포넌트는 LangChain4j 라이브러리와 통합해서 툴 호출, MCP, 대화 메모리, RAG, 가드레일을 갖춘 AI 에이전트를 Camel 라우트 안에서 구동해 주는 컴포넌트예요. Agent나 AgentConfiguration 빈만 등록하면 langchain4j-agent:agentId URI로 바로 쓸 수 있고, Camel 라우트 툴(ai-tool 컴포넌트)과 커스텀 LangChain4j 툴을 함께 엮을 수 있어요.

출처: 문서

본문

LangChain4j Agent

Camel 4.14부터 지원

producer만 지원해요

LangChain4j Agent 컴포넌트는 LangChain4j 라이브러리와의 통합을 통해 종합적인 AI 에이전트 기능을 제공해요. 이 컴포넌트는 툴 호출(tool calling), MCP(Model Context Protocol) 통합, 대화 메모리, 검색 증강 생성(RAG), 입력/출력 가드레일 같은 고급 AI 에이전트 패턴을 지원합니다.

주요 기능 (Features)

LangChain4j Agent 컴포넌트가 제공하는 핵심 기능은 다음과 같아요:

  • 에이전트 기반 아키텍처: Agent API 인터페이스로 유연하게 에이전트를 만들 수 있어요

  • 툴 통합: ai-tool 컴포넌트를 통해 Camel 라우트와 매끄럽게 통합돼요

  • MCP 툴: 외부 시스템 접근을 위해 MCP(Model Context Protocol) 툴과 통합돼요

  • 대화 메모리: 대화 맥락을 유지하는 영속 chat 메모리예요

  • RAG 지원: naive·advanced RAG를 위한 검색 시스템 통합이에요

  • 가드레일(Guardrails): 입력·출력 검증과 변환 기능이에요

  • 설정 유연성: AgentConfiguration으로 에이전트 설정을 한곳에 모아요

  • 멀티모달 콘텐츠: 파일 기반 Camel 컴포넌트로부터 이미지, PDF, 오디오, 비디오, 텍스트 파일을 다룰 수 있어요

컴포넌트 옵션 (Component Options)

이 컴포넌트는 핵심 옵션 두 개만 남기도록 단순화됐어요:

  • agent: Camel 레지스트리에 등록된 Agent 구현체 참조예요

  • tags: Camel 라우트 툴을 찾고 호출할 때 쓰는 태그예요 (선택)

나머지 설정(챗 모델, 메모리, RAG, 가드레일, 커스텀 툴, MCP 클라이언트)은 에이전트를 만들 때 AgentConfiguration으로 처리해요.

URI 형식 (URI Format)

langchain4j-agent:agentId[?options]

여기서 agentId는 에이전트 인스턴스의 고유 식별자예요.

옵션 설정 방법 (Configuring Options)

Camel 컴포넌트는 두 단계로 나눠 설정합니다:

  • 컴포넌트(component) 레벨

  • 엔드포인트(endpoint) 레벨

컴포넌트 옵션 설정 (Configuring Component Options)

컴포넌트 레벨에서는 엔드포인트들이 이어서 물려받는 일반적이고 공유되는 설정을 해요. 가장 상위의 설정 레벨이죠.

예를 들어 컴포넌트에는 보안 설정, 인증용 자격 증명, 네트워크 연결 URL 같은 것들이 있을 수 있어요.

컴포넌트에 따라 옵션이 몇 개뿐인 것도 있고 아주 많은 것도 있어요. 컴포넌트는 보통 널리 쓰이는 기본값이 미리 설정되어 있어서, 몇 가지 옵션만 설정하거나 아예 하나도 건드리지 않아도 되는 경우가 많아요.

컴포넌트는 다음 방법으로 설정할 수 있어요:

  • the Component DSL.

  • 설정 파일(application.properties, *.yaml 파일 등).

  • Java 코드에서 직접.

엔드포인트 옵션 설정 (Configuring Endpoint Options)

엔드포인트는 옵션이 많아서 설정에 시간을 더 쓰게 될 거예요. 이 옵션들이 엔드포인트가 원하는 일을 하도록 커스터마이즈해 줘요. 옵션은 엔드포인트가 consumer(from)로 쓰이는지, producer(to)로 쓰이는지, 둘 다인지에 따라 분류되기도 해요.

엔드포인트 설정은 대부분 엔드포인트 URI에 _path_와 query 파라미터로 바로 하는 경우가 많아요. Java에서 엔드포인트와 데이터 포맷을 _타입 세이프_하게 설정하려면 Endpoint DSL과 DataFormat DSL을 쓸 수도 있어요.

옵션을 설정할 때 좋은 습관은 Property Placeholders를 사용하는 거예요.

프로퍼티 플레이스홀더는 이런 장점이 있어요:

  • URL, 포트 번호, 민감한 정보 같은 설정을 하드코딩하는 걸 막아 줘요.

  • 설정을 코드 밖으로 분리할 수 있어요.

  • 코드가 더 유연해지고 재사용하기 좋아져요.

다음 두 섹션에서 모든 옵션을 나열해요. 먼저 컴포넌트 옵션, 그다음 엔드포인트 옵션 순서예요.

컴포넌트 옵션 (Component Options)

LangChain4j Agent 컴포넌트가 지원하는 옵션은 아래와 같아요.

Name Description Default Type
agent (producer) Autowired 컴포넌트에서 사용할 agent예요. Agent
agentConfiguration (producer) Autowired Camel이 내부적으로 에이전트를 만들 때 쓰는 AgentConfiguration이에요. 설정하면 ChatMemoryProvider가 구성되어 있을 때는 AgentWithMemory를, 아니면 AgentWithoutMemory를 만들어요. agentFactory도 함께 설정되어 있으면 factory가 우선해요. AgentConfiguration
agentFactory (producer) Autowired Agent가 제공되지 않을 때 에이전트를 만들기 위해 사용할 agent factory예요. AgentFactory
compensateOnToolErrors (producer) 툴 실행이 실패했을 때 LangChain4j가 보상(compensate)할지 여부예요. 인라인 에이전트 생성 모드(agent나 agentFactory 없이 agentConfiguration)에서만 지원해요. URI 값이 agentConfiguration 빈의 같은 옵션을 덮어요. false Boolean
configuration (producer) 설정이에요. LangChain4jAgentConfiguration
executeToolsConcurrently (producer) 한 번의 LLM 턴에서 요청된 여러 툴을 동시에 실행할지 여부예요. Camel 라우트 툴은 격리된 exchange 복사본에서 실행돼요. 인라인 에이전트 생성 모드(agent나 agentFactory 없이 agentConfiguration)에서만 지원해요. URI 값이 agentConfiguration 빈의 같은 옵션을 덮어요. false Boolean
jsonSchema (producer) 구조화된 출력 검증용 JSON 스키마예요. 인라인 에이전트 생성 모드에서만 지원해요. agentConfiguration을 설정해야 하고 agent나 agentFactory는 설정하면 안 돼요. outputClass와 상호 배타적이에요. String
lazyStartProducer (producer) producer를 lazy(첫 메시지 시점)로 시작할지 여부예요. lazy 시작을 쓰면 producer가 시작 중 실패해서 라우트 시작이 실패하는 상황에서도 CamelContext와 라우트를 시작할 수 있고, 시작 실패 처리를 Camel의 라우팅 에러 핸들러로 넘길 수 있어요. 다만 첫 메시지를 처리하는 시점에 producer를 만들고 시작하는 데 시간이 조금 걸려서 전체 처리 시간이 길어질 수 있다는 점은 유의하세요. false boolean
maxToolCallingRoundTrips (producer) 요청당 허용되는 툴 호출 라운드 트립의 최대 횟수예요. 각 라운드 트립은 LLM 호출 한 번과 그 호출에서 요청된 툴 실행으로 이루어져요. 0으로 두면 unset이 되고 LangChain4j 기본값을 사용해요. 인라인 에이전트 생성 모드(agent나 agentFactory 없이 agentConfiguration)에서만 지원해요. URI 값이 agentConfiguration 빈의 같은 옵션을 덮어요. 0 int
outputClass (producer) 구조화된 출력에 사용할 Java 클래스예요. Camel이 클래스에서 JSON 스키마를 도출하고 그에 맞는 JSON을 만들라고 모델에 지시해요. 응답 body는 raw JSON 문자열 그대로 유지돼요. 인라인 에이전트 생성 모드에서만 지원해요. agentConfiguration을 설정해야 하고 agent나 agentFactory는 설정하면 안 돼요. 클래스는 public 필드나 getter를 가진 POJO여야 해요. 단순 타입, enum, 컬렉션은 지원하지 않아요. jsonSchema와 상호 배타적이에요. Class
tags (producer) Camel 라우트 툴을 발견하고 호출할 때 쓰는 태그예요. String
autowiredEnabled (advanced) autowiring이 켜져 있는지 여부예요. 레지스트리에서 일치하는 타입의 인스턴스가 단 하나 있는지 찾아서 컴포넌트에 자동으로 설정하는, 자동 autowiring 옵션(옵션에 autowired 표시가 필요해요)을 위해 사용돼요. JDBC 데이터 소스, JMS 커넥션 팩토리, AWS 클라이언트 등의 자동 설정에 쓸 수 있어요. true boolean
mcpClients (advanced) 외부 툴 통합용으로 미리 만들어진 MCP(Model Context Protocol) 클라이언트 인스턴스예요. 레지스트리의 빈을 참조해요. 예: #myMcpClient1,#myMcpClient2. List
mcpServer (advanced) mcpServer..= 형태의 MCP 서버 정의예요. 지원 프로퍼티: transportType (stdio, http 또는 streamableHttp, 기본값: stdio), command (쉼표 구분, stdio용), url (http/streamableHttp용), environment.= (stdio용), timeout (초 단위, 기본값: 60), logRequests, logResponses, oauthProfile (HTTP 인증용 OAuth 프로파일, camel-oauth 필요). mcpServer 접두어를 가진 다중 값 옵션이에요. Map
baseUrl (model) 모델을 프로바이더에서 만들 때 프로바이더 API의 URL이에요(로컬 Ollama는 http://localhost:11434). 설정하지 않으면 프로바이더 기본값을 사용해요. String
modelName (model) 모델을 프로바이더에서 만들 때 프로바이더에서의 모델 이름이에요(qwen2.5, gpt-4o-mini, …​). String
provider (model)
agent를 구동하는 챗 모델의 LangChain4j 프로바이더예요. AgentConfiguration 빈 대신 여기의 옵션(modelName, baseUrl, apiKey, temperature, timeout, 그리고 프로바이더별 model. 프로퍼티)으로 모델을 만들어요. 해당 프로바이더의 LangChain4j 모듈(dev.langchain4j:langchain4j-ollama, …​)이 클래스패스에 있어야 해요. Camel JBang은 이걸 자동으로 내려받아요. AgentConfiguration이 설정되어 있으면 무시돼요. 목록에 없는 프로바이더는 customProvider로 설정하세요.

Enum values:

  • ollama

  • openai

  • anthropic

  • azure-openai

  • mistral

  • gemini

  • vertex-ai

  • github

  • hugging-face

  • bedrock

| | String | | temperature (model) | 모델을 프로바이더에서 만들 때 모델의 샘플링 temperature예요. | | Double | | timeout (model) | 모델을 프로바이더에서 만들 때 모델의 요청 타임아웃이에요(30s, 2m). | | Duration | | customProvider (model (advanced)) | provider에 나열되지 않은 프로바이더의 LangChain4j 모델 클래스 완전한 클래스 이름이에요(dev.langchain4j.model.jlama.JlamaChatModel). 나열된 프로바이더처럼 builder()를 통해 여기의 옵션으로 모델을 만들어요. provider나 customProvider 중 하나만 설정하세요. | | String | | modelProperties (model (advanced)) | 모델을 프로바이더에서 만들 때 모델의 프로바이더별 프로퍼티예요. 그대로 모델 빌더에 설정돼요(Ollama는 model.numPredict=512, OpenAI는 model.maxTokens=1024). model 접두어를 가진 다중 값 옵션이에요. | | Map | | apiKey (security) | 모델을 프로바이더에서 만들 때 프로바이더의 API 키 또는 액세스 토큰이에요. | | String |

엔드포인트 옵션 (Endpoint Options)

LangChain4j Agent 엔드포인트는 다음 URI 문법으로 설정해요:

langchain4j-agent:agentId

다음의 _path_와 query 파라미터를 사용해요:

경로 파라미터 (Path Parameters)

Name Description Default Type
agentId (producer) 필수 Agent id예요. String

쿼리 파라미터 (Query Parameters)

Name Description Default Type
agent (producer) Autowired 컴포넌트에서 사용할 agent예요. Agent
agentConfiguration (producer) Autowired Camel이 내부적으로 에이전트를 만들 때 쓰는 AgentConfiguration이에요. 설정하면 ChatMemoryProvider가 구성되어 있을 때는 AgentWithMemory를, 아니면 AgentWithoutMemory를 만들어요. agentFactory도 함께 설정되어 있으면 factory가 우선해요. AgentConfiguration
agentFactory (producer) Autowired Agent가 제공되지 않을 때 에이전트를 만들기 위해 사용할 agent factory예요. AgentFactory
compensateOnToolErrors (producer) 툴 실행이 실패했을 때 LangChain4j가 보상(compensate)할지 여부예요. 인라인 에이전트 생성 모드(agent나 agentFactory 없이 agentConfiguration)에서만 지원해요. URI 값이 agentConfiguration 빈의 같은 옵션을 덮어요. false Boolean
executeToolsConcurrently (producer) 한 번의 LLM 턴에서 요청된 여러 툴을 동시에 실행할지 여부예요. Camel 라우트 툴은 격리된 exchange 복사본에서 실행돼요. 인라인 에이전트 생성 모드(agent나 agentFactory 없이 agentConfiguration)에서만 지원해요. URI 값이 agentConfiguration 빈의 같은 옵션을 덮어요. false Boolean
jsonSchema (producer) 구조화된 출력 검증용 JSON 스키마예요. 인라인 에이전트 생성 모드에서만 지원해요. agentConfiguration을 설정해야 하고 agent나 agentFactory는 설정하면 안 돼요. outputClass와 상호 배타적이에요. String
maxToolCallingRoundTrips (producer) 요청당 허용되는 툴 호출 라운드 트립의 최대 횟수예요. 각 라운드 트립은 LLM 호출 한 번과 그 호출에서 요청된 툴 실행으로 이루어져요. 0으로 두면 unset이 되고 LangChain4j 기본값을 사용해요. 인라인 에이전트 생성 모드(agent나 agentFactory 없이 agentConfiguration)에서만 지원해요. URI 값이 agentConfiguration 빈의 같은 옵션을 덮어요. 0 int
outputClass (producer) 구조화된 출력에 사용할 Java 클래스예요. Camel이 클래스에서 JSON 스키마를 도출하고 그에 맞는 JSON을 만들라고 모델에 지시해요. 응답 body는 raw JSON 문자열 그대로 유지돼요. 인라인 에이전트 생성 모드에서만 지원해요. agentConfiguration을 설정해야 하고 agent나 agentFactory는 설정하면 안 돼요. 클래스는 public 필드나 getter를 가진 POJO여야 해요. 단순 타입, enum, 컬렉션은 지원하지 않아요. jsonSchema와 상호 배타적이에요. Class
tags (producer) Camel 라우트 툴을 발견하고 호출할 때 쓰는 태그예요. String
lazyStartProducer (producer (advanced)) producer를 lazy(첫 메시지 시점)로 시작할지 여부예요. lazy 시작을 쓰면 producer가 시작 중 실패해서 라우트 시작이 실패하는 상황에서도 CamelContext와 라우트를 시작할 수 있고, 시작 실패 처리를 Camel의 라우팅 에러 핸들러로 넘길 수 있어요. 다만 첫 메시지를 처리하는 시점에 producer를 만들고 시작하는 데 시간이 조금 걸려서 전체 처리 시간이 길어질 수 있다는 점은 유의하세요. false boolean
mcpClients (advanced) 외부 툴 통합용으로 미리 만들어진 MCP(Model Context Protocol) 클라이언트 인스턴스예요. 레지스트리의 빈을 참조해요. 예: #myMcpClient1,#myMcpClient2. List
mcpServer (advanced) mcpServer..= 형태의 MCP 서버 정의예요. 지원 프로퍼티: transportType (stdio, http 또는 streamableHttp, 기본값: stdio), command (쉼표 구분, stdio용), url (http/streamableHttp용), environment.= (stdio용), timeout (초 단위, 기본값: 60), logRequests, logResponses, oauthProfile (HTTP 인증용 OAuth 프로파일, camel-oauth 필요). mcpServer 접두어를 가진 다중 값 옵션이에요. Map
baseUrl (model) 모델을 프로바이더에서 만들 때 프로바이더 API의 URL이에요(로컬 Ollama는 http://localhost:11434). 설정하지 않으면 프로바이더 기본값을 사용해요. String
modelName (model) 모델을 프로바이더에서 만들 때 프로바이더에서의 모델 이름이에요(qwen2.5, gpt-4o-mini, …​). String
provider (model)
agent를 구동하는 챗 모델의 LangChain4j 프로바이더예요. AgentConfiguration 빈 대신 여기의 옵션(modelName, baseUrl, apiKey, temperature, timeout, 그리고 프로바이더별 model. 프로퍼티)으로 모델을 만들어요. 해당 프로바이더의 LangChain4j 모듈(dev.langchain4j:langchain4j-ollama, …​)이 클래스패스에 있어야 해요. Camel JBang은 이걸 자동으로 내려받아요. AgentConfiguration이 설정되어 있으면 무시돼요. 목록에 없는 프로바이더는 customProvider로 설정하세요.

Enum values:

  • ollama

  • openai

  • anthropic

  • azure-openai

  • mistral

  • gemini

  • vertex-ai

  • github

  • hugging-face

  • bedrock

| | String | | temperature (model) | 모델을 프로바이더에서 만들 때 모델의 샘플링 temperature예요. | | Double | | timeout (model) | 모델을 프로바이더에서 만들 때 모델의 요청 타임아웃이에요(30s, 2m). | | Duration | | customProvider (model (advanced)) | provider에 나열되지 않은 프로바이더의 LangChain4j 모델 클래스 완전한 클래스 이름이에요(dev.langchain4j.model.jlama.JlamaChatModel). 나열된 프로바이더처럼 builder()를 통해 여기의 옵션으로 모델을 만들어요. provider나 customProvider 중 하나만 설정하세요. | | String | | modelProperties (model (advanced)) | 모델을 프로바이더에서 만들 때 모델의 프로바이더별 프로퍼티예요. 그대로 모델 빌더에 설정돼요(Ollama는 model.numPredict=512, OpenAI는 model.maxTokens=1024). model 접두어를 가진 다중 값 옵션이에요. | | Map | | apiKey (security) | 모델을 프로바이더에서 만들 때 프로바이더의 API 키 또는 액세스 토큰이에요. | | String |

메시지 헤더 (Message Headers)

LangChain4j Agent 컴포넌트가 지원하는 메시지 헤더는 아래와 같아요:

Name Description Default Type
CamelLangChain4jAgentSystemMessage (producer) Constant: SYSTEM_MESSAGE 시스템 프롬프트예요. String
CamelLangChain4jAgentMemoryId (producer) Constant: MEMORY_ID 메모리 ID예요. Object
CamelLangChain4jAgentUserMessage (producer) Constant: USER_MESSAGE WrappedFile을 입력으로 쓸 때 파일 콘텐츠와 함께 보내는 사용자 메시지예요. String
CamelLangChain4jAgentMediaType (producer) Constant: MEDIA_TYPE 파일 콘텐츠의 미디어 타입(MIME 타입)이에요. 파일 확장자 기반 자동 감지를 덮어요. String
CamelLangChain4jAgentExcludeTags (producer) Constant: EXCLUDE_TAGS 이 에이전트 호출에서 제외할 Camel 툴 태그 목록이에요. 쉼표로 구분해요. String
CamelLangChain4jAgentExcludeMcpServers (producer) Constant: EXCLUDE_MCP_SERVERS 이 에이전트 호출에서 제외할 MCP 서버 이름(키) 목록이에요. 쉼표로 구분해요. String
CamelLangChain4jAgentFinishReason (producer) Constant: FINISH_REASON
Finish Reason이에요.

Enum values:

  • STOP

  • LENGTH

  • TOOL_EXECUTION

  • CONTENT_FILTER

  • OTHER

| | FinishReason | | CamelLangChain4jAgentInputTokenCount (producer) Constant: INPUT_TOKEN_COUNT | 입력 토큰 수예요. | | int | | CamelLangChain4jAgentOutputTokenCount (producer) Constant: OUTPUT_TOKEN_COUNT | 출력 토큰 수예요. | | int | | CamelLangChain4jAgentTotalTokenCount (producer) Constant: TOTAL_TOKEN_COUNT | 전체 토큰 수예요. | | int | | CamelLangChain4jAgentRequestModel (producer) Constant: REQUEST_MODEL | 요청 모델 이름이에요. | | String | | CamelLangChain4jAgentResponseModel (producer) Constant: RESPONSE_MODEL | 응답 모델 이름이에요. langchain4j Result가 노출하지 않으면 agent producer가 설정하지 않아요. | | String | | CamelLangChain4jAgentSources (producer) Constant: SOURCES | 에이전트 호출 동안 검색된 RAG 소스예요. | | List | | CamelLangChain4jAgentToolExecutions (producer) Constant: TOOL_EXECUTIONS | 에이전트 호출 동안 수행된 툴 실행이에요. | | List | | CamelLangChain4jAgentModerationFlagged (producer) Constant: MODERATION_FLAGGED | 설정된 모더레이션 모델이 사용자 입력을 거절하면 true로 설정돼요. 성공하면 설정되지 않아요. | | Boolean |

OAuth 인증 (OAuth Authentication)

Quarkus 런타임

Quarkus에서 실행할 때는 MCP 서버 인증에 quarkus-langchain4j-oidc-mcp-auth-provider 확장을 사용해요. Quarkus OIDC와 네이티브하게 통합되고 자동 토큰 전파를 지원하며 Quarkus 보안 모범 사례를 따르기 때문에 권장되는 방식이에요.

<dependency>
    <groupId>io.quarkiverse.langchain4j</groupId>
    <artifactId>quarkus-langchain4j-oidc-mcp-auth-provider</artifactId>
</dependency>

이 확장을 쓰면 인증된 사용자의 OIDC 액세스 토큰이 MCP 서버로 자동 전파돼요. MCP 클라이언트는 quarkus.langchain4j.mcp.* 프로퍼티로 설정하고 미리 만들어진 빈으로 주입돼요. Camel은 mcpClients 파라미터로 이 빈들을 가져와요. oauthProfile이나 camel-oauth가 필요 없어요.

camel-main과 수동 MCP 서버 설정

Quarkus 밖(예: camel-main)에서 실행하거나 인라인 mcpServer.<name>.* 파라미터로 MCP 서버를 수동 설정할 때는 oauthProfile 옵션으로 OAuth 2.0 Client Credentials 그랜트 방식의 액세스 토큰을 발급받아요. 이 토큰은 HTTP 기반 MCP 트랜스포트에 Authorization: *** 헤더로 주입돼요. 클래스패스에 camel-oauth`가 필요해요.

camel.oauth.keycloak.client-id=camel-client
camel.oauth.keycloak.client-secret=camel-client-secret
camel.oauth.keycloak.token-endpoint=https://keycloak.example.com/realms/camel/protocol/openid-connect/token
  • Java

  • XML

  • YAML

from("direct:agent")
    .to("langchain4j-agent:myAgent?mcpServer.tools.transportType=http&mcpServer.tools.url=https://mcp.internal/mcp&mcpServer.tools.oauthProfile=keycloak");
<route>
  <from uri="direct:agent"/>
  <to uri="langchain4j-agent:myAgent?mcpServer.tools.transportType=http&amp;mcpServer.tools.url=https://mcp.internal/mcp&amp;mcpServer.tools.oauthProfile=keycloak"/>
</route>
- route:
    from:
      uri: direct:agent
      steps:
        - to:
            uri: langchain4j-agent:myAgent
            parameters:
              mcpServer.tools.transportType: http
              mcpServer.tools.url: "https://mcp.internal/mcp"
              mcpServer.tools.oauthProfile: keycloak

LLM 프로바이더 인증

langchain4j-agent 컴포넌트는 미리 만들어진 Agent나 ChatModel 빈을 받아요. LLM 클라이언트를 직접 만들지는 않아요. OAuth 인증이 필요한 LLM 프로바이더(예: Azure OpenAI)를 쓸 때는 빈을 프로그래밍 방식으로 만들면서 OAuthHelper를 사용하세요:

Java 전용: `OAuthHelper`로 프로그래밍 방식 ChatModel 빈 등록

String token = OAuthHelper.resolveOAuthToken(getContext(), "azure");

ChatModel chatModel = OpenAiChatModel.builder()
        .apiKey(token)
        .modelName("gpt-4")
        .build();

getContext().getRegistry().bind("myChatModel", chatModel);

from("direct:agent")
    .to("langchain4j-agent:myAgent");

참고 Quarkus나 Spring Boot에서는 빈을 프로그래밍 방식으로 등록하는 대신 프레임워크 고유의 프로퍼티와 의존성 주입으로 ChatModel을 설정해요.

사용 방법 (Usage)

프로바이더로 모델 설정하기

agent를 구동하는 챗 모델은 프로바이더와 각 프로바이더가 가진 옵션만으로 선언할 수 있어요. 프로바이더 모델 클래스의 빈이 없어도 돼요(Camel 4.23부터). application.properties에서 컴포넌트의 모든 엔드포인트에 적용하려면:

camel.component.langchain4j-agent.provider = ollama
camel.component.langchain4j-agent.model-name = qwen2.5
camel.component.langchain4j-agent.base-url = http://localhost:11434

엔드포인트에서는 model.이 모델 빌더의 프로바이더별 옵션 앞에 붙어요:

- route:
    from:
      uri: direct:start
      steps:
        - to:
            uri: langchain4j-agent:assistant
            parameters:
              provider: openai
              apiKey: "{{openai.api.key}}"
              modelName: gpt-4o-mini
              timeout: 30s
              tags: support

프로바이더는 ollama, openai, anthropic, azure-openai, mistral, gemini, vertex-ai, github, hugging-face, bedrock 중 하나예요. 목록에 없는 프로바이더는 customProvider로 설정해요. 이 값은 해당 LangChain4j 모델 클래스의 완전한 클래스 이름(builder()를 가진 클래스면 무엇이든, 예: dev.langchain4j.model.jlama.JlamaChatModel)이에요. 해당 프로바이더의 LangChain4j 모듈(dev.langchain4j:langchain4j-ollama, dev.langchain4j:langchain4j-open-ai, …​)이 클래스패스에 있어야 해요. 나열된 프로바이더는 Camel JBang이 내려받아 줘요. Ollama, LocalAI, vLLM, LM Studio처럼 OpenAI API를 말하는 서버들도 provider: openai에 baseUrl을 붙여 쓸 수 있어요. 이 경우 전용 모듈이 필요 없어요. 공통 옵션은 modelName, baseUrl, apiKey, temperature, timeout이고, 프로바이더 빌더가 쓰는 이름으로 설정해요(apiKey는 Hugging Face의 액세스 토큰, modelName은 Azure OpenAI의 배포 이름이에요). 프로바이더에 없는 옵션(Ollama에 apiKey)이나 빌더에 없는 model. 프로퍼티는 빌더가 받는 이름을 알려주는 에러가 돼요.

에이전트는 그 모델만 담은 AgentConfiguration을 쓰는 것과 같은 방식으로 만들어져요(메모리 없음). 같은 프로바이더 옵션을 쓰는 엔드포인트들은 모델 인스턴스 하나를 공유해요. 모델 빈(agent, agentFactory, agentConfiguration)이 설정되어 있으면 프로바이더는 무시돼요.

커스텀 에이전트 만들기

Camel 4.14부터 LangChain4j Agent 컴포넌트는 에이전트 기반 아키텍처를 사용해요. org.apache.camel.component.langchain4j.agent.api.Agent 인터페이스를 구현해서 에이전트를 만들어요. 컴포넌트는 내장 에이전트 구현체 두 개를 제공합니다:

  • AgentWithMemory - 대화 기록이 있는 챗 인터랙션용이에요

  • AgentWithoutMemory - 상태가 없는 챗 인터랙션용이에요

에이전트 설정 (Agent Configuration)

에이전트는 AgentConfiguration 클래스로 설정해요. 플루언트 API로 다음을 구성할 수 있어요:

  • Chat Model

  • Chat Memory Provider (메모리를 쓰는 에이전트용)

  • Retrieval Augmentor (RAG 기능용)

  • 입력·출력 가드레일

  • 콘텐츠 모더레이션 (withModerationModel)

  • 동시 툴 실행 (withExecuteToolsConcurrently): 한 번의 LLM 라운드 트립에서 Camel 라우트 툴과 MCP 툴을 병렬로 실행해요

  • 툴 호출 제어: 라운드 트립 한도, 환각(hallucinated) 툴 처리, 에러 보상

  • 고급 LangChain4j 옵션을 위한 AiServices 빌더 커스터마이저

툴 호출 옵션 (Tool-calling options)

AgentConfiguration은 LangChain4j AiServices의 가장 흔한 툴 호출 설정을 1급 플루언트 메서드로 노출해요. Camel이 설정 빈으로 에이전트를 만들 때(인라인 에이전트 모드 또는 등록된 AgentWithMemory / AgentWithoutMemory 빈) 자동으로 적용돼요:

Method Purpose
withMaxToolCallingRoundTrips(int) 요청당 LLM이 수행할 수 있는 툴 호출 라운드 트립 횟수를 제한해요 (0 = unset)
withHallucinatedToolNameStrategy(…​) 존재하지 않는 툴 이름 요청(예: 환각된 task_complete 툴)을 처리해요
withToolExecutionErrorHandler(…​) 툴 실행 예외를 LLM용 툴 결과 메시지로 변환해요
withToolArgumentsErrorHandler(…​) 유효하지 않거나 파싱할 수 없는 툴 인자를 처리해요
withCompensateOnToolErrors(Boolean) 툴 에러를 LLM에 다시 보내서 exchange를 실패시키는 대신 복구하게 해요
withExecuteToolsConcurrently() / withExecuteToolsConcurrently(Executor) 한 LLM 턴의 여러 툴 호출을 병렬로 실행해요

콘텐츠 모더레이션 (Content moderation)

AgentConfiguration.withModerationModel(ModerationModel)이 설정되면 Camel은 챗 모델을 호출하기 전에 사용자 메시지를 먼저 모더레이션해요. 문제가 있다고 판정된 입력은 툴이 실행되거나 메모리가 갱신되기 전에 ModerationException을 발생시켜요. producer는 실패 시 CamelLangChain4jAgentModerationFlagged 헤더를 true로 설정해서 라우트가 제어된 거절 응답을 돌려줄 수 있어요. 라우트 예제는 콘텐츠 모더레이션을 보세요. ModerationException을 처리할 때 판정된 텍스트는 ${exception.moderation}으로 확인할 수 있어요.

Java 전용: 모더레이션이 있는 공개 지원 챗봇

AgentConfiguration configuration = new AgentConfiguration()
    .withChatModel(chatModel)
    .withModerationModel(openAiModerationModel);

context.getRegistry().bind("supportAgentConfig", configuration);

onException(ModerationException.class)
    .handled(true)
    .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(422))
    .setBody(constant("Sorry, your message violates our usage policy."));

from("platform-http:/support/chat")
    .to("langchain4j-agent:support?agentConfiguration=#supportAgentConfig&tags=orders,billing");

Java 전용: 환각(hallucinated) 툴 이름에서 복구하기

AgentConfiguration configuration = new AgentConfiguration()
    .withChatModel(chatModel)
    .withMaxToolCallingRoundTrips(5)
    .withHallucinatedToolNameStrategy(request ->
        ToolExecutionResultMessage.from(request, "Unknown tool: " + request.name()));

일부 LangChain4j 빌더 옵션(beforeToolExecution, afterToolExecution, toolSearchStrategy 같은 것)은 개별 래퍼가 제공되지 않아요. 대신 커스터마이저 escape hatch를 사용하세요:

Java 전용: 남은 AiServices 빌더 옵션 설정

AgentConfiguration configuration = new AgentConfiguration()
    .withChatModel(chatModel)
    .withAiServicesCustomizer(builder -> builder
        .beforeToolExecution(ctx -> log.info("Calling tool {}", ctx.toolExecutionRequest().name()))
        .afterToolExecution(exec -> log.info("Tool finished: {}", exec.result())));

커스터마이저는 AbstractAgent.configureBuilder()에서 실행돼요. 표준 Camel 구성(툴 프로바이더, MCP, 가드레일, RAG, 위의 1급 툴 호출 옵션)이 모두 끝난 뒤, build() 호출 전이에요.

동시 툴 실행 (Concurrent tool execution)

LLM이 한 턴에서 여러 툴을 요청하면 LangChain4j는 AgentConfiguration.withExecuteToolsConcurrently()로 병렬 실행할 수 있어요. Camel 라우트 툴(tags로 발견된 ai-tool: consumer)은 각 호출을 격리된 exchange 복사본에서 실행해요. 그래서 동시 실행이 producer exchange를 망가뜨리지 않아요.

Java 전용: 관리되는 Camel executor로 병렬 툴 호출 켜기

AgentConfiguration configuration = new AgentConfiguration()
    .withChatModel(chatModel)
    .withExecuteToolsConcurrently();

// When created through langchain4j-agent (agentConfiguration on the endpoint),
// Camel registers a managed thread pool from ExecutorServiceManager automatically.
// Pass your own Executor with withExecuteToolsConcurrently(executor) to override.

툴이 동시에 실행될 때 툴 라우트의 헤더 부수 효과는 메인 exchange로 다시 병합되지 않아요. LLM에는 툴 결과 텍스트만 돌아가요.

인라인 에이전트 생성 모드(agent나 agentFactory 없이 agentConfiguration)에서는 같은 툴 호출 옵션을 엔드포인트 URI에 바로 설정할 수도 있어요. URI 값이 AgentConfiguration 빈의 같은 옵션을 덮어요:

- route:
    from:
      uri: direct:start
      steps:
        - to:
            uri: "langchain4j-agent:assistant"
            parameters:
              agentConfiguration: "#myConfig"
              tags: "orders"
              maxToolCallingRoundTrips: 5
              compensateOnToolErrors: true
              executeToolsConcurrently: true
from("direct:start")
    .to("langchain4j-agent:assistant?agentConfiguration=#myConfig&tags=orders"
        + "&maxToolCallingRoundTrips=5&compensateOnToolErrors=true&executeToolsConcurrently=true");

메모리 없는 에이전트 만들기 (Creating an Agent without Memory)

Java 전용: LangChain4j AgentConfiguration과 프로그래밍 방식 빈 등록

// Create and configure the chat model
ChatModel chatModel = OpenAiChatModel.builder()
    .apiKey(openApiKey)
    .modelName(GPT_3_5_TURBO)
    .temperature(0.3)
    .timeout(ofSeconds(3000))
    .build();

// Create agent configuration
AgentConfiguration configuration = new AgentConfiguration()
    .withChatModel(chatModel)
    .withInputGuardrailClasses(List.of())
    .withOutputGuardrailClasses(List.of());

// Create the agent
Agent simpleAgent = new AgentWithoutMemory(configuration);

// Register the agent in the Camel context
context.getRegistry().bind("simpleAgent", simpleAgent);

Camel 라우트에서 이 에이전트를 사용해요:

  • Java

  • XML

  • YAML

from("direct:chat")
    .to("langchain4j-agent:test?agent=#simpleAgent")
<route>
  <from uri="direct:chat"/>
  <to uri="langchain4j-agent:test?agent=#simpleAgent"/>
</route>
- route:
    from:
      uri: direct:chat
      steps:
        - to:
            uri: langchain4j-agent:test
            parameters:
              agent: "#simpleAgent"

메모리 있는 에이전트 만들기 (Creating an Agent with Memory)

Java 전용: LangChain4j ChatMemoryProvider와 AgentConfiguration 구성

// Create chat model (same as above)
ChatModel chatModel = OpenAiChatModel.builder()...

// Create memory provider
ChatMemoryProvider memoryProvider = memoryId -> MessageWindowChatMemory.builder()
    .id(memoryId)
    .maxMessages(10)
    .chatMemoryStore(persistentStore) // Your persistent store implementation
    .build();

// Create agent configuration with memory
AgentConfiguration configuration = new AgentConfiguration()
    .withChatModel(chatModel)
    .withChatMemoryProvider(memoryProvider)
    .withInputGuardrailClasses(List.of())
    .withOutputGuardrailClasses(List.of());

// Create the agent
Agent memoryAgent = new AgentWithMemory(configuration);

// Register the agent
context.getRegistry().bind("memoryAgent", memoryAgent);

참고 애플리케이션에서 Agent API 클래스를 사용하려면 camel-langchain4j-agent-api 의존성을 추가하세요:

<dependency>
    <groupId>org.apache.camel</groupId>
    <artifactId>camel-langchain4j-agent-api</artifactId>
    <version>x.x.x</version>
</dependency>

AgentConfiguration 직접 사용하기

AgentWithoutMemory나 AgentWithMemory를 직접 인스턴스화하는 대신 AgentConfiguration 빈을 등록하면 Camel이 알아서 맞는 에이전트 구현체를 만들어 줘요. ChatMemoryProvider가 있으면 AgentWithMemory를, 없으면 AgentWithoutMemory를 만들어요.

상태 없는 에이전트 (Stateless agent)

Java 전용: AgentConfiguration 빈 등록

AgentConfiguration config = new AgentConfiguration()
    .withChatModel(chatModel);

context.getRegistry().bind("myConfig", config);
  • Java

  • XML

  • YAML

from("direct:chat")
    .to("langchain4j-agent:assistant?agentConfiguration=#myConfig");
<route>
  <from uri="direct:chat"/>
  <to uri="langchain4j-agent:assistant?agentConfiguration=#myConfig"/>
</route>
- route:
    from:
      uri: direct:chat
      steps:
        - to:
            uri: langchain4j-agent:assistant
            parameters:
              agentConfiguration: "#myConfig"

상태 있는 에이전트 (with memory)

Java 전용: ChatMemoryProvider와 AgentConfiguration 빈 등록

ChatMemoryProvider memoryProvider = memoryId -> MessageWindowChatMemory.builder()
    .id(memoryId)
    .maxMessages(10)
    .chatMemoryStore(persistentStore)
    .build();

AgentConfiguration config = new AgentConfiguration()
    .withChatModel(chatModel)
    .withChatMemoryProvider(memoryProvider);

context.getRegistry().bind("myConfig", config);
  • Java

  • XML

  • YAML

from("direct:chat")
    .to("langchain4j-agent:assistant?agentConfiguration=#myConfig");
<route>
  <from uri="direct:chat"/>
  <to uri="langchain4j-agent:assistant?agentConfiguration=#myConfig"/>
</route>
- route:
    from:
      uri: direct:chat
      steps:
        - to:
            uri: langchain4j-agent:assistant
            parameters:
              agentConfiguration: "#myConfig"

엔드포인트에 agentFactory도 함께 설정되어 있으면 factory가 agentConfiguration보다 우선해요.

userMessage만 있는 기본 챗

단순 챗 인터랙션에는 메모리 없는 에이전트를 쓸 수 있어요.

  • Java

  • XML

  • YAML

from("direct:chat")
    .to("langchain4j-agent:simple?agent=#simpleAgent")
<route>
  <from uri="direct:chat"/>
  <to uri="langchain4j-agent:simple?agent=#simpleAgent"/>
</route>
- route:
    from:
      uri: direct:chat
      steps:
        - to:
            uri: langchain4j-agent:simple
            parameters:
              agent: "#simpleAgent"

body에는 프롬프트를 String으로 담거나, userMessage를 담은 org.apache.camel.component.langchain4j.agent.api.AiAgentBody 타입 객체를 만들어 담을 수 있어요.

Java 전용: ProducerTemplate 테스트 API

var prompt = "What is Apache Camel";

String response = template.requestBody("direct:chat", prompt, String.class);

Java 전용: `AiAgentBody`를 쓰는 ProducerTemplate 테스트 API

var prompt = "What is Apache Camel";
AiAgentBody body = new AiAgentBody(prompt);

String response = template.requestBody("direct:chat", body, String.class);

user와 system 메시지가 있는 기본 챗

시스템 프롬프트가 있는 챗 인터랙션에도 메모리 없는 에이전트를 쓸 수 있어요.

  • Java

  • XML

  • YAML

from("direct:chat")
    .to("langchain4j-agent:simple?agent=#simpleAgent")
<route>
  <from uri="direct:chat"/>
  <to uri="langchain4j-agent:simple?agent=#simpleAgent"/>
</route>
- route:
    from:
      uri: direct:chat
      steps:
        - to:
            uri: langchain4j-agent:simple
            parameters:
              agent: "#simpleAgent"

body에 사용자 프롬프트를 String으로 담고 시스템 프롬프트용 CamelLangChain4jAgentSystemMessage 헤더를 지정하거나, userMessage와 systemMessage를 모두 담은 org.apache.camel.component.langchain4j.agent.api.AiAgentBody 타입 객체를 만들 수 있어요.

Java 전용: ProducerTemplate 테스트 API

var userPrompt = "Write a short story about a lost cat.";
var systemPrompt = "You are a whimsical storyteller. Your responses should be imaginative, descriptive, and always include a touch of magic. Start every story with 'Once upon a starlit night...";

String response = template.requestBodyAndHeader("direct:chat",
                userPrompt, "CamelLangChain4jAgentSystemMessage", systemPrompt , String.class);

Java 전용: `AiAgentBody`를 쓰는 ProducerTemplate 테스트 API

var userPrompt = "Write a short story about a lost cat.";
var systemPrompt = "You are a whimsical storyteller. Your responses should be imaginative, descriptive, and always include a touch of magic. Start every story with 'Once upon a starlit night...";

AiAgentBody body = new AiAgentBody()
                .withUserMessage(userPrompt)
                .withSystemMessage(systemPrompt);

String response = template.requestBody("direct:chat", body, String.class);

툴과 챗하기 (Chat with Tools)

Camel 라우트를 툴로 통합해요. LangChain4j Agent 컴포넌트는 tags 파라미터를 통해 ai-tool 컴포넌트로 정의된 Camel Routes와 통합돼요.

  • Java

  • XML

  • YAML

// Define tool routes
from("ai-tool:userDb?tags=users&description=Query user database&parameter.userId=string")
    .setBody(constant("{\"name\": \"John Doe\", \"id\": \"123\"}"));

from("ai-tool:weather?tags=weather&description=Get weather information&parameter.city=string")
    .setBody(constant("{\"weather\": \"sunny\", \"temperature\": \"22°C\"}"));

// Agent with tools (using the created agent)
from("direct:chat")
    .to("langchain4j-agent:tools?agent=#simpleAgent&tags=users,weather");
<!-- Define tool routes -->
<route>
  <from uri="ai-tool:userDb?tags=users&amp;description=Query user database&amp;parameter.userId=string"/>
  <setBody>
    <constant>{"name": "John Doe", "id": "123"}</constant>
  </setBody>
</route>

<route>
  <from uri="ai-tool:weather?tags=weather&amp;description=Get weather information&amp;parameter.city=string"/>
  <setBody>
    <constant>{"weather": "sunny", "temperature": "22°C"}</constant>
  </setBody>
</route>

<!-- Agent with tools -->
<route>
  <from uri="direct:chat"/>
  <to uri="langchain4j-agent:tools?agent=#simpleAgent&amp;tags=users,weather"/>
</route>
# Define tool routes
- route:
    from:
      uri: ai-tool:userDb
      parameters:
        tags: users
        description: Query user database
        parameter.userId: string
      steps:
        - setBody:
            expression:
              constant:
                expression: '{"name": "John Doe", "id": "123"}'

- route:
    from:
      uri: ai-tool:weather
      parameters:
        tags: weather
        description: Get weather information
        parameter.city: string
      steps:
        - setBody:
            expression:
              constant:
                expression: '{"weather": "sunny", "temperature": "22°C"}'

# Agent with tools
- route:
    from:
      uri: direct:chat
      steps:
        - to:
            uri: langchain4j-agent:tools
            parameters:
              agent: "#simpleAgent"
              tags: users,weather

Java 전용: ProducerTemplate 테스트 API

var userPrompt = "Can you tell me the name of user 123 and the weather in New York?";
var systemPrompt = "You are a helpful assistant that can access user database and weather information. Use the available tools to provide accurate information.";

String response = template.requestBodyAndHeader("direct:chat",
                userPrompt, "CamelLangChain4jAgentSystemMessage", systemPrompt , String.class);

참고 LangChain4j Agent 컴포넌트에서 Camel 라우트 툴을 사용하려면 camel-ai-tool 의존성을 추가하세요:

<dependency>
    <groupId>org.apache.camel</groupId>
    <artifactId>camel-ai-tool</artifactId>
</dependency>

커스텀 LangChain4j 툴 (Custom LangChain4j Tools)

@Tool 애노테이션으로 커스텀 LangChain4j 툴을 추가할 수도 있어요. 이 툴들은 customTools 설정 파라미터로 에이전트에 바로 전달돼요.

커스텀 LangChain4j 툴 만들기 (Creating Custom LangChain4j Tools)

@Tool이 붙은 메서드를 가진 클래스를 만들어요:

Java 전용: LangChain4j @Tool 애노테이션 클래스

import dev.langchain4j.agent.tool.P;
import dev.langchain4j.agent.tool.Tool;

public class CalculatorTool {

    @Tool("Adds two numbers")
    public int add(@P("First number") int a, @P("Second number") int b) {
        return a + b;
    }

    @Tool("Multiplies two numbers")
    public int multiply(@P("First number") int a, @P("Second number") int b) {
        return a * b;
    }

    @Tool("Gets the square root of a number")
    public double sqrt(@P("Number") double x) {
        return Math.sqrt(x);
    }
}

커스텀 LangChain4j 툴을 에이전트에서 사용하기

커스텀 툴 인스턴스를 에이전트 설정에 전달해요:

Java 전용: LangChain4j @Tool 인스턴스와 AgentConfiguration 구성

// Create tool instances
CalculatorTool calculator = new CalculatorTool();
WeatherTool weather = new WeatherTool();

// Create agent configuration with custom tools
AgentConfiguration config = new AgentConfiguration()
    .withChatModel(chatModel)
    .withCustomTools(Arrays.asList(calculator, weather));

// Create agent
Agent agent = new AgentWithoutMemory(config);

// Register agent in Camel context
context.getRegistry().bind("customToolsAgent", agent);

라우트 설정 (Route Configuration)

커스텀 툴을 붙인 에이전트를 라우트에서 사용해요:

  • Java

  • XML

  • YAML

from("direct:chat")
    .to("langchain4j-agent:assistant?agent=#customToolsAgent")
    .to("mock:agent-response");
<route>
  <from uri="direct:chat"/>
  <to uri="langchain4j-agent:assistant?agent=#customToolsAgent"/>
  <to uri="mock:agent-response"/>
</route>
- route:
    from:
      uri: direct:chat
      steps:
        - to:
            uri: langchain4j-agent:assistant
            parameters:
              agent: "#customToolsAgent"
        - to:
            uri: mock:agent-response

사용 예제 (Usage Example)

Java 전용: ProducerTemplate 테스트 API

String response = template.requestBody("direct:chat",
    "Calculate 10 * 5 and tell me the weather in Paris", String.class);

참고 커스텀 LangChain4j 툴은 LangChain4j 프레임워크가 직접 실행해요. 툴 실행에 추가 설정이나 툴 Executor가 필요 없어요.

혼합 툴 (Mixed Tools) — Camel Routes + 커스텀 LangChain4j 툴

같은 에이전트에 Camel 라우트 툴(tags 사용)과 커스텀 LangChain4j 툴(customTools 사용)을 함께 섞을 수 있어요:

Java 전용: LangChain4j @Tool 인스턴스, AgentConfiguration, 빈 등록

// Define Camel route tools
from("ai-tool:weatherService?tags=weather&description=Get current weather information&parameter.location=string")
    .setBody(constant("{\"weather\": \"sunny\", \"location\": \"Current Location\"}"));

// Create custom tool instances
CalculatorTool calculator = new CalculatorTool();
StringTool stringTool = new StringTool();

// Create agent configuration with both types of tools
AgentConfiguration config = new AgentConfiguration()
    .withChatModel(chatModel)
    .withCustomTools(Arrays.asList(calculator, stringTool));

// Create agent
Agent agent = new AgentWithMemory(config);

// Register agent in Camel context
context.getRegistry().bind("mixedToolsAgent", agent);

혼합 툴의 라우트 설정 (Route Configuration with Mixed Tools)

  • Java

  • XML

  • YAML

from("direct:chat")
    .to("langchain4j-agent:assistant?agent=#mixedToolsAgent&tags=weather")
    .to("mock:agent-response");
<route>
  <from uri="direct:chat"/>
  <to uri="langchain4j-agent:assistant?agent=#mixedToolsAgent&amp;tags=weather"/>
  <to uri="mock:agent-response"/>
</route>
- route:
    from:
      uri: direct:chat
      steps:
        - to:
            uri: langchain4j-agent:assistant
            parameters:
              agent: "#mixedToolsAgent"
              tags: weather
        - to:
            uri: mock:agent-response

사용 예제 (Usage Example)

Java 전용: ProducerTemplate 테스트 API

String response = template.requestBody("direct:chat",
    "Calculate 10 * 5 and tell me the weather in London", String.class);

참고 혼합 툴을 쓸 때 Camel 라우트 툴은 tags 파라미터로 동적으로 발견되고, 커스텀 LangChain4j 툴은 customTools 설정으로 정적으로 제공돼요.

RAG 통합 (RAG Integration)

RAG(Retrieval-Augmented Generation)는 AgentConfiguration에 RetrievalAugmentor를 설정해서 지원해요. RAG 기능이 있는 에이전트를 만들어요:

Java 전용: LangChain4j RetrievalAugmentor와 AgentConfiguration 구성

// Create the retrieval augmentor (shown below)
RetrievalAugmentor retrievalAugmentor = createRetrievalAugmentor();

// Create agent configuration with RAG
AgentConfiguration configuration = new AgentConfiguration()
    .withChatModel(chatModel)
    .withRetrievalAugmentor(retrievalAugmentor)
    .withInputGuardrailClasses(List.of())
    .withOutputGuardrailClasses(List.of());

Agent ragAgent = new AgentWithoutMemory(configuration);
context.getRegistry().bind("ragAgent", ragAgent);

RAG 에이전트를 사용해요:

  • Java

  • XML

  • YAML

from("direct:chat")
    .to("langchain4j-agent:rag?agent=#ragAgent")
<route>
  <from uri="direct:chat"/>
  <to uri="langchain4j-agent:rag?agent=#ragAgent"/>
</route>
- route:
    from:
      uri: direct:chat
      steps:
        - to:
            uri: langchain4j-agent:rag
            parameters:
              agent: "#ragAgent"

Java 전용: LangChain4j EmbeddingStoreContentRetriever와 ProducerTemplate 테스트 API

// creating the retrieval Augmentor
EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
                .embeddingStore(embeddingStore) // the embedding store should be defined
                .embeddingModel(embeddingModel) // the embedding model should be defined
                .maxResults(3)
                .minScore(0.6)
                .build();

RetrievalAugmentor retrievalAugmentor = DefaultRetrievalAugmentor.builder()
                .contentRetriever(contentRetriever)
                // other options or steps can be included for Advanced RAG
                .build();

// bind the retrievalAugmentor in the context
context.getRegistry().bind("retrievalAugmentor", retrievalAugmentor);

// using the producer
String response = template.requestBody("direct:chat", body, String.class);

메모리와 챗하기 (Chat with Memory)

메모리 기능은 AgentWithMemory를 사용하고 AgentConfiguration에 ChatMemoryProvider를 설정해서 지원해요. 메모리는 여러 사용자/세션에서 동작해요.

참고 이 컴포넌트는 영속 메모리 스토어를 사용하는 Chat Memory Provider를 써야 해요.

메모리는 여러 사용자/세션에서 동작해요. 각 컨텍스트 윈도우마다 사용자가 메모리 ID를 설정해야 해요: - Header에 CamelLangChain4jAgentMemoryId를 설정하는 방법. body를 String으로 쓰는 경우예요. - AiAgentBody.memoryId 필드를 설정하는 방법. body를 AiAgentBody로 쓰는 경우예요.

메모리 에이전트가 있는 라우트 예제

  • Java

  • XML

  • YAML

from("direct:chat")
    .to("langchain4j-agent:memory?agent=#memoryAgent")
<route>
  <from uri="direct:chat"/>
  <to uri="langchain4j-agent:memory?agent=#memoryAgent"/>
</route>
- route:
    from:
      uri: direct:chat
      steps:
        - to:
            uri: langchain4j-agent:memory
            parameters:
              agent: "#memoryAgent"

Java 전용: ChatMemoryProvider, AiAgentBody, ProducerTemplate 테스트 API

// Example of creating a Chat Memory Provider : Create a message window memory that keeps the last 10 messages
        ChatMemoryProvider chatMemoryProvider = memoryId -> MessageWindowChatMemory.builder()
                .id(memoryId)
                .maxMessages(10)
                .chatMemoryStore(store) // the Chat Memory store is previously created
                .build();

// bind the chat memory provider in the context
context.getRegistry().bind("chatMemoryProvider", chatMemoryProvider);


AiAgentBody request = new AiAgentBody("Hello!", null, "session-123");
String response = template.requestBody("direct:chat", request, String.class);

JSON Schema로 구조화된 출력 (Structured Outputs with JSON Schema)

LangChain4j Agent 컴포넌트는 LLM 응답에 JSON 스키마를 강제하는 방식으로 구조화된 출력을 지원해요. 이 기능은 구조화된 출력을 지원하는 프로바이더(Amazon Bedrock, Azure OpenAI, Google AI Gemini, Mistral, Ollama, OpenAI 포함)에서 사용할 수 있어요.

jsonSchema 엔드포인트 옵션 사용하기

구조화된 출력을 켜는 가장 간단한 방법은 jsonSchema 엔드포인트 옵션이에요. agentConfiguration(인라인 에이전트 생성 모드)을 쓸 때 동작해요. 이 옵션은 클래스패스 참조, 파일 경로, 인라인 JSON을 지원하고, camel-openai 컴포넌트와 같은 방식이에요.

클래스패스 리소스 예제

JSON 스키마 파일을 만들어요. 예: src/main/resources/person-schema.json:

{
    "type": "object",
    "properties": {
        "name": {"type": "string", "description": "The person's full name"},
        "age": {"type": "integer", "description": "The person's age in years"},
        "occupation": {"type": "string", "description": "The person's job"}
    },
    "required": ["name", "age", "occupation"],
    "additionalProperties": false
}

라우트에서 사용해요:

Java 전용: AgentConfiguration 빈 등록

AgentConfiguration agentConfiguration = new AgentConfiguration()
        .withChatModel(chatModel);

context.getRegistry().bind("myAgentConfig", agentConfiguration);
  • Java

  • XML

  • YAML

from("direct:extract-person-info")
    .setBody(constant("Extract information about John Smith, a 35-year-old software engineer"))
    .to("langchain4j-agent:structured?agentConfiguration=#myAgentConfig&jsonSchema=classpath:person-schema.json")
    .unmarshal().json()
    .log("Extracted person: ${body}");
<route>
  <from uri="direct:extract-person-info"/>
  <setBody>
    <constant>Extract information about John Smith, a 35-year-old software engineer</constant>
  </setBody>
  <to uri="langchain4j-agent:structured?agentConfiguration=#myAgentConfig&amp;jsonSchema=classpath:person-schema.json"/>
  <unmarshal>
    <json/>
  </unmarshal>
  <log message="Extracted person: ${body}"/>
</route>
- route:
    from:
      uri: direct:extract-person-info
      steps:
        - setBody:
            expression:
              constant:
                expression: "Extract information about John Smith, a 35-year-old software engineer"
        - to:
            uri: langchain4j-agent:structured
            parameters:
              agentConfiguration: "#myAgentConfig"
              jsonSchema: "classpath:person-schema.json"
        - unmarshal:
            json: {}
        - log:
            message: "Extracted person: ${body}"

jsonSchema 옵션이 받는 값은 다음과 같아요:

  • 클래스패스 리소스: jsonSchema=classpath:schemas/person.json

  • 파일 경로: jsonSchema=file:///path/to/schema.json

  • 인라인 JSON: jsonSchema={"type":"object","properties":{"name":{"type":"string"}}}

  • 프로퍼티 플레이스홀더: jsonSchema=resource:classpath:${schema.location}

outputClass 엔드포인트 옵션 사용하기 (Java 클래스 기반 스키마)

JSON 스키마를 직접 주는 대신 outputClass 엔드포인트 옵션으로 Java 클래스를 지정할 수도 있어요. Camel LangChain4j agent가 자동으로 이런 일을 해 줘요:

  1. 클래스 구조에서 JSON 스키마를 도출해요

  2. 그 스키마에 맞는 JSON을 돌려주도록 AI 모델을 설정해요

응답 body는 raw JSON 문자열 그대로 유지돼요. camel-openai 컴포넌트와 같은 방식이에요. 라우트에서 Camel의 .unmarshal().json()으로 POJO로 바꾸세요.

이 방식은 jsonSchema와 상호 배타적이에요. 둘 중 하나만 쓸 수 있어요.

Java POJO 예제

먼저 응답 클래스를 정의해요. 필수 필드에는 @JsonProperty(required = true)를 붙이세요. 생성된 JSON 스키마의 required 배열에 들어가서 모델이 항상 채우도록 보장해 줘요. 의미 힌트는 @Description으로 추가해요:

Java 전용: @JsonProperty와 @Description 애노테이션을 붙인 Java POJO

import com.fasterxml.jackson.annotation.JsonProperty;
import dev.langchain4j.model.output.structured.Description;

public class PersonInfo {
    @JsonProperty(required = true)
    @Description("The person's full name")
    private String name;

    @JsonProperty(required = true)
    @Description("The person's age in years")
    private int age;

    @JsonProperty(required = true)
    @Description("The person's job or profession")
    private String occupation;

    // Getters and setters...
}

엔드포인트가 이 클래스를 쓰도록 설정해요. 완전한 클래스 이름(FQCN)을 바로 쓰면 돼요. 레지스트리 바인딩이 필요 없어요. raw JSON 응답을 POJO로 바꾸려면 .unmarshal().json()을 추가하세요:

Java 전용: AgentConfiguration 빈 구성, POJO 클래스 unmarshal, process 람다

AgentConfiguration agentConfiguration = new AgentConfiguration()
        .withChatModel(chatModel);

context.getRegistry().bind("myAgentConfig", agentConfiguration);

from("direct:extract-person-info")
    .setBody(constant("Extract information about John Smith, a 35-year-old software engineer"))
    .to("langchain4j-agent:structured?agentConfiguration=#myAgentConfig&outputClass=com.example.PersonInfo")
    .unmarshal().json(PersonInfo.class)
    .process(exchange -> {
        PersonInfo person = exchange.getIn().getBody(PersonInfo.class);
        log.info("Name: {}, Age: {}, Occupation: {}",
            person.getName(), person.getAge(), person.getOccupation());
    });

참고

  • jsonSchema와 outputClass는 agentConfiguration(인라인 에이전트 생성 모드)을 쓸 때만 동작해요. agent나 agentFactory가 설정되어 있으면 안 돼요

  • 두 옵션을 동시에 쓸 수는 없어요. 상호 배타적이에요

  • AI 모델이 구조화된 출력을 지원해야 해요 (예: OpenAI GPT-4o, GPT-4o-mini, JSON 모드의 Ollama 모델)

  • 복잡한 중첩 객체와 컬렉션은 outputClass에서 완전히 지원돼요

대안: ChatModel에 ResponseFormat 설정

ChatModel 레벨에서 ResponseFormat을 정의할 수도 있어요. 자세한 내용은 LangChain4j Structured Outputs 문서를 보세요.

참고

  • LLM 응답이 제공된 스키마를 따른다는 게 보장돼요

  • 출력 포매팅을 위한 프롬프트 엔지니어링이 필요 없어요

  • 같은 스키마 파일을 camel-openai와 camel-langchain4j-agent 컴포넌트가 공유할 수 있어요

구조화된 에러 exchange 프로퍼티

LangChain4j agent 호출이 실패하면 Camel은 모델 예외가 전파되기 전에 exchange에 구조화된 메타데이터를 설정해요. GenAI observability가 꺼져 있어도 동작해요.

Exchange property Meaning
CamelAiErrorCategory LangChain4j 예외에서 도출한 대분류예요: RATE_LIMIT, SERVER_ERROR, VALIDATION, AUTH, UNKNOWN
CamelAiRetryAfterMillis LangChain4j 프로바이더는 채워지지 않아요(현재는 OpenAI 전용)

카테고리 기반 처리는 LangChain4j Chat 에러 처리의 LangChain4j 예외 타입 매칭과 보완 관계예요:

onException(Exception.class)
    .process(exchange -> {
        String category = exchange.getProperty("CamelAiErrorCategory", String.class);
        if ("RATE_LIMIT".equals(category)) {
            exchange.getIn().setHeader("RateLimited", true);
        }
    })
    .maximumRedeliveries(3)
    .handled(true)
    .to("direct:rate-limited");

컴포넌트 전반의 개요는 AI LLM 통합 가이드를 보세요.

하위 페이지 (Sub-Pages)

특정 기능의 자세한 내용은 다음을 보세요:

더 알아보기 (Learn more)

툴 호출·모더레이션·가드레일의 동작 세부와 라우트 예제는 콘텐츠 모더레이션과 LangChain4j Chat 에러 처리 섹션에서 이어서 볼 수 있어요. 가드레일·MCP·멀티모달은 각각의 하위 페이지(guardrails, MCP, multimodal)에 정리되어 있고, 구조화된 에러 프로퍼티의 전체 개요는 AI LLM 통합 가이드에 있어요.