embabel은 코틀린으로 개발되었지만, 자바/코틀린에서 모두 사용할 수 있다!
Embabel은 다양한 방식으로 활용할 수 있으며, 개발 환경과 사용 목적에 맞춰 유연하게 동작한다.
maven은 내가 사용하지 않을 것 같아서 생략한다.
repositories {
mavenCentral()
maven {
name = "embabel-releases"
url = uri("https://repo.embabel.com/artifactory/libs-release")
mavenContent { releasesOnly() }
}
maven {
name = "embabel-snapshots"
url = uri("https://repo.embabel.com/artifactory/libs-snapshot")
mavenContent { snapshotsOnly() }
}
maven {
name = "Spring Milestones"
url = uri("https://repo.spring.io/milestone")
}
}
dependencies {
implementation("com.embabel.agent:embabel-agent-starter-shell:${embabel-agent.version}")
}
필수:
OPENAI_API_KEY: OpenAI 모델 접근선택사항:
ANTHROPIC_API_KEY: Anthropic 모델 접근Anthropic 모델이 더 높은 성능을 보여주지만, Cost 때문에 OPENAI API를 기본으로 사용하고 Anthropic 모델의 경우 선택적으로 사용할 수 있게 하는 걸로 보인다.
git clone https://github.com/embabel/embabel-agent-examples
cd embabel-agent-examples/scripts/java
./shell.sh
사용 가능한 명령은 help를 입력한다.
에이전트 실행
execute "린다는 전갈자리이고 뉴스를 찾아줘" -p -r
-p: 프롬프트 로깅-r: LLM 응답 로깅대화형 채팅 시작
chat
Spring Shell은 명령어 히스토리를 지원한다.
!!를 입력하면 마지막으로 실행한 명령을 다시 실행할 수 있다.
이 히스토리는 재시작 후에도 유지되기 때문에, 에이전트를 반복적으로 테스트하거나 실험할 때 매우 유용하다.
https://github.com/embabel/embabel-agent-examples 에서 제공하는 예제를 실행하는 예시이다.
# 간단한 운세 에이전트
execute "내 이름은 Sarah이고 레오입니다"
# 웹 도구를 사용한 연구
execute "research the recent australian federal election"
# 팩트 체킹
x "fact check: holden cars are still made in australia"
개발 중에는 에이전트나 특정 플로우를 빠르게 시험해보고 싶을 때가 많다.
이럴 때 직접 Spring Shell 명령을 구현해 사용하면 매우 편리하다. Spring Shell 컴포넌트를 하나 작성하기만 하면, Spring이 자동으로 빈을 생성하고 명령을 등록해 줍니다.
@ShellComponent
public record SupportAgentShellCommands(AgentPlatform agentPlatform) {
@ShellMethod("고객 쿼리에 대한 은행 지원 받기")
public String bankSupport(
@ShellOption(value = "id", defaultValue = "123") Long id,
@ShellOption(value = "query", defaultValue = "잔액이 얼마예요?") String query) {
var supportInput = new SupportInput(id, query);
var invocation = AgentInvocation
.builder(agentPlatform)
.options(ProcessOptions.builder()
.verbosity(v -> v.showPrompts(true)).build())
.build(SupportOutput.class);
return invocation.invoke(supportInput).toString();
}
}
AgentPlatform을 주입받아 에이전트를 직접 실행할 수 있다. 간략하게 코드를 분석해보면 다음과 같다.
@ShellComponent
AgentPlatform 주입
@ShellMethod
AgentInvocation - agent 호출 준비
invoke - 에이전트 실행
결과 반환
Embabel을 이용해 기존 애플리케이션에 간단하게 AI 기능을 추가하는 방법부터 알아보자.
Embabel을 가장 단순하게 사용하는 방법은 OperationContext(또는 Ai 객체)를 Spring에서 주입받아 직접 AI 기능을 호출하는 것이다.
예시: 거짓말 생성기
@Component
public record InjectedComponent(Ai ai) {
public record Joke(String leadup, String punchline) {
}
public String tellJokeAbout(String topic) {
return ai
.withDefaultLlm()
.generateText("Tell me a joke about " + topic);
}
public Joke createJokeObjectAbout(String topic1, String topic2, String voice) {
return ai
.withLlm(LlmOptions.withDefaultLlm().withTemperature(.8))
.createObject("""
Tell me a joke about %s and %s.
The voice of the joke should be %s.
The joke should have a leadup and a punchline.
""".formatted(topic1, topic2, voice),
Joke.class);
}
}
이 예제에서 우리는 embabel의 설계 철학을 볼 수 있다.
1) 표준 Spring 통합
2) 단순한 API
ai.generateText(), ai.createObject()처럼 직관적인 메서드 호출만으로 LLM 기능 사용 가능하다. 또는 OperationContext.ai()로 동일한 인터페이스에 접근할 수도 있다.3) 유연한 구성
.withLlm(LlmOptions.withDefaultLlm().withTemperature(.8))4) 타입 안전성
createObject(prompt, Joke.class)5) 일관된 프로그래밍 경험
공식문서에선 아래와 같이 설명하고 있다.
Ai 타입은 Embabel의 모든 AI 기능에 접근할 수 있는 간단하고 강력한 게이트웨이다. Agent를 만들지 않아도 기존 애플리케이션에 AI 기능을 점진적으로 추가할 수 있으며, 이는 Embabel을 기존 Spring/JVM 애플리케이션과 통합하는 매우 자연스러운 방식이다.
이제 Agent를 만들어보자. 가장 쉬운 방법은 template을 가져다 사용하는 거다.
@Agent(description = "이야기를 쓰고 검토하는 에이전트")
public class WriteAndReviewAgent {
@Action
public Story writeStory(UserInput userInput, OperationContext context) {
return context.ai().withAutoLlm()
.createObject("다음에 대해 이야기를 작성해줘: %s".formatted(userInput.getContent()),
Story.class);
}
@AchievesGoal(description = "이야기 검토")
@Action
public ReviewedStory reviewStory(Story story, OperationContext context) {
return context.ai().withLlmByRole("reviewer")
.createObject("다음 이야기를 검토해줘: %s".formatted(story.text),
ReviewedStory.class);
}
}
여러 LLM과 서로 다른 설정 사용
액션과 목표(Goals)
@Action 메서드는 에이전트가 실행할 수 있는 개별 단계(step)를 의미 @AchievesGoal은 에이전트의 목표를 완성하는 최종 액션임을 나타냄 도메인 객체(Domain Objects)
Story와 ReviewedStory는 강하게 타입이 정의된 도메인 모델 export OPENAI_API_KEY="your_key_here"
./scripts/shell.sh
실행에 성공했다면, x "Tell me a story about a robot learning to paint"와 같이 에이전트에게 요청해보자.