test_chat_completions.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. from typing import List
  2. import openai
  3. import pytest
  4. from .utils import MESSAGES_WITHOUT_TOOLS, WEATHER_TOOL
  5. # test: make sure chat completions without tools provided work even when tools
  6. # are enabled. This makes sure tool call chat templates work, AND that the tool
  7. # parser stream processing doesn't change the output of the model.
  8. @pytest.mark.asyncio
  9. async def test_chat_completion_without_tools(client: openai.AsyncOpenAI):
  10. models = await client.models.list()
  11. model_name: str = models.data[0].id
  12. chat_completion = await client.chat.completions.create(
  13. messages=MESSAGES_WITHOUT_TOOLS,
  14. temperature=0,
  15. max_tokens=150,
  16. model=model_name,
  17. logprobs=False)
  18. choice = chat_completion.choices[0]
  19. stop_reason = chat_completion.choices[0].finish_reason
  20. output_text = chat_completion.choices[0].message.content
  21. # check to make sure we got text
  22. assert output_text is not None
  23. assert len(output_text) > 0
  24. assert stop_reason != "tool_calls"
  25. # check to make sure no tool calls were returned
  26. assert (choice.message.tool_calls is None
  27. or len(choice.message.tool_calls) == 0)
  28. # make the same request, streaming
  29. stream = await client.chat.completions.create(
  30. messages=MESSAGES_WITHOUT_TOOLS,
  31. temperature=0,
  32. max_tokens=150,
  33. model=model_name,
  34. logprobs=False,
  35. stream=True,
  36. )
  37. chunks: List[str] = []
  38. finish_reason_count = 0
  39. role_sent: bool = False
  40. # assemble streamed chunks
  41. async for chunk in stream:
  42. delta = chunk.choices[0].delta
  43. # make sure the role is assistant
  44. if delta.role:
  45. assert not role_sent
  46. assert delta.role == 'assistant'
  47. role_sent = True
  48. if delta.content:
  49. chunks.append(delta.content)
  50. if chunk.choices[0].finish_reason is not None:
  51. finish_reason_count += 1
  52. assert chunk.choices[0].finish_reason == choice.finish_reason
  53. # make sure tool call chunks aren't being streamed
  54. assert not delta.tool_calls or len(delta.tool_calls) == 0
  55. # make sure the role was sent, only 1 finish reason was sent, that chunks
  56. # were in fact sent, and that the chunks match non-streaming
  57. assert role_sent
  58. assert finish_reason_count == 1
  59. assert len(chunks)
  60. assert "".join(chunks) == output_text
  61. # test: conversation with tools enabled and provided that should not invoke
  62. # tools, to make sure we can still get normal chat completion responses
  63. # and that they won't be parsed as tools
  64. @pytest.mark.asyncio
  65. async def test_chat_completion_with_tools(client: openai.AsyncOpenAI):
  66. models = await client.models.list()
  67. model_name: str = models.data[0].id
  68. chat_completion = await client.chat.completions.create(
  69. messages=MESSAGES_WITHOUT_TOOLS,
  70. temperature=0,
  71. max_tokens=150,
  72. model=model_name,
  73. tools=[WEATHER_TOOL],
  74. logprobs=False)
  75. choice = chat_completion.choices[0]
  76. stop_reason = chat_completion.choices[0].finish_reason
  77. output_text = chat_completion.choices[0].message.content
  78. # check to make sure we got text
  79. assert output_text is not None
  80. assert stop_reason != 'tool_calls'
  81. assert len(output_text) > 0
  82. # check to make sure no tool calls were returned
  83. assert (choice.message.tool_calls is None
  84. or len(choice.message.tool_calls) == 0)
  85. # make the same request, streaming
  86. stream = await client.chat.completions.create(
  87. messages=MESSAGES_WITHOUT_TOOLS,
  88. temperature=0,
  89. max_tokens=150,
  90. model=model_name,
  91. logprobs=False,
  92. tools=[WEATHER_TOOL],
  93. stream=True,
  94. )
  95. chunks: List[str] = []
  96. finish_reason_count = 0
  97. role_sent: bool = False
  98. # assemble streamed chunks
  99. async for chunk in stream:
  100. delta = chunk.choices[0].delta
  101. # make sure the role is assistant
  102. if delta.role:
  103. assert delta.role == 'assistant'
  104. role_sent = True
  105. if delta.content:
  106. chunks.append(delta.content)
  107. if chunk.choices[0].finish_reason is not None:
  108. finish_reason_count += 1
  109. # make sure tool call chunks aren't being streamed
  110. assert not delta.tool_calls or len(delta.tool_calls) == 0
  111. # make sure the role was sent, only 1 finish reason was sent, that chunks
  112. # were in fact sent, and that the chunks match non-streaming
  113. assert role_sent
  114. assert finish_reason_count == 1
  115. assert chunk.choices[0].finish_reason == stop_reason
  116. assert chunk.choices[0].finish_reason != 'tool_calls'
  117. assert len(chunks)
  118. assert "".join(chunks) == output_text