필요한 사전학습
- 기본적인 개발 지식: 비전공자를 위한 이해할 수 있는 IT 지식 책 추천 (교보문고 바로가기)
- API 에 대한 기본적인 이해
- Postman 을 통해 API 호출 하는 방법 (브레이즈 포스트맨 콜랙션 바로가기)
- 브레이즈 커넥티드 컨텐츠에 대한 이해 (브레이즈 공식 도큐먼트 바로가기)
- Open AI API Chat completions 의 endpoint 에 대한 이해 (공식 도큐먼트 바로가기)
방법
Open AI API Chat completions 도큐먼트로 가서 curl 로 library 를 바꾸면 아래와 같은 API call 방법이 나온다
curl https://api.openai.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d '{
"model": "gpt-4o-mini",
"messages": [
{
"role": "system",
"content": "You are a helpful assistant."
},
{
"role": "user",
"content": "Who won the world series in 2020?"
},
{
"role": "assistant",
"content": "The Los Angeles Dodgers won the World Series in 2020."
},
{
"role": "user",
"content": "Where was it played?"
}
]
}'
이 명령어를 Braze Connected Contents 에서 호출하기 위해서 아래와 같은 형태로 변경해야한다
{% connected_content
https://your_API_endpoint_here/
:headers {
"Content-Type": "YOUR-CONTENT-TYPE",
"Authorization": "{{token_response}}"
}
:body key1=value1&key2=value2
:save response
%}
Open AI API 는 중첩된 객체 (Nested Objects) 로 돼 있는데, 브레이즈 커넥티드 컨텐츠 문서에는 key <> value pair 예시 밖에 없다.
브레이즈 커넥티드 컨텐츠 두 번째 문서인 Local Connected Content variables 에 Body in an assign statement: spaces allowed 라는 예제가 있고, 아래와 같이 include 라는 객체에 attributes 라는 또 다른 객체가 중첩되어 있다. 그 안에 withkey 라는 배열이 포함 돼 있다
{% capture postbody %}
{
"ids":[ca_57832,ca_75869],"include":{"attributes":{"withKey":["daily_deals"]}}
}
{% endcapture %}
{% connected_content
https://example.com/api/endpoint
:method post
:headers {
"Content-Type": "application/json"
}
:body {{postbody}}
:save result
%}
아래와 같이 capture postbody 에 body 를 assign 하고 connected contents 의 body 에서 {{postbody}} 로 호출한다. response 를 호출하고 response 의 message.content 만 불러올 수 있도록 JSON 을 Parsing 한다
{% capture postbody %}
{
"model": "gpt-4o",
"messages": [
{
"role": "system",
"content": "You are a helpful assistant."
},
{
"role": "user",
"content": "daddy joke please."
}
]
}
{% endcapture %}
{% connected_content
https://api.openai.com/v1/chat/completions
:method post
:headers {
"Content-Type": "application/json",
"Authorization": "Bearer $OPENAI_API_KEY"
}
:body {{postbody}}
:save response
%}
{% assign parsed_response = response | parse_json %}
{% assign message_content = parsed_response.choices[0].message.content %}
{{ message_content }}
내가 문제를 푼 방식
- 구글링을 한다. 이 케이스엔 도움되지 않았다
- 나의 모든 Social capital 을 동원한다. 브레이즈 리셀러 CSM, 브레이즈 본사 CSM 친구 등에게 Open AI API 방법에 대해 물어본 결과 Webhook 으로 받은 response 는 save 할 수 없다는 사실을 알아차리고 Webhook 방법은 포기하고 Connected Contents 로 보기로 했다. Social capital 에게 질문하기가 1번인 이유는, 그들이 칼답을 하지 않기 때문에 그들의 응답을 기다리는 시간을 최소화하기 위해 최대한 빠르게 질문한다. 질문을 논리적으로 설명하기 위해서 정리를 하다보면 문제에 대한 실마리를 스스로 얻기도 한다
- 공식 문서를 뒤진다. Connected Contents 로 방향을 잡았으니 커넥티드 컨텐츠 문서를 스캐닝하면서 실마리를 잡는다
- Tools: LLM (GPT or Claude 3.5 Sonnet) 과 대화 해 본다. 브레이즈가 커넥티드 컨텐츠로 호출 시 response Error 를 출력할 수 있도록 구조를 만들어서 점차 문제 해결에 다가갈 수 있었다. 리퀴드 랭귀지 pase_json 과 message_content 를 assign 하는 법도 GPT 가 짜 주었다
- 시도해 본 내용과 response 를 구글시트에 적어보면서 다음 시도(실험) 을 디자인한다
글을 마치며
결국 ex-브레이즈 본사 CSM 이였던 친구의 LinkedIn 쪽지로 받은 해결책 두 개 중 하나였던 capture postbody 로 문제를 풀었다. 다른 해결책은 내가 이미 익숙했던 방법이라 빠르게 실험 해 보고 안 된다고 징징댔는데, capture postbody 는 써 본적이 없었기 때문에 실험을 계속 미루다가, 마지막 실험에서 이를 써 보고 바로 작동했다.
AC2 의 퍼포먼스 공식, Essence of Agile, 야생학습 휴리스틱 등을 사용하여 ‘학습 과정 중 새로운 정보가 들어오면 그에 맞게 목표를 지속적으로 조정’ 하고 내가 가진 자원 (bird in hand) 을 적극적으로 활용했다. 에러 핸들링을 위해 response 를 저장하고 이를 피드백 루프에 사용하기 (이 케이스에서 도움은 별로 안 됐음) 도 하였다.
내가 풀려는 문제는 무엇인지 빠르게 정의하고 내가 가진 리소스를 최대한 사용하고 Reflection-in-action 으로 피드백을 초단기로 받으면 문제는 조금 더 수월하게 풀리는 것 같다. 방법은 나의 hard skill 이고, 내가 문제를 푼 방식이 암묵지이며, 글을 마치며가 내 task 에 대한 나의 회고다.