Langchain OpenAI Agent 살펴보기
langchain의 create_openai_functions_agent 함수로 생성된 agent를 실행할 때, prompt에서 강제로 지정하는 parameters가 있다.
각각의 parameter가 어떤 의미를 가지는지, 어떻게 실행이 되는지 살펴보자.
prompt (ChatPromptTemplate)
[system message] | "you're helpful assistant."
[message placeholder] | {chat_history}
[human placeholder] | {input}
[message placeholder] | {agent_scratchpad}
우선, 각 parameters를 살펴보기 전에 개념 정리를 하고 가자.
- Tool : Agent가 사용할 수 있는 도구
- Agent : 어떤 Action을 취할 지 결정하는 역할
- AgentExecutor : 주어진 Agent, Tools를 사용해서 Action을 실행
여기서 중요한 건 Agent와 AgentExecutor는 다른 개념이고, 다른 역할을 수행한다는 것이다.
보통 openai Function Callings를 사용해서 agent를 만들게 되면 아래와 같다.
agent = create_openai_functions_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent, tools)
# [use_case 1] 처음 질문하는 경우
response = agent_executor.invoke({"input": question})
# [use_case 2] 과거 기록을 가지고 질문하는 경우
response = agent_executor.invoke({
"input": question,
"chat_history": [
HumanMessage(content=question_history),
AIMessage(content=answer_history)
]
})
# response 결과 = {"input": question, "output": answer}
L1 : OpenAI Function Calling을 사용해서, Agent Instance 를 생성한다.
따라서 parameter로 주어지는 llm은 반드시 OpanAI Function Calling 과 소통이 가능해야 한다.
내부 동작 과정을 살펴보면 다음과 같다.
- llm에 tools binding 시킨다.
- agent chain 으로 연결한 뒤에 반환한다.
- (AgentAction, observation) 묶음이 AIMessage로 {agent_scratchpad} 변수로 가져온다.
- prompt를 업데이트 및 할당 시킨다.
- 위에서 tools binded llm을 실행시킨다.
- Output parsing해서 반환한다.
이런 식으로 중간 과정의 agent / tool 결과물들이 prompt의 {agent_scratchpad}에 passed 된다.
따라서 prompt 내에서는 반드시 존재해야 하며, 없을 경우 assert 된다.
하지만 prompt의 {chat_history}는 optional하게 있어도 되고 없어도 된다.
L2,3 : AgentExecutor를 세팅 및 실행한다.
AgentExecutor 는 Chain을 상속한다.
여기서 invoke를 호출하는데, invoke 함수는 Chain에서 수행이 되며, Chain.invoke는 AgentExecutor._call을 호출해서 연산한다.
Chain.invoke
- prep_inputs 함수로 메모리에 저장된 messages 등을 세팅한다.
- callback_manager를 세팅한다.
- _call(inputs, run_manager)를 수행하여 결과를 가져온다.
- prep_outputs 함수로 결과를 처리하여 반환한다.
AgentExecutor._call
- {tool_name: tool}를 세팅한다.
- 반복적으로 _should_continue를 수행한다. 시간이나 횟수로 제어한다. (-> _iter_next_step)
- output = agent.plan( 중간결과물, 콜백, inputs )
- output이 AgentFinish이면 끝내고, AgentAction이면 actions = [output]
- actions를 돌면서, _perform_agent_action( tool_dict ~~ )를 수행한다. ( observation = tool.run() )
- _return 으로 (출력값, 중간결과물, 콜백)을 반환한다.