모양
/api/chat은 messages array (system / user / assistant / tool role) 받아서 streaming NDJSON이나 single JSON 객체 (stream에 따라) 반환. Raw completion / FIM 빼고 다 이 endpoint 써.
Request 필드
model(필수).ollama list에 뜨는 그대로의 모델 이름을 써.messages—{role, content, images?, tool_calls?}array. Role:system,user,assistant,tool.stream— boolean (defaulttrue).format—"json"또는 JSON Schema 객체 (structured output용).options— Inference parameter (temperature,top_p,num_ctx,num_predict등).tools— OpenAI-format tool 정의 array (function calling용).keep_alive— 이 request 후에 모델을 메모리에 얼마나 붙들어 둘지 (default는"5m"). Pin은 숫자-1로 해."-1"문자열은 duration으로 파싱되다가time: missing unit in duration "-1"으로 거절돼.think— reasoning 모델의 thinking 출력을 켜. boolean도 되고 레벨도 돼."low","medium","high","max".
Response 필드 (non-streaming)
message—{role, content, tool_calls?}.done— boolean (stream off일 땐 항상true).- 시간, 단위는 nanosecond:
total_duration,load_duration,prompt_eval_duration(prompt에 쓴 시간),eval_duration(생성에 쓴 시간). - 개수, 단위는 토큰:
prompt_eval_count(prompt 토큰 수),eval_count(생성된 토큰 수). 시간인 건_duration으로 끝나는 것들뿐이야. 그래서 초당 토큰이 개수 ÷ 시간인 거고, 아래 코드가 딱 그렇게 하고 있어.
왜 /api/chat을 /api/generate보다 선호?
messages 모양이 role 경계 (system instruction vs user turn vs assistant output vs tool result) 의식하게 강제해. 그 구조가 뒤에서 tool 사용, multi-turn context, adapter 패턴이 일관되게 굴러가게 해주는 거야. /api/generate는 단순해 보이는데, prompt를 문자열 하나로 이어 붙이게 몰아가서 오히려 조합하기가 더 어려워져.