Skip to content

Commit 0e74ec3

Browse files
committed
Update Ollama/Anthropic
1 parent 63040e7 commit 0e74ec3

File tree

2 files changed

+50
-115
lines changed

2 files changed

+50
-115
lines changed

tests/unit/llm/test_anthropic_llm.py

Lines changed: 48 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@
1919

2020
import anthropic
2121
import pytest
22-
from neo4j_graphrag.exceptions import LLMGenerationError
22+
from anthropic import NOT_GIVEN, NotGiven
23+
24+
from neo4j_graphrag.llm import LLMResponse
2325
from neo4j_graphrag.llm.anthropic_llm import AnthropicLLM
24-
from neo4j_graphrag.llm.types import LLMResponse
26+
from neo4j_graphrag.types import LLMMessage
2527

2628

2729
@pytest.fixture
@@ -40,147 +42,82 @@ def test_anthropic_llm_missing_dependency(mock_import: Mock) -> None:
4042
AnthropicLLM(model_name="claude-3-opus-20240229")
4143

4244

43-
def test_anthropic_invoke_happy_path(mock_anthropic: Mock) -> None:
44-
mock_anthropic.Anthropic.return_value.messages.create.return_value = MagicMock(
45-
content=[MagicMock(text="generated text")]
46-
)
47-
model_params = {"temperature": 0.3}
48-
llm = AnthropicLLM("claude-3-opus-20240229", model_params=model_params)
49-
input_text = "may thy knife chip and shatter"
50-
response = llm.invoke(input_text)
51-
assert response.content == "generated text"
52-
llm.client.messages.create.assert_called_once_with( # type: ignore
53-
messages=[{"role": "user", "content": input_text}],
54-
model="claude-3-opus-20240229",
55-
system=anthropic.NOT_GIVEN,
56-
**model_params,
57-
)
58-
59-
60-
def test_anthropic_invoke_with_message_history_happy_path(mock_anthropic: Mock) -> None:
61-
mock_anthropic.Anthropic.return_value.messages.create.return_value = MagicMock(
62-
content=[MagicMock(text="generated text")]
63-
)
64-
model_params = {"temperature": 0.3}
65-
llm = AnthropicLLM(
66-
"claude-3-opus-20240229",
67-
model_params=model_params,
68-
)
45+
def test_anthropic_llm_get_messages_with_system_instructions() -> None:
46+
llm = AnthropicLLM(api_key="my key", model_name="claude")
6947
message_history = [
70-
{"role": "user", "content": "When does the sun come up in the summer?"},
71-
{"role": "assistant", "content": "Usually around 6am."},
48+
LLMMessage(**{"role": "system", "content": "do something"}),
49+
LLMMessage(
50+
**{"role": "user", "content": "When does the sun come up in the summer?"}
51+
),
52+
LLMMessage(**{"role": "assistant", "content": "Usually around 6am."}),
7253
]
73-
question = "What about next season?"
74-
75-
response = llm.invoke(question, message_history) # type: ignore
76-
assert response.content == "generated text"
77-
message_history.append({"role": "user", "content": question})
78-
llm.client.messages.create.assert_called_once_with( # type: ignore[attr-defined]
79-
messages=message_history,
80-
model="claude-3-opus-20240229",
81-
system=anthropic.NOT_GIVEN,
82-
**model_params,
83-
)
8454

55+
system_instruction, messages = llm.get_messages(message_history)
56+
assert isinstance(system_instruction, str)
57+
assert system_instruction == "do something"
58+
assert isinstance(messages, list)
59+
assert len(messages) == 2 # exclude system instruction
60+
for actual, expected in zip(messages, message_history[1:]):
61+
assert isinstance(actual, dict)
62+
assert actual["role"] == expected["role"]
63+
assert actual["content"] == expected["content"]
8564

86-
def test_anthropic_invoke_with_system_instruction(
87-
mock_anthropic: Mock,
88-
) -> None:
89-
mock_anthropic.Anthropic.return_value.messages.create.return_value = MagicMock(
90-
content=[MagicMock(text="generated text")]
91-
)
92-
model_params = {"temperature": 0.3}
93-
system_instruction = "You are a helpful assistant."
94-
llm = AnthropicLLM(
95-
"claude-3-opus-20240229",
96-
model_params=model_params,
97-
)
9865

99-
question = "When does it come up in the winter?"
100-
response = llm.invoke(question, system_instruction=system_instruction)
101-
assert isinstance(response, LLMResponse)
102-
assert response.content == "generated text"
103-
messages = [{"role": "user", "content": question}]
104-
llm.client.messages.create.assert_called_with( # type: ignore[attr-defined]
105-
model="claude-3-opus-20240229",
106-
system=system_instruction,
107-
messages=messages,
108-
**model_params,
109-
)
66+
def test_anthropic_llm_get_messages_without_system_instructions() -> None:
67+
llm = AnthropicLLM(api_key="my key", model_name="claude")
68+
message_history = [
69+
LLMMessage(
70+
**{"role": "user", "content": "When does the sun come up in the summer?"}
71+
),
72+
LLMMessage(**{"role": "assistant", "content": "Usually around 6am."}),
73+
]
11074

111-
assert llm.client.messages.create.call_count == 1 # type: ignore
75+
system_instruction, messages = llm.get_messages(message_history)
76+
assert isinstance(system_instruction, NotGiven)
77+
assert system_instruction == NOT_GIVEN
78+
assert isinstance(messages, list)
79+
assert len(messages) == 2
80+
for actual, expected in zip(messages, message_history):
81+
assert isinstance(actual, dict)
82+
assert actual["role"] == expected["role"]
83+
assert actual["content"] == expected["content"]
11284

11385

114-
def test_anthropic_invoke_with_message_history_and_system_instruction(
115-
mock_anthropic: Mock,
116-
) -> None:
86+
def test_anthropic_invoke_happy_path(mock_anthropic: Mock) -> None:
11787
mock_anthropic.Anthropic.return_value.messages.create.return_value = MagicMock(
11888
content=[MagicMock(text="generated text")]
11989
)
90+
mock_anthropic.types.MessageParam.return_value = {"role": "user", "content": "hi"}
12091
model_params = {"temperature": 0.3}
121-
system_instruction = "You are a helpful assistant."
122-
llm = AnthropicLLM(
123-
"claude-3-opus-20240229",
124-
model_params=model_params,
125-
)
126-
message_history = [
127-
{"role": "user", "content": "When does the sun come up in the summer?"},
128-
{"role": "assistant", "content": "Usually around 6am."},
129-
]
130-
131-
question = "When does it come up in the winter?"
132-
response = llm.invoke(question, message_history, system_instruction) # type: ignore
92+
llm = AnthropicLLM("claude-3-opus-20240229", model_params=model_params)
93+
input_text = "may thy knife chip and shatter"
94+
response = llm.invoke(input_text)
13395
assert isinstance(response, LLMResponse)
13496
assert response.content == "generated text"
135-
message_history.append({"role": "user", "content": question})
136-
llm.client.messages.create.assert_called_with( # type: ignore[attr-defined]
97+
llm.client.messages.create.assert_called_once_with( # type: ignore
98+
messages=[{"role": "user", "content": "hi"}],
13799
model="claude-3-opus-20240229",
138-
system=system_instruction,
139-
messages=message_history,
100+
system=anthropic.NOT_GIVEN,
140101
**model_params,
141102
)
142103

143-
assert llm.client.messages.create.call_count == 1 # type: ignore
144-
145-
146-
def test_anthropic_invoke_with_message_history_validation_error(
147-
mock_anthropic: Mock,
148-
) -> None:
149-
mock_anthropic.Anthropic.return_value.messages.create.return_value = MagicMock(
150-
content=[MagicMock(text="generated text")]
151-
)
152-
model_params = {"temperature": 0.3}
153-
system_instruction = "You are a helpful assistant."
154-
llm = AnthropicLLM(
155-
"claude-3-opus-20240229",
156-
model_params=model_params,
157-
system_instruction=system_instruction,
158-
)
159-
message_history = [
160-
{"role": "human", "content": "When does the sun come up in the summer?"},
161-
{"role": "assistant", "content": "Usually around 6am."},
162-
]
163-
question = "What about next season?"
164-
165-
with pytest.raises(LLMGenerationError) as exc_info:
166-
llm.invoke(question, message_history) # type: ignore
167-
assert "Input should be 'user', 'assistant' or 'system'" in str(exc_info.value)
168-
169104

170105
@pytest.mark.asyncio
171106
async def test_anthropic_ainvoke_happy_path(mock_anthropic: Mock) -> None:
172107
mock_response = AsyncMock()
173108
mock_response.content = [MagicMock(text="Return text")]
174109
mock_model = mock_anthropic.AsyncAnthropic.return_value
175110
mock_model.messages.create = AsyncMock(return_value=mock_response)
111+
mock_anthropic.types.MessageParam.return_value = {"role": "user", "content": "hi"}
176112
model_params = {"temperature": 0.3}
177113
llm = AnthropicLLM("claude-3-opus-20240229", model_params)
178114
input_text = "may thy knife chip and shatter"
179115
response = await llm.ainvoke(input_text)
116+
assert isinstance(response, LLMResponse)
180117
assert response.content == "Return text"
181118
llm.async_client.messages.create.assert_awaited_once_with( # type: ignore
182119
model="claude-3-opus-20240229",
183120
system=anthropic.NOT_GIVEN,
184-
messages=[{"role": "user", "content": input_text}],
121+
messages=[{"role": "user", "content": "hi"}],
185122
**model_params,
186123
)

tests/unit/llm/test_ollama_llm.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,8 @@ def test_ollama_llm_happy_path_deprecated_options(mock_import: Mock) -> None:
6262
assert res.content == "ollama chat response"
6363
llm.client.chat.assert_called_once_with( # type: ignore[attr-defined]
6464
model=model,
65-
messages=[
66-
{"role": "user", "content": "test"}
67-
],
68-
options={"temperature": 0.3}
65+
messages=[{"role": "user", "content": "test"}],
66+
options={"temperature": 0.3},
6967
)
7068

7169

0 commit comments

Comments
 (0)